From rhettinger at users.sourceforge.net Fri Oct 1 00:29:06 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri Oct 1 00:29:09 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_genexps.py,1.6,1.7 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9044 Modified Files: test_genexps.py Log Message: Add tests for syntax errors. Index: test_genexps.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_genexps.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- test_genexps.py 30 Sep 2004 07:47:20 -0000 1.6 +++ test_genexps.py 30 Sep 2004 22:29:03 -0000 1.7 @@ -120,6 +120,19 @@ >>> max(tupleids) - min(tupleids) 0 +Verify that syntax error's are raised for genexps used as lvalues + + >>> (y for y in (1,2)) = 10 + Traceback (most recent call last): + ... + SyntaxError: assign to generator expression not possible + + >>> (y for y in (1,2)) += 10 + Traceback (most recent call last): + ... + SyntaxError: augmented assign to tuple literal or generator expression not possible + + ########### Tests borrowed from or inspired by test_generators.py ############ From tim_one at users.sourceforge.net Fri Oct 1 03:03:32 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri Oct 1 03:03:35 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.22, 1.23 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9722/Modules Modified Files: collectionsmodule.c Log Message: Trimmed trailing whitespace. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- collectionsmodule.c 19 Jul 2004 00:10:24 -0000 1.22 +++ collectionsmodule.c 1 Oct 2004 01:03:29 -0000 1.23 @@ -48,7 +48,7 @@ deque = (dequeobject *)type->tp_alloc(type, 0); if (deque == NULL) return NULL; - + b = newblock(NULL, NULL); if (b == NULL) { Py_DECREF(deque); @@ -206,12 +206,12 @@ deque->rightblock->data[deque->rightindex] = item; } Py_DECREF(it); - if (PyErr_Occurred()) + if (PyErr_Occurred()) return NULL; Py_RETURN_NONE; } -PyDoc_STRVAR(extend_doc, +PyDoc_STRVAR(extend_doc, "Extend the right side of the deque with elements from the iterable"); static PyObject * @@ -246,7 +246,7 @@ Py_RETURN_NONE; } -PyDoc_STRVAR(extendleft_doc, +PyDoc_STRVAR(extendleft_doc, "Extend the left side of the deque with elements from the iterable"); static PyObject * @@ -289,7 +289,7 @@ Py_RETURN_NONE; } -PyDoc_STRVAR(rotate_doc, +PyDoc_STRVAR(rotate_doc, "Rotate the deque n steps to the right (default n=1). If n is negative, rotates left."); static int @@ -354,7 +354,7 @@ /* delitem() implemented in terms of rotate for simplicity and reasonable performance near the end points. If for some reason this method becomes - popular, it is not hard to re-implement this using direct data movement + popular, it is not hard to re-implement this using direct data movement (similar to code in list slice assignment) and achieve a two or threefold performance boost. */ @@ -365,7 +365,7 @@ PyObject *item=NULL, *minus_i=NULL, *plus_i=NULL; int rv = -1; - assert (i >= 0 && i < deque->len); + assert (i >= 0 && i < deque->len); minus_i = Py_BuildValue("(i)", -i); if (minus_i == NULL) @@ -376,7 +376,7 @@ goto fail; item = deque_rotate(deque, minus_i); - if (item == NULL) + if (item == NULL) goto fail; Py_DECREF(item); @@ -385,7 +385,7 @@ Py_DECREF(item); item = deque_rotate(deque, plus_i); - if (item == NULL) + if (item == NULL) goto fail; rv = 0; @@ -489,7 +489,7 @@ static PyObject * deque_copy(PyObject *deque) { - return PyObject_CallFunctionObjArgs((PyObject *)(deque->ob_type), + return PyObject_CallFunctionObjArgs((PyObject *)(deque->ob_type), deque, NULL); } @@ -582,7 +582,7 @@ } Py_ReprLeave(deque); Py_DECREF(it); - if (PyErr_Occurred()) + if (PyErr_Occurred()) return -1; fputs("])", fp); return 0; @@ -594,7 +594,7 @@ PyObject *it1=NULL, *it2=NULL, *x, *y; int i, b, vs, ws, minlen, cmp=-1; - if (!PyObject_TypeCheck(v, &deque_type) || + if (!PyObject_TypeCheck(v, &deque_type) || !PyObject_TypeCheck(w, &deque_type)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; @@ -654,7 +654,7 @@ case Py_GT: cmp = vs > ws; break; case Py_GE: cmp = vs >= ws; break; } - + done: Py_XDECREF(it1); Py_XDECREF(it2); @@ -695,31 +695,31 @@ static PyObject *deque_iter(dequeobject *deque); static PyObject *deque_reviter(dequeobject *deque); -PyDoc_STRVAR(reversed_doc, +PyDoc_STRVAR(reversed_doc, "D.__reversed__() -- return a reverse iterator over the deque"); static PyMethodDef deque_methods[] = { - {"append", (PyCFunction)deque_append, + {"append", (PyCFunction)deque_append, METH_O, append_doc}, - {"appendleft", (PyCFunction)deque_appendleft, + {"appendleft", (PyCFunction)deque_appendleft, METH_O, appendleft_doc}, - {"clear", (PyCFunction)deque_clearmethod, + {"clear", (PyCFunction)deque_clearmethod, METH_NOARGS, clear_doc}, - {"__copy__", (PyCFunction)deque_copy, + {"__copy__", (PyCFunction)deque_copy, METH_NOARGS, copy_doc}, - {"extend", (PyCFunction)deque_extend, + {"extend", (PyCFunction)deque_extend, METH_O, extend_doc}, - {"extendleft", (PyCFunction)deque_extendleft, + {"extendleft", (PyCFunction)deque_extendleft, METH_O, extendleft_doc}, - {"pop", (PyCFunction)deque_pop, + {"pop", (PyCFunction)deque_pop, METH_NOARGS, pop_doc}, - {"popleft", (PyCFunction)deque_popleft, + {"popleft", (PyCFunction)deque_popleft, METH_NOARGS, popleft_doc}, - {"__reduce__", (PyCFunction)deque_reduce, + {"__reduce__", (PyCFunction)deque_reduce, METH_NOARGS, reduce_doc}, - {"__reversed__", (PyCFunction)deque_reviter, + {"__reversed__", (PyCFunction)deque_reviter, METH_NOARGS, reversed_doc}, - {"rotate", (PyCFunction)deque_rotate, + {"rotate", (PyCFunction)deque_rotate, METH_VARARGS, rotate_doc}, {NULL, NULL} /* sentinel */ }; @@ -980,7 +980,7 @@ PyModule_AddObject(m, "deque", (PyObject *)&deque_type); if (PyType_Ready(&dequeiter_type) < 0) - return; + return; if (PyType_Ready(&dequereviter_type) < 0) return; From tim_one at users.sourceforge.net Fri Oct 1 03:04:58 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri Oct 1 03:05:01 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.23, 1.24 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9904/Modules Modified Files: collectionsmodule.c Log Message: Definition consistency. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- collectionsmodule.c 1 Oct 2004 01:03:29 -0000 1.23 +++ collectionsmodule.c 1 Oct 2004 01:04:50 -0000 1.24 @@ -15,7 +15,8 @@ PyObject *data[BLOCKLEN]; } block; -static block *newblock(block *leftlink, block *rightlink) { +static block * +newblock(block *leftlink, block *rightlink) { block *b = PyMem_Malloc(sizeof(block)); if (b == NULL) { PyErr_NoMemory(); From gward at users.sourceforge.net Fri Oct 1 03:16:57 2004 From: gward at users.sourceforge.net (gward@users.sourceforge.net) Date: Fri Oct 1 03:17:00 2004 Subject: [Python-checkins] python/dist/src/Doc/lib liboptparse.tex, 1.16, 1.17 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11932 Modified Files: liboptparse.tex Log Message: Get references working (except for references to "Extending optparse", which isn't being converted from reST yet). Index: liboptparse.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liboptparse.tex,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- liboptparse.tex 28 Sep 2004 01:30:23 -0000 1.16 +++ liboptparse.tex 1 Oct 2004 01:16:39 -0000 1.17 @@ -175,7 +175,7 @@ argument. \code{"foo"} and \code{"bar"} are positional arguments. -\subsubsection{What are options for?\label{optparse-what-are-options-for?}} +\subsubsection{What are options for?\label{optparse-what-options-for}} Options are used to provide extra information to tune or customize the execution of a program. In case it wasn't clear, options are usually @@ -209,7 +209,7 @@ another, or several files to another directory. -\subsubsection{What are positional arguments for?\label{optparse-what-are-positional-arguments-for?}} +\subsubsection{What are positional arguments for?\label{optparse-what-positional-arguments-for}} Positional arguments are for those pieces of information that your program absolutely, positively requires to run. @@ -302,7 +302,7 @@ Of these, \member{action} is the most fundamental. -\subsubsection{Option actions\label{optparse-option-actions}} +\subsubsection{Understanding option actions\label{optparse-understanding-option-actions}} Actions tell \module{optparse} what to do when it encounters an option on the command line. There is a fixed set of actions hard-coded into \module{optparse}; @@ -314,7 +314,7 @@ If you don't specify an option action, \module{optparse} defaults to \code{store}. -\subsubsection{The store action\label{optparse-the-store-action}} +\subsubsection{The store action\label{optparse-store-action}} The most common option action is \code{store}, which tells \module{optparse} to take the next argument (or the remainder of the current argument), ensure @@ -374,7 +374,7 @@ types is covered in section~\ref{optparse-extending}, Extending \module{optparse}. -\subsubsection{Handling flag (boolean) options\label{optparse-handling-flag-(boolean)-options}} +\subsubsection{Handling boolean (flag) options\label{optparse-handling-boolean-options}} Flag options{---}set a variable to true or false when a particular option is seen{---}are quite common. \module{optparse} supports them with two separate @@ -387,7 +387,7 @@ Here we have two different options with the same destination, which is perfectly OK. (It just means you have to be a bit careful when setting -default values{---}see section~\ref{optparse-default-values}, Default values, below.) +default values{---}see below.) When \module{optparse} encounters \code{"-v"} on the command line, it sets \code{options.verbose} to \code{True}; when it encounters \code{"-q"}, @@ -408,8 +408,7 @@ call a specified function \end{description} -These are covered in the section~\ref{None}, Reference Guide and section~\ref{None}, Option Callbacks -documents. +These are covered in section~\ref{optparse-reference-guide}, Reference Guide and section~\ref{optparse-option-callbacks}, Option Callbacks. \subsubsection{Default values\label{optparse-default-values}} @@ -558,7 +557,7 @@ \end{itemize} -\subsubsection{Printing a version string\label{optparse-printing-a-version-string}} +\subsubsection{Printing a version string\label{optparse-printing-version-string}} Similar to the brief usage string, \module{optparse} can also print a version string for your program. You have to supply the string as the \code{version} @@ -581,7 +580,7 @@ \end{verbatim} -\subsubsection{Error-handling\label{optparse-error-handling}} +\subsubsection{How \module{optparse} handles errors\label{optparse-how-optik-handles-errors}} There are two broad classes of errors that \module{optparse} has to worry about: programmer errors and user errors. Programmer errors are usually @@ -666,11 +665,11 @@ \subsection{Reference Guide\label{optparse-reference-guide}} -\subsubsection{Populating the parser\label{optparse-populating-the-parser}} +\subsubsection{Populating the parser\label{optparse-populating-parser}} There are several ways to populate the parser with options. The preferred way is by using \code{OptionParser.add{\_}option()}, as shown in -section~\ref{None}, the tutorial section. \method{add{\_}option()} can be called in one of two +section~\ref{optparse-tutorial}, the tutorial. \method{add{\_}option()} can be called in one of two ways: \begin{itemize} \item {} @@ -802,7 +801,7 @@ options. -\subsubsection{Option actions\label{optparse-option-actions}} +\subsubsection{Standard option actions\label{optparse-standard-option-actions}} The various option actions all have slightly different requirements and effects. Most actions have several relevant option attributes which you @@ -950,7 +949,7 @@ *args, **kwargs) \end{verbatim} -See section~\ref{None}, Option Callbacks for more detail. +See section~\ref{optparse-option-callbacks}, Option Callbacks for more detail. \item {} \member{help} @@ -1008,7 +1007,7 @@ \end{itemize} -\subsubsection{Option types\label{optparse-option-types}} +\subsubsection{Standard option types\label{optparse-standard-option-types}} \module{optparse} has six built-in option types: \code{string}, \code{int}, \code{long}, \code{choice}, \code{float} and \code{complex}. If you need to add new option @@ -1036,7 +1035,7 @@ OptionValueError if an invalid string is given. -\subsubsection{Querying and manipulating your option parser\label{optparse-querying-and-manipulating-your-option-parser}} +\subsubsection{Querying and manipulating your option parser\label{optparse-querying-manipulating-option-parser}} Sometimes, it's useful to poke around your option parser and see what's there. OptionParser provides a couple of methods to help you out: @@ -1154,7 +1153,7 @@ \end{itemize} -\subsubsection{Defining a callback option\label{optparse-defining-a-callback-option}} +\subsubsection{Defining a callback option\label{optparse-defining-callback-option}} As always, the easiest way to define a callback option is by using the \code{parser.add{\_}option()} method. Apart from \member{action}, the only option @@ -1202,7 +1201,7 @@ \end{description} -\subsubsection{How callbacks are called\label{optparse-how-callbacks-are-called}} +\subsubsection{How callbacks are called\label{optparse-how-callbacks-called}} All callbacks are called as follows: \begin{verbatim} @@ -1259,7 +1258,7 @@ \end{description} -\subsubsection{Error handling\label{optparse-error-handling}} +\subsubsection{Raising errors in a callback\label{optparse-raising-errors-in-callback}} The callback function should raise OptionValueError if there are any problems with the option or its argument(s). \module{optparse} catches this and @@ -1269,7 +1268,7 @@ figuring out what he did wrong. -\subsubsection{Callback example 1: trivial callback\label{optparse-callback-example-1:-trivial-callback}} +\subsubsection{Callback example 1: trivial callback\label{optparse-callback-example-1}} Here's an example of a callback option that takes no arguments, and simply records that the option was seen: @@ -1283,7 +1282,7 @@ Of course, you could do that with the \code{store{\_}true} action. -\subsubsection{Callback example 2: check option order\label{optparse-callback-example-2:-check-option-order}} +\subsubsection{Callback example 2: check option order\label{optparse-callback-example-2}} Here's a slightly more interesting example: record the fact that \code{"-a"} is seen, but blow up if it comes after \code{"-b"} in the @@ -1299,7 +1298,7 @@ \end{verbatim} -\subsubsection{Callback example 3: check option order (generalized)\label{optparse-callback-example-3:-check-option-order-(generalized)}} +\subsubsection{Callback example 3: check option order (generalized)\label{optparse-callback-example-3}} If you want to re-use this callback for several similar options (set a flag, but blow up if \code{"-b"} has already been seen), it needs a bit of @@ -1317,7 +1316,7 @@ \end{verbatim} -\subsubsection{Callback example 4: check arbitrary condition\label{optparse-callback-example-4:-check-arbitrary-condition}} +\subsubsection{Callback example 4: check arbitrary condition\label{optparse-callback-example-4}} Of course, you could put any condition in there{---}you're not limited to checking the values of already-defined options. For example, if @@ -1338,7 +1337,7 @@ reader.) -\subsubsection{Callback example 5: fixed arguments\label{optparse-callback-example-5:-fixed-arguments}} +\subsubsection{Callback example 5: fixed arguments\label{optparse-callback-example-5}} Things get slightly more interesting when you define callback options that take a fixed number of arguments. Specifying that a callback @@ -1362,7 +1361,7 @@ obviously you don't need a callback for this example.) -\subsubsection{Callback example 6: variable arguments\label{optparse-callback-example-6:-variable-arguments}} +\subsubsection{Callback example 6: variable arguments\label{optparse-callback-example-6}} Things get hairy when you want an option to take a variable number of arguments. For this case, you must write a callback, as \module{optparse} doesn't From tim_one at users.sourceforge.net Fri Oct 1 03:32:56 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri Oct 1 03:32:58 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.24, 1.25 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14968/Modules Modified Files: collectionsmodule.c Log Message: Document some reverse-engineered invariants and pragmatic hints. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- collectionsmodule.c 1 Oct 2004 01:04:50 -0000 1.24 +++ collectionsmodule.c 1 Oct 2004 01:32:53 -0000 1.25 @@ -9,6 +9,21 @@ #define BLOCKLEN 46 +/* A `dequeobject` is composed of a doubly-linked list of `block` nodes. + * This list is not circular (the leftmost block has leftlink==NULL, + * and the rightmost block has rightlink==NULL). A deque d's first + * element is at d.leftblock[leftindex] and its last element is at + * d.rightblock[rightindex]; note that, unlike as for Python slice + * indices, this indices are inclusive on both ends. + * The list of blocks is never empty. An empty deque d has + * d.leftblock == d.rightblock != NULL; d.len == 0; and + * d.leftindex > d.rightindex; checking for d.len == 0 is the intended + * way to see whether d is empty. + * Note that since d.leftindex and d.rightindex may be indices into + * distinct blocks (and certainly are, for and d with len(d) > BLOCKLEN), + * it's not generally true that d.leftindex <= d.rightindex. + */ + typedef struct BLOCK { struct BLOCK *leftlink; struct BLOCK *rightlink; @@ -31,8 +46,8 @@ PyObject_HEAD block *leftblock; block *rightblock; - int leftindex; - int rightindex; + int leftindex; /* in range(BLOCKLEN) */ + int rightindex; /* in range(BLOCKLEN) */ int len; PyObject *weakreflist; /* List of weak references */ } dequeobject; From tim_one at users.sourceforge.net Fri Oct 1 03:35:57 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri Oct 1 03:36:00 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.25, 1.26 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15451/Modules Modified Files: collectionsmodule.c Log Message: Typos in new comments. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- collectionsmodule.c 1 Oct 2004 01:32:53 -0000 1.25 +++ collectionsmodule.c 1 Oct 2004 01:35:54 -0000 1.26 @@ -14,13 +14,13 @@ * and the rightmost block has rightlink==NULL). A deque d's first * element is at d.leftblock[leftindex] and its last element is at * d.rightblock[rightindex]; note that, unlike as for Python slice - * indices, this indices are inclusive on both ends. + * indices, these indices are inclusive on both ends. * The list of blocks is never empty. An empty deque d has * d.leftblock == d.rightblock != NULL; d.len == 0; and * d.leftindex > d.rightindex; checking for d.len == 0 is the intended * way to see whether d is empty. * Note that since d.leftindex and d.rightindex may be indices into - * distinct blocks (and certainly are, for and d with len(d) > BLOCKLEN), + * distinct blocks (and certainly are, for any d with len(d) > BLOCKLEN), * it's not generally true that d.leftindex <= d.rightindex. */ From tim_one at users.sourceforge.net Fri Oct 1 04:01:08 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri Oct 1 04:01:12 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_deque.py,1.15,1.16 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18895/Lib/test Modified Files: test_deque.py Log Message: deque_traverse(): If the deque had one block, and its rightindex was BLOCKLEN-1, this assert-failed in a debug build, or went wild with a NULL pointer in a release build. Reported on c.l.py by Stefan Behnel. Index: test_deque.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_deque.py,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- test_deque.py 27 Sep 2004 15:29:04 -0000 1.15 +++ test_deque.py 1 Oct 2004 02:01:03 -0000 1.16 @@ -324,6 +324,15 @@ for s in ('abcd', xrange(2000)): self.assertEqual(list(reversed(deque(s))), list(reversed(s))) + def test_gc_doesnt_blowup(self): + import gc + # This used to assert-fail in deque_traverse() under a debug + # build, or run wild with a NULL pointer in a release build. + d = deque() + for i in xrange(100): + d.append(1) + gc.collect() + def R(seqn): 'Regular generator' for i in seqn: From tim_one at users.sourceforge.net Fri Oct 1 04:01:08 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri Oct 1 04:01:12 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.26, 1.27 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18895/Modules Modified Files: collectionsmodule.c Log Message: deque_traverse(): If the deque had one block, and its rightindex was BLOCKLEN-1, this assert-failed in a debug build, or went wild with a NULL pointer in a release build. Reported on c.l.py by Stefan Behnel. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- collectionsmodule.c 1 Oct 2004 01:35:54 -0000 1.26 +++ collectionsmodule.c 1 Oct 2004 02:01:04 -0000 1.27 @@ -478,19 +478,22 @@ static int deque_traverse(dequeobject *deque, visitproc visit, void *arg) { - block * b = deque->leftblock; - int index = deque->leftindex; + block *b; PyObject *item; + int index; + int indexlo = deque->leftindex; - while (b != deque->rightblock || index <= deque->rightindex) { - item = b->data[index]; - index++; - if (index == BLOCKLEN ) { - assert(b->rightlink != NULL); - b = b->rightlink; - index = 0; + assert(deque->leftblock != NULL); + for (b = deque->leftblock; b != NULL; b = b->rightlink) { + const int indexhi = b == deque->rightblock ? + deque->rightindex : + BLOCKLEN - 1; + + for (index = indexlo; index <= indexhi; ++index) { + item = b->data[index]; + Py_VISIT(item); } - Py_VISIT(item); + indexlo = 0; } return 0; } From tim_one at users.sourceforge.net Fri Oct 1 04:13:20 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri Oct 1 04:13:22 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1146,1.1147 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21372/Misc Modified Files: NEWS Log Message: Noted the fix to deque gc. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1146 retrieving revision 1.1147 diff -u -d -r1.1146 -r1.1147 --- NEWS 28 Sep 2004 04:08:11 -0000 1.1146 +++ NEWS 1 Oct 2004 02:13:16 -0000 1.1147 @@ -27,7 +27,9 @@ Extension modules ----------------- -... +- ``collections.deque`` objects didn't play quite right with garbage + collection, which could lead to a segfault in a release build, or + an assert failure in a debug build. Library ------- From rhettinger at users.sourceforge.net Fri Oct 1 08:24:15 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri Oct 1 08:24:18 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.27, 1.28 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24008 Modified Files: collectionsmodule.c Log Message: * Elaborate on the invariant comments and make them more precise. * Change the centering by one to make it possible to test the module with BLOCKLEN's as low as two. Testing small blocks makes end-point errors surface more readily. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- collectionsmodule.c 1 Oct 2004 02:01:04 -0000 1.27 +++ collectionsmodule.c 1 Oct 2004 06:24:12 -0000 1.28 @@ -8,20 +8,33 @@ */ #define BLOCKLEN 46 +#define CENTER ((BLOCKLEN - 1) / 2) /* A `dequeobject` is composed of a doubly-linked list of `block` nodes. * This list is not circular (the leftmost block has leftlink==NULL, * and the rightmost block has rightlink==NULL). A deque d's first * element is at d.leftblock[leftindex] and its last element is at * d.rightblock[rightindex]; note that, unlike as for Python slice - * indices, these indices are inclusive on both ends. - * The list of blocks is never empty. An empty deque d has - * d.leftblock == d.rightblock != NULL; d.len == 0; and - * d.leftindex > d.rightindex; checking for d.len == 0 is the intended - * way to see whether d is empty. - * Note that since d.leftindex and d.rightindex may be indices into - * distinct blocks (and certainly are, for any d with len(d) > BLOCKLEN), - * it's not generally true that d.leftindex <= d.rightindex. + * indices, these indices are inclusive on both ends. By being inclusive + * on both ends, algorithms for left and right operations become + * symmetrical which simplifies the design. + * + * The list of blocks is never empty, so d.leftblock and d.rightblock + * are never equal to NULL. + * + * The indices, d.leftindex and d.rightindex are always in the range + * 0 <= index < BLOCKLEN. + * + * Empty deques have d.len == 0; d.leftblock==d.rightblock; + * d.leftindex == CENTER+1; and d.rightindex == CENTER. + * Checking for d.len == 0 is the intended way to see whether d is empty. + * + * Whenever d.leftblock == d.rightblock, + * d.leftindex + d.len == d.rightindex + 1. + * + * However, when d.leftblock != rightblock, d.leftindex and d.rightindex + * are indices into distinct blocks and have no relationship to one + * another (for example, sometimes d.leftindex > d.rightindex). */ typedef struct BLOCK { @@ -71,10 +84,11 @@ return NULL; } + assert(BLOCKLEN >= 2); deque->leftblock = b; deque->rightblock = b; - deque->leftindex = BLOCKLEN / 2 + 1; - deque->rightindex = BLOCKLEN / 2; + deque->leftindex = CENTER + 1; + deque->rightindex = CENTER; deque->len = 0; deque->weakreflist = NULL; @@ -142,8 +156,8 @@ assert(deque->leftblock == deque->rightblock); assert(deque->leftindex == deque->rightindex+1); /* re-center instead of freeing a block */ - deque->leftindex = BLOCKLEN / 2 + 1; - deque->rightindex = BLOCKLEN / 2; + deque->leftindex = CENTER + 1; + deque->rightindex = CENTER; } else { prevblock = deque->rightblock->leftlink; assert(deque->leftblock != deque->rightblock); @@ -177,8 +191,8 @@ assert(deque->leftblock == deque->rightblock); assert(deque->leftindex == deque->rightindex+1); /* re-center instead of freeing a block */ - deque->leftindex = BLOCKLEN / 2 + 1; - deque->rightindex = BLOCKLEN / 2; + deque->leftindex = CENTER + 1; + deque->rightindex = CENTER; } else { assert(deque->leftblock != deque->rightblock); prevblock = deque->leftblock->rightlink; From rhettinger at users.sourceforge.net Fri Oct 1 17:14:42 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri Oct 1 17:14:44 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.28, 1.29 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26515 Modified Files: collectionsmodule.c Log Message: Clarify the relationship between indices. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- collectionsmodule.c 1 Oct 2004 06:24:12 -0000 1.28 +++ collectionsmodule.c 1 Oct 2004 15:14:39 -0000 1.29 @@ -7,7 +7,7 @@ All rights reserved. */ -#define BLOCKLEN 46 +#define BLOCKLEN 2 #define CENTER ((BLOCKLEN - 1) / 2) /* A `dequeobject` is composed of a doubly-linked list of `block` nodes. @@ -24,17 +24,19 @@ * * The indices, d.leftindex and d.rightindex are always in the range * 0 <= index < BLOCKLEN. + * Their exact relationship is: + * (d.leftindex + d.len - 1) % BLOCKLEN == d.rightindex. * * Empty deques have d.len == 0; d.leftblock==d.rightblock; * d.leftindex == CENTER+1; and d.rightindex == CENTER. * Checking for d.len == 0 is the intended way to see whether d is empty. * * Whenever d.leftblock == d.rightblock, - * d.leftindex + d.len == d.rightindex + 1. + * d.leftindex + d.len - 1 == d.rightindex. * - * However, when d.leftblock != rightblock, d.leftindex and d.rightindex - * are indices into distinct blocks and have no relationship to one - * another (for example, sometimes d.leftindex > d.rightindex). + * However, when d.leftblock != d.rightblock, d.leftindex and d.rightindex + * become indices into distinct blocks and either may be larger than the + * other. */ typedef struct BLOCK { From rhettinger at users.sourceforge.net Fri Oct 1 17:25:55 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri Oct 1 17:25:58 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.29, 1.30 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28798 Modified Files: collectionsmodule.c Log Message: Restore the block length and add a comment. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- collectionsmodule.c 1 Oct 2004 15:14:39 -0000 1.29 +++ collectionsmodule.c 1 Oct 2004 15:25:53 -0000 1.30 @@ -7,7 +7,13 @@ All rights reserved. */ -#define BLOCKLEN 2 +/* The block length may be set to any number over 1. Larger numbers + * reduce the number of calls to the memory allocator but take more + * memory. Ideally, BLOCKLEN should be set with an eye to the + * length of a cache line. + */ + +#define BLOCKLEN 46 #define CENTER ((BLOCKLEN - 1) / 2) /* A `dequeobject` is composed of a doubly-linked list of `block` nodes. From pje at users.sourceforge.net Fri Oct 1 22:03:04 2004 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Fri Oct 1 22:03:08 2004 Subject: [Python-checkins] python/nondist/peps pep-0333.txt,1.19,1.20 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19538 Modified Files: pep-0333.txt Log Message: Clarifications and citations as requested by Mark Nottingham, and discussed further at: http://mail.python.org/pipermail/web-sig/2004-September/000917.html Also, add Mark to the Acknowledgments, since his input has now touched a substantial number of paragraphs in the PEP. :) Index: pep-0333.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0333.txt,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- pep-0333.txt 19 Sep 2004 19:49:37 -0000 1.19 +++ pep-0333.txt 1 Oct 2004 20:03:01 -0000 1.20 @@ -167,8 +167,8 @@ def simple_app(environ, start_response): """Simplest possible application object""" status = '200 OK' - headers = [('Content-type','text/plain')] - start_response(status, headers) + response_headers = [('Content-type','text/plain')] + start_response(status, response_headers) return ['Hello world!\n'] @@ -193,8 +193,8 @@ def __iter__(self): status = '200 OK' - headers = [('Content-type','text/plain')] - self.start(status, headers) + response_headers = [('Content-type','text/plain')] + self.start(status, response_headers) yield "Hello world!\n" @@ -237,16 +237,16 @@ elif not headers_sent: # Before the first output, send the stored headers - status, headers = headers_sent[:] = headers_set + status, response_headers = headers_sent[:] = headers_set sys.stdout.write('Status: %s\r\n' % status) - for header in headers: + for header in response_headers: sys.stdout.write('%s: %s\r\n' % header) sys.stdout.write('\r\n') sys.stdout.write(data) sys.stdout.flush() - def start_response(status,headers,exc_info=None): + def start_response(status,response_headers,exc_info=None): if exc_info: try: if headers_sent: @@ -257,7 +257,7 @@ elif headers_sent: raise AssertionError("Headers already sent!") - headers_set[:] = [status,headers] + headers_set[:] = [status,response_headers] return write result = application(environ, start_response) @@ -356,19 +356,22 @@ transform_ok = [] - def start_latin(status,headers,exc_info=None): - - for name,value in headers: + def start_latin(status,response_headers,exc_info=None): + + # Reset ok flag, in case this is a repeat call + transform_ok[:]=[] + + for name,value in response_headers: if name.lower()=='content-type' and value=='text/plain': transform_ok.append(True) # Strip content-length if present, else it'll be wrong - headers = [(name,value) - for name,value in headers + response_headers = [(name,value) + for name,value in response_headers if name.lower()<>'content-length' ] break - write = start_response(status,headers,exc_info) + write = start_response(status,response_headers,exc_info) if transform_ok: def write_latin(data): @@ -407,13 +410,14 @@ The ``start_response`` parameter is a callable accepting two required positional arguments, and one optional argument. For the sake -of illustration, we have named these arguments ``status``, ``headers``, -and ``exc_info``, but they are not required to have these names, and -the application **must** invoke the ``start_response`` callable using -positional arguments (e.g. ``start_response(status,headers)``). +of illustration, we have named these arguments ``status``, +``response_headers``, and ``exc_info``, but they are not required to +have these names, and the application **must** invoke the +``start_response`` callable using positional arguments (e.g. +``start_response(status,response_headers)``). The ``status`` parameter is a status string of the form -``"999 Message here"``, and ``headers`` is a list of +``"999 Message here"``, and ``response_headers`` is a list of ``(header_name,header_value)`` tuples describing the HTTP response header. The optional ``exc_info`` parameter is described below in the sections on `The start_response() Callable`_ and `Error Handling`_. @@ -428,19 +432,29 @@ can be avoided. See the `Buffering and Streaming`_ section for more details.) -The application object must return an iterable yielding strings. -(For example, it could be a generator-iterator that yields strings, -or it could be a sequence such as a list of strings.) The server -or gateway must transmit these strings to the client in an -unbuffered fashion, completing the transmission of each string -before requesting another one. (See the `Buffering and Streaming`_ -section below for more on how application output must be handled.) +When called by the server, the application object must return an +iterable yielding zero or more strings. This can be accomplished in a +variety of ways, such as by returning a list of strings, or by the +application being a generator function that yields strings, or +by the application being a class whose instances are iterable. +Regardless of how it is accomplished, the application object must +always return an iterable yielding zero or more strings. -The server or gateway must not modify supplied strings in any way; -they must be treated as binary byte sequences with no character -interpretation, line ending changes, or other modification. The -application is responsible for ensuring that the string(s) to be -written are in a format suitable for the client. +The server or gateway must transmit the yielded strings to the client +in an unbuffered fashion, completing the transmission of each string +before requesting another one. (In other words, applications +**should** perform their own buffering. See the `Buffering and +Streaming`_ section below for more on how application output must be +handled.) + +The server or gateway should treat the yielded strings as binary byte +sequences: in particular, it should ensure that line endings are +not altered. The application is responsible for ensuring that the +string(s) to be written are in a format suitable for the client. (The +server or gateway **may** apply HTTP transfer encodings, or perform +other transformations for the purpose of implementing HTTP features +such as byte-range transmission. See `Other HTTP Features`_, below, +for more details.) If a call to ``len(iterable)`` succeeds, the server must be able to rely on the result being accurate. That is, if the iterable @@ -518,17 +532,20 @@ can never be empty strings, and so are always required. ``HTTP_`` Variables - Variables corresponding to the client-supplied HTTP headers (i.e., - variables whose names begin with ``"HTTP_"``). The presence or + Variables corresponding to the client-supplied HTTP request headers + (i.e., variables whose names begin with ``"HTTP_"``). The presence or absence of these variables should correspond with the presence or absence of the appropriate HTTP header in the request. -In general, a server or gateway **should** attempt to provide as many -other CGI variables as are applicable, including e.g. the nonstandard -SSL variables such as ``HTTPS=on``, if an SSL connection is in effect. -However, an application that uses any CGI variables other than the ones -listed above are necessarily non-portable to web servers that do not -support the relevant extensions. +A server or gateway **should** attempt to provide as many other CGI +variables as are applicable. In addition, if SSL is in use, the server +or gateway **should** also provide as many of the Apache SSL environment +variables [5]_ as are applicable, such as ``HTTPS=on`` and +``SSL_PROTOCOL``. Note, however, an application that uses any CGI +variables other than the ones listed above are necessarily non-portable +to web servers that do not support the relevant extensions. (For +example, web servers that do not publish files will not be able to +provide a meaningful ``DOCUMENT_ROOT`` or ``PATH_TRANSLATED``.) A WSGI-compliant server or gateway **should** document what variables it provides, along with their definitions as appropriate. Applications @@ -542,7 +559,8 @@ for a CGI variable's value to be of any type other than ``str``. In addition to the CGI-defined variables, the ``environ`` dictionary -must also contain the following WSGI-defined variables: +**may** also contain arbitrary operating-system "environment variables", +and **must** contain the following WSGI-defined variables: ===================== =============================================== Variable Value @@ -555,20 +573,21 @@ invoked. Normally, this will have the value ``"http"`` or ``"https"``, as appropriate. -``wsgi.input`` An input stream from which the HTTP request - body can be read. (The server or gateway may - perform reads on-demand as requested by the - application, or it may pre-read the client's - request body and buffer it in-memory or on - disk, or use any other technique for providing - such an input stream, according to its - preference.) +``wsgi.input`` An input stream (file-like object) from which + the HTTP request body can be read. (The server + or gateway may perform reads on-demand as + requested by the application, or it may pre- + read the client's request body and buffer it + in-memory or on disk, or use any other + technique for providing such an input stream, + according to its preference.) -``wsgi.errors`` An output stream to which error output can be - written, for the purpose of recording program - or other errors in a standardized and possibly - centralized location. For many servers, this - will be the server's main error log. +``wsgi.errors`` An output stream (file-like object) to which + error output can be written, for the purpose of + recording program or other errors in a + standardized and possibly centralized location. + For many servers, this will be the server's + main error log. Alternatively, this may be ``sys.stderr``, or a log file of some sort. The server's @@ -578,22 +597,22 @@ supply different error streams to different applications, if this is desired. -``wsgi.multithread`` This value should be true if the application - object may be simultaneously invoked by another - thread in the same process, and false - otherwise. - -``wsgi.multiprocess`` This value should be true if an equivalent +``wsgi.multithread`` This value should evaluate true if the application object may be simultaneously - invoked by another process, and false - otherwise. + invoked by another thread in the same process, + and should evaluate false otherwise. -``wsgi.run_once`` This value should be true if the server/gateway - expects (but does not guarantee!) that the - application will only be invoked this one time - during the life of its containing process. - Normally, this will only be true for a gateway - based on CGI (or something similar). +``wsgi.multiprocess`` This value should evaluate true if an + equivalent application object may be + simultaneously invoked by another process, + and should evaluate false otherwise. + +``wsgi.run_once`` This value should evaluate true if the server + or gateway expects (but does not guarantee!) + that the application will only be invoked this + one time during the life of its containing + process. Normally, this will only be true for + a gateway based on CGI (or something similar). ===================== =============================================== Finally, the ``environ`` dictionary may also contain server-defined @@ -639,8 +658,8 @@ both caller and implementer. The application is free not to supply it, and the server or gateway is free to ignore it. -4. Since the ``errors`` stream may not be rewound, a container is - free to forward write operations immediately, without buffering. +4. Since the ``errors`` stream may not be rewound, servers and gateways + are free to forward write operations immediately, without buffering. In this case, the ``flush()`` method may be a no-op. Portable applications, however, cannot assume that output is unbuffered or that ``flush()`` is a no-op. They must call ``flush()`` if @@ -660,7 +679,7 @@ --------------------------------- The second parameter passed to the application object is a callable -of the form ``start_response(status,headers,exc_info=None)``. +of the form ``start_response(status,response_headers,exc_info=None)``. (As with all WSGI callables, the arguments must be supplied positionally, not by keyword.) The ``start_response`` callable is used to begin the HTTP response, and it must return a @@ -668,26 +687,32 @@ section, below). The ``status`` argument is an HTTP "status" string like ``"200 OK"`` -or ``"404 Not Found"``. The string **must not** contain control -characters, and must not be terminated with a carriage return, -linefeed, or combination thereof. +or ``"404 Not Found"``. That is, it is a string consisting of a +Status-Code and a Reason-Phrase, in that order and separated by a +single space, with no surrounding whitespace or other characters. +(See RFC 2616, Section 6.1.1 for more information.) The string +**must not** contain control characters, and must not be terminated +with a carriage return, linefeed, or combination thereof. -The ``headers`` argument is a list of ``(header_name,header_value)`` -tuples. It must be a Python list; i.e. ``type(headers) is -ListType)``, and the server **may** change its contents in any way -it desires. Each ``header_name`` must be a valid HTTP header name, -without a trailing colon or other punctuation. Each ``header_value`` -**must not** include *any* control characters, including carriage -returns or linefeeds, either embedded or at the end. (These -requirements are to minimize the complexity of any parsing that must -be performed by servers, gateways, and intermediate response +The ``response_headers`` argument is a list of ``(header_name, +header_value)`` tuples. It must be a Python list; i.e. +``type(response_headers) is ListType``, and the server **may** change +its contents in any way it desires. Each ``header_name`` must be a +valid HTTP header field-name (as defined by RFC 2616, Section 4.2), +without a trailing colon or other punctuation. + +Each ``header_value`` **must not** include *any* control characters, +including carriage returns or linefeeds, either embedded or at the end. +(These requirements are to minimize the complexity of any parsing that +must be performed by servers, gateways, and intermediate response processors that need to inspect or modify response headers.) In general, the server or gateway is responsible for ensuring that correct headers are sent to the client: if the application omits -a needed header, the server or gateway *should* add it. For example, -the HTTP ``Date:`` and ``Server:`` headers would normally be supplied -by the server or gateway. +a header required by HTTP (or other relevant specifications that are in +effect), the server or gateway **must** add it. For example, the HTTP +``Date:`` and ``Server:`` headers would normally be supplied by the +server or gateway. (A reminder for server/gateway authors: HTTP header names are case-insensitive, so be sure to take that into consideration when @@ -699,23 +724,33 @@ connection to the web server. These features are the exclusive province of the actual web server, and a server or gateway **should** consider it a fatal error for an application to attempt -using them, and raise an error if they are supplied to +sending them, and raise an error if they are supplied to ``start_response()``. (For more specifics on "hop-by-hop" features and headers, please see the `Other HTTP Features`_ section below.) The ``start_response`` callable **must not** actually transmit the -HTTP headers. It must store them until the first ``write`` call, or -until after the first iteration of the application return value that -yields a non-empty string. This is to ensure that buffered and -asynchronous applications can replace their originally intended output -with error output, up until the last possible moment. +response headers. Instead, it must store them for the server or +gateway to transmit **only** after the first iteration of the +application return value that yields a non-empty string, or upon +the application's first invocation of the ``write()`` callable. In +other words, response headers must not be sent until there is actual +body data available, or until the application's returned iterable is +exhausted. (The only possible exception to this rule is if the +response headers explicitly include a ``Content-Length`` of zero.) + +This delaying of response header transmission is to ensure that buffered +and asynchronous applications can replace their originally intended +output with error output, up until the last possible moment. For +example, the application may need to change the response status from +"200 OK" to "500 Internal Error", if an error occurs while the body is +being generated within an application buffer. The ``exc_info`` argument, if supplied, must be a Python ``sys.exc_info()`` tuple. This argument should be supplied by the application only if ``start_response`` is being called by an error handler. If ``exc_info`` is supplied, and no HTTP headers have been output yet, ``start_response`` should replace the currently-stored -HTTP headers with the newly-supplied ones, thus allowing the +HTTP response headers with the newly-supplied ones, thus allowing the application to "change its mind" about the output when an error has occurred. @@ -747,7 +782,7 @@ creating a circular reference through the traceback and frames involved. The simplest way to do this is something like:: - def start_response(status,headers,exc_info=None): + def start_response(status,response_headers,exc_info=None): if exc_info: try: # do stuff w/exc_info here @@ -795,18 +830,15 @@ Generally speaking, applications will achieve the best throughput by buffering their (modestly-sized) output and sending it all at -once. When this is the case, applications **should** simply -return a single-element iterable containing their entire output as -a single string. +once. This is a common approach in existing frameworks such as +Zope: the output is buffered in a StringIO or similar object, then +transmitted all at once, along with the response headers. -(In addition to improved performance, buffering all of an application's -output has an advantage for error handling: the buffered output can -be discarded and replaced by an error page, rather than dumping an -error message in the middle of some partially-completed output. For -this and other reasons, many existing Python frameworks already -accumulate their output for a single write, unless the application -explicitly requests streaming, or the expected output is larger than -practical for buffering (e.g. multi-megabyte PDFs).) +The corresponding approach in WSGI is for the application to simply +return a single-element iterable (such as a list) containing the +response body as a single string. This is the recommended approach +for the vast majority of application functions, that render +HTML pages whose text easily fits in memory. For large files, however, or for specialized uses of HTTP streaming (such as multipart "server push"), an application may need to provide @@ -815,7 +847,7 @@ be time-consuming to produce, but it would be useful to send ahead the portion of the response that precedes it. -In these cases, applications **should** return an iterator (usually +In these cases, applications will usually return an iterator (often a generator-iterator) that produces the output in a block-by-block fashion. These blocks may be broken to coincide with mulitpart boundaries (for "server push"), or just before time-consuming @@ -894,11 +926,10 @@ New WSGI applications and frameworks **should not** use the ``write()`` callable if it is possible to avoid doing so. The ``write()`` callable is strictly a hack to support imperative -streaming APIs. In general, applications should either be -internally buffered, or produce iterable output, as this makes -it possible for web servers to interleave other tasks in the -same Python thread, potentially providing better throughput for -the server as a whole. +streaming APIs. In general, applications should produce their +output via their returned iterable, as this makes it possible +for web servers to interleave other tasks in the same Python thread, +potentially providing better throughput for the server as a whole. The ``write()`` callable is returned by the ``start_response()`` callable, and it accepts a single parameter: a string to be @@ -909,11 +940,15 @@ that it is buffered for transmission while the application proceeds forward. -An application **may** return a non-empty iterable even if it -invokes ``write()``, and that output must be treated normally -by the server or gateway (i.e., it must be sent or queued -immediately). Applications **must not** invoke ``write()`` -from within their return iterable. +An application **must** return an iterable object, even if it +uses ``write()`` to produce all or part of its response body. +The returned iterable **may** be empty (i.e. yield no non-empty +strings), but if it *does* yield non-empty strings, that output +must be treated normally by the server or gateway (i.e., it must be +sent or queued immediately). Applications **must not** invoke +``write()`` from within their return iterable, and therefore any +strings yielded by the iterable are transmitted after all strings +passed to ``write()`` have been sent to the client. Unicode Issues @@ -926,9 +961,9 @@ where a string object is required, is undefined. Note also that strings passed to ``start_response()`` as a status or -as headers **must** follow RFC 2616 with respect to encoding. That -is, they must either be ISO-8859-1 characters, or use RFC 2047 MIME -encoding. +as response headers **must** follow RFC 2616 with respect to encoding. +That is, they must either be ISO-8859-1 characters, or use RFC 2047 +MIME encoding. On Python platforms where the ``str`` or ``StringType`` type is in fact Unicode-based (e.g. Jython, IronPython, Python 3000, etc.), all @@ -964,15 +999,15 @@ try: # regular application code here status = "200 Froody" - headers = [("content-type","text/plain")] - start_response(status, headers) + response_headers = [("content-type","text/plain")] + start_response(status, response_headers) return ["normal body goes here"] except: # XXX should trap runtime issues like MemoryError, KeyboardInterrupt # in a separate handler before this bare 'except:'... status = "500 Oops" - headers = [("content-type","text/plain")] - start_response(status, headers, sys.exc_info()) + response_headers = [("content-type","text/plain")] + start_response(status, response_headers, sys.exc_info()) return ["error body goes here"] If no output has been written when an exception occurs, the call to @@ -1041,8 +1076,9 @@ response. It is always possible for the application developer to add middleware components to supply additional features, so server/gateway developers should be conservative in their implementation. In a sense, -a server should consider itself to be like an HTTP "proxy server", with -the application being an HTTP "origin server". +a server should consider itself to be like an HTTP "gateway server", +with the application being an HTTP "origin server". (See RFC 2616, +section 1.3, for the definition of these terms.) However, because WSGI servers and applications do not communicate via HTTP, what RFC 2616 calls "hop-by-hop" headers do not apply to WSGI @@ -1564,6 +1600,10 @@ older versions of Python" section, as well as the optional ``wsgi.file_wrapper`` facility. +* Mark Nottingham, who reviewed the spec extensively for issues with + HTTP RFC compliance, especially with regard to HTTP/1.1 features that + I didn't even know existed until he pointed them out. + References ========== @@ -1580,6 +1620,9 @@ .. [4] "End-to-end and Hop-by-hop Headers" -- HTTP/1.1, Section 13.5.1 (http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1) +.. [5] mod_ssl Reference, "Environment Variables" + (http://www.modssl.org/docs/2.8/ssl_reference.html#ToC25) + Copyright ========= From rhettinger at users.sourceforge.net Sat Oct 2 02:43:15 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat Oct 2 02:43:19 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.30, 1.31 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11281 Modified Files: collectionsmodule.c Log Message: * Bulletproof the method for detecting mutations during iteration. The previous approach was too easily fooled (a rotate() sufficed). * Use it->counter to determine when iteration is complete. The previous approach was too complex. * Strengthen an assertion and add a comment here or there. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- collectionsmodule.c 1 Oct 2004 15:25:53 -0000 1.30 +++ collectionsmodule.c 2 Oct 2004 00:43:13 -0000 1.31 @@ -70,6 +70,7 @@ int leftindex; /* in range(BLOCKLEN) */ int rightindex; /* in range(BLOCKLEN) */ int len; + long state; /* incremented whenever the indices move */ PyObject *weakreflist; /* List of weak references */ } dequeobject; @@ -98,6 +99,7 @@ deque->leftindex = CENTER + 1; deque->rightindex = CENTER; deque->len = 0; + deque->state = 0; deque->weakreflist = NULL; return (PyObject *)deque; @@ -108,6 +110,7 @@ { deque->rightindex++; deque->len++; + deque->state++; if (deque->rightindex == BLOCKLEN) { block *b = newblock(deque->rightblock, NULL); if (b == NULL) @@ -129,6 +132,7 @@ { deque->leftindex--; deque->len++; + deque->state++; if (deque->leftindex == -1) { block *b = newblock(NULL, deque->leftblock); if (b == NULL) @@ -158,6 +162,7 @@ item = deque->rightblock->data[deque->rightindex]; deque->rightindex--; deque->len--; + deque->state++; if (deque->rightindex == -1) { if (deque->len == 0) { @@ -193,6 +198,7 @@ item = deque->leftblock->data[deque->leftindex]; deque->leftindex++; deque->len--; + deque->state++; if (deque->leftindex == BLOCKLEN) { if (deque->len == 0) { @@ -229,6 +235,7 @@ while ((item = PyIter_Next(it)) != NULL) { deque->rightindex++; deque->len++; + deque->state++; if (deque->rightindex == BLOCKLEN) { block *b = newblock(deque->rightblock, NULL); if (b == NULL) { @@ -264,6 +271,7 @@ while ((item = PyIter_Next(it)) != NULL) { deque->leftindex--; deque->len++; + deque->state++; if (deque->leftindex == -1) { block *b = newblock(NULL, deque->leftblock); if (b == NULL) { @@ -341,13 +349,14 @@ { PyObject *item; - while (deque_len(deque)) { + while (deque->len) { item = deque_pop(deque, NULL); assert (item != NULL); Py_DECREF(item); } assert(deque->leftblock == deque->rightblock && - deque->leftindex > deque->rightindex); + deque->leftindex - 1 == deque->rightindex && + deque->len == 0); return 0; } @@ -822,8 +831,8 @@ int index; block *b; dequeobject *deque; - int len; - int counter; + long state; /* state when the iterator is created */ + int counter; /* number of items remaining for iteration */ } dequeiterobject; PyTypeObject dequeiter_type; @@ -840,7 +849,7 @@ it->index = deque->leftindex; Py_INCREF(deque); it->deque = deque; - it->len = deque->len; + it->state = deque->state; it->counter = deque->len; return (PyObject *)it; } @@ -856,24 +865,27 @@ dequeiter_next(dequeiterobject *it) { PyObject *item; - if (it->b == it->deque->rightblock && it->index > it->deque->rightindex) + + if (it->counter == 0) return NULL; - if (it->len != it->deque->len) { - it->len = -1; /* Make this state sticky */ + if (it->deque->state != it->state) { it->counter = 0; PyErr_SetString(PyExc_RuntimeError, - "deque changed size during iteration"); + "deque mutated during iteration"); return NULL; } + assert (!(it->b == it->deque->rightblock && + it->index > it->deque->rightindex)); item = it->b->data[it->index]; it->index++; - if (it->index == BLOCKLEN && it->b->rightlink != NULL) { + it->counter--; + if (it->index == BLOCKLEN && it->counter > 0) { + assert (it->b->rightlink != NULL); it->b = it->b->rightlink; it->index = 0; } - it->counter--; Py_INCREF(item); return item; } @@ -938,7 +950,7 @@ it->index = deque->rightindex; Py_INCREF(deque); it->deque = deque; - it->len = deque->len; + it->state = deque->state; it->counter = deque->len; return (PyObject *)it; } @@ -947,24 +959,26 @@ dequereviter_next(dequeiterobject *it) { PyObject *item; - if (it->b == it->deque->leftblock && it->index < it->deque->leftindex) + if (it->counter == 0) return NULL; - if (it->len != it->deque->len) { - it->len = -1; /* Make this state sticky */ + if (it->deque->state != it->state) { it->counter = 0; PyErr_SetString(PyExc_RuntimeError, - "deque changed size during iteration"); + "deque mutated during iteration"); return NULL; } + assert (!(it->b == it->deque->leftblock && + it->index < it->deque->leftindex)); item = it->b->data[it->index]; it->index--; - if (it->index == -1 && it->b->leftlink != NULL) { + it->counter--; + if (it->index == -1 && it->counter > 0) { + assert (it->b->leftlink != NULL); it->b = it->b->leftlink; it->index = BLOCKLEN - 1; } - it->counter--; Py_INCREF(item); return item; } From jvr at users.sourceforge.net Sat Oct 2 10:40:49 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Sat Oct 2 10:40:53 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py,1.4,1.5 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14988 Modified Files: plistlib.py Log Message: Which reminds me, I've had a much improved plistlib.py lying around for ages. The main improvements are: - a much more convenient API: readPlist() and writePlist() - support non-dict top-level objects Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- plistlib.py 10 Jul 2003 14:26:06 -0000 1.4 +++ plistlib.py 2 Oct 2004 08:40:47 -0000 1.5 @@ -1,15 +1,16 @@ """plistlib.py -- a tool to generate and parse MacOSX .plist files. -The main class in this module is Plist. It takes a set of arbitrary -keyword arguments, which will be the top level elements of the plist -dictionary. After instantiation you can add more elements by assigning -new attributes to the Plist instance. +The PropertList (.plist) file format is a simple XML pickle supporting +basic object types, like dictionaries, lists, numbers and strings. +Usually the top level object is a dictionary. -To write out a plist file, call the write() method of the Plist -instance with a filename or a file object. +To write out a plist file, use the writePlist(rootObject, pathOrFile) +function. 'rootObject' is the top level object, 'pathOrFile' is a +filename or a (writable) file object. -To parse a plist from a file, use the Plist.fromFile(pathOrFile) -classmethod, with a file name or a file object as the only argument. +To parse a plist from a file, use the readPlist(pathOrFile) +function, with a file name or a (readable) file object as the only +argument. It returns the top level object (usually a dictionary). (Warning: you need pyexpat installed for this to work, ie. it doesn't work with a vanilla Python 2.2 as shipped with MacOS X.2.) @@ -17,9 +18,10 @@ dictionaries, Data or Date objects. String values (including dictionary keys) may be unicode strings -- they will be written out as UTF-8. -For convenience, this module exports a class named Dict(), which -allows you to easily construct (nested) dicts using keyword arguments. -But regular dicts work, too. +This module exports a class named Dict(), which allows you to easily +construct (nested) dicts using keyword arguments as well as accessing +values with attribute notation, where d.foo is equivalent to d["foo"]. +Regular dictionaries work, too. To support Boolean values in plists with Python < 2.3, "bool", "True" and "False" are exported. Use these symbols from this module if you @@ -33,7 +35,7 @@ Generate Plist example: - pl = Plist( + pl = Dict( aString="Doodah", aList=["A", "B", 12, 32.1, [1, 2, 3]], aFloat = 0.1, @@ -50,31 +52,62 @@ ) # unicode keys are possible, but a little awkward to use: pl[u'\xc5benraa'] = "That was a unicode key." - pl.write(fileName) + writePlist(pl, fileName) Parse Plist example: - pl = Plist.fromFile(pathOrFile) - print pl.aKey + pl = readPlist(pathOrFile) + print pl.aKey # same as pl["aKey"] """ -# written by Just van Rossum (just@letterror.com), 2002-11-19 + +__all__ = ["readPlist", "writePlist", "Plist", "Data", "Date", "Dict", + "False", "True", "bool"] +# Note: the Plist class has been deprecated, Dict, False, True and bool +# are here only for compatibility with Python 2.2. -__all__ = ["Plist", "Data", "Date", "Dict", "False", "True", "bool"] +def readPlist(pathOrFile): + """Read a .plist file. 'pathOrFile' may either be a file name or a + (readable) file object. Return the unpacked root object (which + usually is a dictionary). + """ + didOpen = 0 + if isinstance(pathOrFile, (str, unicode)): + pathOrFile = open(pathOrFile) + didOpen = 1 + p = PlistParser() + rootObject = p.parse(pathOrFile) + if didOpen: + pathOrFile.close() + return rootObject -INDENT = "\t" +def writePlist(rootObject, pathOrFile): + """Write 'rootObject' to a .plist file. 'pathOrFile' may either be a + file name or a (writable) file object. + """ + didOpen = 0 + if isinstance(pathOrFile, (str, unicode)): + pathOrFile = open(pathOrFile, "w") + didOpen = 1 + writer = PlistWriter(pathOrFile) + writer.writeln("") + writer.writeValue(rootObject) + writer.writeln("") + if didOpen: + pathOrFile.close() class DumbXMLWriter: - def __init__(self, file): + def __init__(self, file, indentLevel=0, indent="\t"): self.file = file self.stack = [] - self.indentLevel = 0 + self.indentLevel = indentLevel + self.indent = indent def beginElement(self, element): self.stack.append(element) @@ -89,22 +122,30 @@ def simpleElement(self, element, value=None): if value is not None: - value = _encode(value) + value = _escapeAndEncode(value) self.writeln("<%s>%s" % (element, value, element)) else: self.writeln("<%s/>" % element) def writeln(self, line): if line: - self.file.write(self.indentLevel * INDENT + line + "\n") + self.file.write(self.indentLevel * self.indent + line + "\n") else: self.file.write("\n") -def _encode(text): - text = text.replace("&", "&") - text = text.replace("<", "<") - return text.encode("utf-8") +import re +# Regex to strip all control chars, but for \t \n \r and \f +_controlStripper = re.compile(r"[\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0e\x0f" + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]") + +def _escapeAndEncode(text): + text = text.replace("\r\n", "\n") # convert DOS line endings + text = text.replace("\r", "\n") # convert Mac line endings + text = text.replace("&", "&") # escape '&' + text = text.replace("<", "<") # escape '<' + text = _controlStripper.sub("?", text) # replace control chars with '?' + return text.encode("utf-8") # encode as UTF-8 PLISTHEADER = """\ @@ -114,9 +155,10 @@ class PlistWriter(DumbXMLWriter): - def __init__(self, file): - file.write(PLISTHEADER) - DumbXMLWriter.__init__(self, file) + def __init__(self, file, indentLevel=0, indent="\t", writeHeader=1): + if writeHeader: + file.write(PLISTHEADER) + DumbXMLWriter.__init__(self, file, indentLevel, indent) def writeValue(self, value): if isinstance(value, (str, unicode)): @@ -133,7 +175,7 @@ elif isinstance(value, float): # should perhaps use repr() for better precision? self.simpleElement("real", str(value)) - elif isinstance(value, (dict, Dict)): + elif isinstance(value, dict): self.writeDict(value) elif isinstance(value, Data): self.writeData(value) @@ -169,66 +211,55 @@ self.endElement("array") -class Dict: +class Dict(dict): - """Dict wrapper for convenient access of values through attributes.""" + """Convenience dictionary subclass: it allows dict construction using + keyword arguments (just like dict() in 2.3) as well as attribute notation + to retrieve values, making d.foo more or less uquivalent to d["foo"]. + """ - def __init__(self, **kwargs): - self.__dict__.update(kwargs) + def __new__(cls, **kwargs): + self = dict.__new__(cls) + self.update(kwargs) + return self - def __cmp__(self, other): - if isinstance(other, self.__class__): - return cmp(self.__dict__, other.__dict__) - elif isinstance(other, dict): - return cmp(self.__dict__, other) - else: - return cmp(id(self), id(other)) + def __init__(self, **kwargs): + self.update(kwargs) - def __str__(self): - return "%s(**%s)" % (self.__class__.__name__, self.__dict__) - __repr__ = __str__ + def __getattr__(self, attr): + try: + value = self[attr] + except KeyError: + raise AttributeError, attr + return value - def copy(self): - return self.__class__(**self.__dict__) + def __setattr__(self, attr, value): + self[attr] = value - def __getattr__(self, attr): - """Delegate everything else to the dict object.""" - return getattr(self.__dict__, attr) + def __delattr__(self, attr): + try: + del self[attr] + except KeyError: + raise AttributeError, attr class Plist(Dict): - """The main Plist object. Basically a dict (the toplevel object - of a plist is a dict) with two additional methods to read from - and write to files. + """This class has been deprecated! Use the Dict with readPlist() and + writePlist() functions instead. """ def fromFile(cls, pathOrFile): - didOpen = 0 - if isinstance(pathOrFile, (str, unicode)): - pathOrFile = open(pathOrFile) - didOpen = 1 - p = PlistParser() - plist = p.parse(pathOrFile) - if didOpen: - pathOrFile.close() + """Deprecated! Use the readPlist() function instead.""" + rootObject = readPlist(pathOrFile) + plist = cls() + plist.update(rootObject) return plist fromFile = classmethod(fromFile) def write(self, pathOrFile): - if isinstance(pathOrFile, (str, unicode)): - pathOrFile = open(pathOrFile, "w") - didOpen = 1 - else: - didOpen = 0 - - writer = PlistWriter(pathOrFile) - writer.writeln("") - writer.writeDict(self.__dict__) - writer.writeln("") - - if didOpen: - pathOrFile.close() + """Deprecated! Use the writePlist() function instead.""" + writePlist(self, pathOrFile) class Data: @@ -323,7 +354,7 @@ self.currentKey = None elif not self.stack: # this is the root object - assert self.root is value + self.root = value else: self.stack[-1].append(value) @@ -339,10 +370,7 @@ # element handlers def begin_dict(self, attrs): - if self.root is None: - self.root = d = Plist() - else: - d = Dict() + d = Dict() self.addObject(d) self.stack.append(d) def end_dict(self): @@ -401,7 +429,7 @@ from StringIO import StringIO import time if len(sys.argv) == 1: - pl = Plist( + pl = Dict( aString="Doodah", aList=["A", "B", 12, 32.1, [1, 2, 3]], aFloat = 0.1, @@ -414,10 +442,10 @@ ), someData = Data(""), someMoreData = Data("" * 10), - aDate = Date(time.mktime(time.gmtime())), +# aDate = Date(time.mktime(time.gmtime())), ) elif len(sys.argv) == 2: - pl = Plist.fromFile(sys.argv[1]) + pl = readPlist(sys.argv[1]) else: print "Too many arguments: at most 1 plist file can be given." sys.exit(1) @@ -425,13 +453,13 @@ # unicode keys are possible, but a little awkward to use: pl[u'\xc5benraa'] = "That was a unicode key." f = StringIO() - pl.write(f) + writePlist(pl, f) xml = f.getvalue() print xml f.seek(0) - pl2 = Plist.fromFile(f) + pl2 = readPlist(f) assert pl == pl2 f = StringIO() - pl2.write(f) + writePlist(pl2, f) assert xml == f.getvalue() #print repr(pl2) From rhettinger at users.sourceforge.net Sat Oct 2 12:56:50 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat Oct 2 12:56:53 2004 Subject: [Python-checkins] python/dist/src/Modules itertoolsmodule.c, 1.36, 1.37 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3067 Modified Files: itertoolsmodule.c Log Message: Replace structure member before decreffing. Index: itertoolsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/itertoolsmodule.c,v retrieving revision 1.36 retrieving revision 1.37 diff -u -d -r1.36 -r1.37 --- itertoolsmodule.c 28 Sep 2004 04:45:27 -0000 1.36 +++ itertoolsmodule.c 2 Oct 2004 10:56:43 -0000 1.37 @@ -662,6 +662,7 @@ { PyObject *item; PyObject *it; + PyObject *tmp; while (1) { item = PyIter_Next(lz->it); @@ -681,9 +682,10 @@ it = PyObject_GetIter(lz->saved); if (it == NULL) return NULL; - Py_DECREF(lz->it); + tmp = lz->it; lz->it = it; lz->firstpass = 1; + Py_DECREF(tmp); } } From rhettinger at users.sourceforge.net Sat Oct 2 13:03:03 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat Oct 2 13:03:05 2004 Subject: [Python-checkins] python/dist/src/Doc/mac libaetypes.tex, 1.3, 1.4 libmacic.tex, 1.16, 1.17 using.tex, 1.11, 1.12 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4246/Doc/mac Modified Files: libaetypes.tex libmacic.tex using.tex Log Message: SF bug#1038917 fix typos (Contributed by George Yoshida.) Index: libaetypes.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/mac/libaetypes.tex,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- libaetypes.tex 22 Sep 2003 15:27:11 -0000 1.3 +++ libaetypes.tex 2 Oct 2004 11:02:57 -0000 1.4 @@ -121,7 +121,7 @@ \end{classdesc} \begin{classdesc}{NProperty}{fr} -Abstract basclass for an OSA property. The subclass should set the class +Abstract baseclass for an OSA property. The subclass should set the class attributes \code{want} and \code{which} to designate which property we are talking about. Instances of subclasses of this class are Object Specifiers. Index: libmacic.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/mac/libmacic.tex,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- libmacic.tex 14 Jul 2001 02:10:11 -0000 1.16 +++ libmacic.tex 2 Oct 2004 11:02:58 -0000 1.17 @@ -74,7 +74,7 @@ \begin{methoddesc}{launchurl}{url\optional{, hint}} -Parse the given URL, lauch the correct application and pass it the +Parse the given URL, launch the correct application and pass it the URL. The optional \var{hint} can be a scheme name such as \code{'mailto:'}, in which case incomplete URLs are completed with this scheme. If \var{hint} is not provided, incomplete URLs are invalid. Index: using.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/mac/using.tex,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- using.tex 15 Jul 2004 22:38:06 -0000 1.11 +++ using.tex 2 Oct 2004 11:02:58 -0000 1.12 @@ -384,7 +384,7 @@ You can create a new script, open a previously saved script, and save your currently open script by selecting the appropriate item in the ``File'' menu. Dropping a Python script onto the -\program{Python IDE} will open it for editting. +\program{Python IDE} will open it for editing. If you try to open a script with the \program{Python IDE} but either can't locate it from the ``Open'' dialog box, or you get an error From rhettinger at users.sourceforge.net Sat Oct 2 13:03:05 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat Oct 2 13:03:08 2004 Subject: [Python-checkins] python/dist/src/Misc HISTORY,1.13,1.14 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4246/Misc Modified Files: HISTORY Log Message: SF bug#1038917 fix typos (Contributed by George Yoshida.) Index: HISTORY =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/HISTORY,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- HISTORY 21 Mar 2004 18:48:22 -0000 1.13 +++ HISTORY 2 Oct 2004 11:02:59 -0000 1.14 @@ -7255,7 +7255,7 @@ x[lo:hi:stride] == x[slice(lo, hi, stride)] x[a, ..., z] == x[(a, Ellipses, z)] -- New documentation for errno and cgi mdoules. +- New documentation for errno and cgi modules. - The directory containing the script passed to the interpreter is inserted in from of sys.path; "." is no longer a default path From rhettinger at users.sourceforge.net Sat Oct 2 13:03:29 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat Oct 2 13:03:32 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libgetopt.tex,1.23,1.24 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4246/Doc/lib Modified Files: libgetopt.tex Log Message: SF bug#1038917 fix typos (Contributed by George Yoshida.) Index: libgetopt.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libgetopt.tex,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- libgetopt.tex 26 Jan 2004 19:40:18 -0000 1.23 +++ libgetopt.tex 2 Oct 2004 11:02:57 -0000 1.24 @@ -37,7 +37,7 @@ \var{options} should be an empty string. Long options on the command line can be recognized so long as they provide a prefix of the option name that matches exactly one of the accepted options. For example, -it \var{long_options} is \code{['foo', 'frob']}, the option +if \var{long_options} is \code{['foo', 'frob']}, the option \longprogramopt{fo} will match as \longprogramopt{foo}, but \longprogramopt{f} will not match uniquely, so \exception{GetoptError} will be raised. From arigo at users.sourceforge.net Sat Oct 2 15:59:36 2004 From: arigo at users.sourceforge.net (arigo@users.sourceforge.net) Date: Sat Oct 2 15:59:39 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_deque.py,1.16,1.17 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2501/Lib/test Modified Files: test_deque.py Log Message: Upon insertion, if memory runs out, the deque was left in a corrupted state. deque_item(): a performance bug: the linked list of blocks was followed from the left in most cases, because the test (i < (deque->len >> 1)) was after "i %= BLOCKLEN". deque_clear(): replaced a call to deque_len() with deque->len; not sure what this call was here for, nor if all compilers under the sun would inline it. deque_traverse(): I belive that it could be called by the GC when the deque has leftblock==rightblock==NULL, because it is tracked before the first block is allocated (though closely before). Still, a C extension module subclassing deque could provide its own tp_alloc that could trigger a GC collection after the PyObject_GC_Track()... deque_richcompare(): rewrote to cleanly check for end-of-iterations instead of relying on deque.__iter__().next() to succeed exactly len(deque) times -- an assumption which can break if deques are subclassed. Added a test. I wonder if the length should be explicitely bounded to INT_MAX, with OverflowErrors, as in listobject.c. On 64-bit machines, adding more than INT_MAX in the deque will result in trouble. (Note to anyone/me fixing this: carefully check for overflows if len is close to INT_MAX in the following functions: deque_rotate(), deque_item(), deque_ass_item()) Index: test_deque.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_deque.py,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- test_deque.py 1 Oct 2004 02:01:03 -0000 1.16 +++ test_deque.py 2 Oct 2004 13:59:34 -0000 1.17 @@ -479,6 +479,15 @@ d = None self.assertRaises(ReferenceError, str, p) + def test_strange_subclass(self): + class X(deque): + def __iter__(self): + return iter([]) + d1 = X([1,2,3]) + d2 = X([4,5,6]) + d1 == d2 # not clear if this is supposed to be True or False, + # but it used to give a SystemError + #============================================================================== libreftest = """ From arigo at users.sourceforge.net Sat Oct 2 15:59:36 2004 From: arigo at users.sourceforge.net (arigo@users.sourceforge.net) Date: Sat Oct 2 15:59:40 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.31, 1.32 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2501/Modules Modified Files: collectionsmodule.c Log Message: Upon insertion, if memory runs out, the deque was left in a corrupted state. deque_item(): a performance bug: the linked list of blocks was followed from the left in most cases, because the test (i < (deque->len >> 1)) was after "i %= BLOCKLEN". deque_clear(): replaced a call to deque_len() with deque->len; not sure what this call was here for, nor if all compilers under the sun would inline it. deque_traverse(): I belive that it could be called by the GC when the deque has leftblock==rightblock==NULL, because it is tracked before the first block is allocated (though closely before). Still, a C extension module subclassing deque could provide its own tp_alloc that could trigger a GC collection after the PyObject_GC_Track()... deque_richcompare(): rewrote to cleanly check for end-of-iterations instead of relying on deque.__iter__().next() to succeed exactly len(deque) times -- an assumption which can break if deques are subclassed. Added a test. I wonder if the length should be explicitely bounded to INT_MAX, with OverflowErrors, as in listobject.c. On 64-bit machines, adding more than INT_MAX in the deque will result in trouble. (Note to anyone/me fixing this: carefully check for overflows if len is close to INT_MAX in the following functions: deque_rotate(), deque_item(), deque_ass_item()) Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- collectionsmodule.c 2 Oct 2004 00:43:13 -0000 1.31 +++ collectionsmodule.c 2 Oct 2004 13:59:33 -0000 1.32 @@ -108,19 +108,19 @@ static PyObject * deque_append(dequeobject *deque, PyObject *item) { - deque->rightindex++; - deque->len++; deque->state++; - if (deque->rightindex == BLOCKLEN) { + if (deque->rightindex == BLOCKLEN-1) { block *b = newblock(deque->rightblock, NULL); if (b == NULL) return NULL; assert(deque->rightblock->rightlink == NULL); deque->rightblock->rightlink = b; deque->rightblock = b; - deque->rightindex = 0; + deque->rightindex = -1; } Py_INCREF(item); + deque->len++; + deque->rightindex++; deque->rightblock->data[deque->rightindex] = item; Py_RETURN_NONE; } @@ -130,19 +130,19 @@ static PyObject * deque_appendleft(dequeobject *deque, PyObject *item) { - deque->leftindex--; - deque->len++; deque->state++; - if (deque->leftindex == -1) { + if (deque->leftindex == 0) { block *b = newblock(NULL, deque->leftblock); if (b == NULL) return NULL; assert(deque->leftblock->leftlink == NULL); deque->leftblock->leftlink = b; deque->leftblock = b; - deque->leftindex = BLOCKLEN - 1; + deque->leftindex = BLOCKLEN; } Py_INCREF(item); + deque->len++; + deque->leftindex--; deque->leftblock->data[deque->leftindex] = item; Py_RETURN_NONE; } @@ -233,10 +233,8 @@ return NULL; while ((item = PyIter_Next(it)) != NULL) { - deque->rightindex++; - deque->len++; deque->state++; - if (deque->rightindex == BLOCKLEN) { + if (deque->rightindex == BLOCKLEN-1) { block *b = newblock(deque->rightblock, NULL); if (b == NULL) { Py_DECREF(item); @@ -246,8 +244,10 @@ assert(deque->rightblock->rightlink == NULL); deque->rightblock->rightlink = b; deque->rightblock = b; - deque->rightindex = 0; + deque->rightindex = -1; } + deque->len++; + deque->rightindex++; deque->rightblock->data[deque->rightindex] = item; } Py_DECREF(it); @@ -269,10 +269,8 @@ return NULL; while ((item = PyIter_Next(it)) != NULL) { - deque->leftindex--; - deque->len++; deque->state++; - if (deque->leftindex == -1) { + if (deque->leftindex == 0) { block *b = newblock(NULL, deque->leftblock); if (b == NULL) { Py_DECREF(item); @@ -282,8 +280,10 @@ assert(deque->leftblock->leftlink == NULL); deque->leftblock->leftlink = b; deque->leftblock = b; - deque->leftindex = BLOCKLEN - 1; + deque->leftindex = BLOCKLEN; } + deque->len++; + deque->leftindex--; deque->leftblock->data[deque->leftindex] = item; } Py_DECREF(it); @@ -365,7 +365,7 @@ { block *b; PyObject *item; - int n; + int n, index=i; if (i < 0 || i >= deque->len) { PyErr_SetString(PyExc_IndexError, @@ -383,7 +383,7 @@ i += deque->leftindex; n = i / BLOCKLEN; i %= BLOCKLEN; - if (i < (deque->len >> 1)) { + if (index < (deque->len >> 1)) { b = deque->leftblock; while (n--) b = b->rightlink; @@ -514,7 +514,6 @@ int index; int indexlo = deque->leftindex; - assert(deque->leftblock != NULL); for (b = deque->leftblock; b != NULL; b = b->rightlink) { const int indexhi = b == deque->rightblock ? deque->rightindex : @@ -642,7 +641,7 @@ deque_richcompare(PyObject *v, PyObject *w, int op) { PyObject *it1=NULL, *it2=NULL, *x, *y; - int i, b, vs, ws, minlen, cmp=-1; + int b, vs, ws, cmp=-1; if (!PyObject_TypeCheck(v, &deque_type) || !PyObject_TypeCheck(w, &deque_type)) { @@ -673,16 +672,13 @@ it2 = PyObject_GetIter(w); if (it2 == NULL) goto done; - minlen = (vs < ws) ? vs : ws; - for (i=0 ; i < minlen ; i++) { + for (;;) { x = PyIter_Next(it1); - if (x == NULL) + if (x == NULL && PyErr_Occurred()) goto done; y = PyIter_Next(it2); - if (y == NULL) { - Py_DECREF(x); - goto done; - } + if (x == NULL || y == NULL) + break; b = PyObject_RichCompareBool(x, y, Py_EQ); if (b == 0) { cmp = PyObject_RichCompareBool(x, y, op); @@ -695,14 +691,18 @@ if (b == -1) goto done; } - /* Elements are equal through minlen. The longest input is the greatest */ + /* We reached the end of one deque or both */ + Py_XDECREF(x); + Py_XDECREF(y); + if (PyErr_Occurred()) + goto done; switch (op) { - case Py_LT: cmp = vs < ws; break; - case Py_LE: cmp = vs <= ws; break; - case Py_EQ: cmp = vs == ws; break; - case Py_NE: cmp = vs != ws; break; - case Py_GT: cmp = vs > ws; break; - case Py_GE: cmp = vs >= ws; break; + case Py_LT: cmp = y != NULL; break; /* if w was longer */ + case Py_LE: cmp = x == NULL; break; /* if v was not longer */ + case Py_EQ: cmp = x == y; break; /* if we reached the end of both */ + case Py_NE: cmp = x != y; break; /* if one deque continues */ + case Py_GT: cmp = x != NULL; break; /* if v was longer */ + case Py_GE: cmp = y == NULL; break; /* if w was not longer */ } done: From jvr at users.sourceforge.net Sat Oct 2 16:06:20 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Sat Oct 2 16:06:23 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_plistlib.py, 1.3, 1.4 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3864 Modified Files: test_plistlib.py Log Message: use new readPlist() and writePlist() functions Index: test_plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_plistlib.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- test_plistlib.py 1 Jul 2003 20:22:30 -0000 1.3 +++ test_plistlib.py 2 Oct 2004 14:06:18 -0000 1.4 @@ -14,7 +14,7 @@ pass def _create(self): - pl = plistlib.Plist( + pl = plistlib.Dict( aString="Doodah", aList=["A", "B", 12, 32.1, [1, 2, 3]], aFloat = 0.1, @@ -45,24 +45,24 @@ def test_io(self): pl = self._create() - pl.write(test_support.TESTFN) - pl2 = plistlib.Plist.fromFile(test_support.TESTFN) + plistlib.writePlist(pl, test_support.TESTFN) + pl2 = plistlib.readPlist(test_support.TESTFN) self.assertEqual(dict(pl), dict(pl2)) def test_stringio(self): from StringIO import StringIO f = StringIO() pl = self._create() - pl.write(f) - pl2 = plistlib.Plist.fromFile(StringIO(f.getvalue())) + plistlib.writePlist(pl, f) + pl2 = plistlib.readPlist(StringIO(f.getvalue())) self.assertEqual(dict(pl), dict(pl2)) def test_cstringio(self): from cStringIO import StringIO f = StringIO() pl = self._create() - pl.write(f) - pl2 = plistlib.Plist.fromFile(StringIO(f.getvalue())) + plistlib.writePlist(pl, f) + pl2 = plistlib.readPlist(StringIO(f.getvalue())) self.assertEqual(dict(pl), dict(pl2)) From jvr at users.sourceforge.net Sat Oct 2 16:06:59 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Sat Oct 2 16:07:01 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py,1.5,1.6 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4010 Modified Files: plistlib.py Log Message: removed 2.2 support Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- plistlib.py 2 Oct 2004 08:40:47 -0000 1.5 +++ plistlib.py 2 Oct 2004 14:06:56 -0000 1.6 @@ -11,8 +11,6 @@ To parse a plist from a file, use the readPlist(pathOrFile) function, with a file name or a (readable) file object as the only argument. It returns the top level object (usually a dictionary). -(Warning: you need pyexpat installed for this to work, ie. it doesn't -work with a vanilla Python 2.2 as shipped with MacOS X.2.) Values can be strings, integers, floats, booleans, tuples, lists, dictionaries, Data or Date objects. String values (including dictionary @@ -23,10 +21,6 @@ values with attribute notation, where d.foo is equivalent to d["foo"]. Regular dictionaries work, too. -To support Boolean values in plists with Python < 2.3, "bool", "True" -and "False" are exported. Use these symbols from this module if you -want to be compatible with Python 2.2.x (strongly recommended). - The plist type is supported through the Data class. This is a thin wrapper around a Python string. @@ -63,10 +57,8 @@ """ -__all__ = ["readPlist", "writePlist", "Plist", "Data", "Date", "Dict", - "False", "True", "bool"] -# Note: the Plist class has been deprecated, Dict, False, True and bool -# are here only for compatibility with Python 2.2. +__all__ = ["readPlist", "writePlist", "Plist", "Data", "Date", "Dict"] +# Note: the Plist class has been deprecated. def readPlist(pathOrFile): @@ -215,7 +207,7 @@ """Convenience dictionary subclass: it allows dict construction using keyword arguments (just like dict() in 2.3) as well as attribute notation - to retrieve values, making d.foo more or less uquivalent to d["foo"]. + to retrieve values, making d.foo equivalent to d["foo"]. """ def __new__(cls, **kwargs): @@ -400,66 +392,3 @@ self.addObject(Data.fromBase64(self.getData())) def end_date(self): self.addObject(Date(self.getData())) - - -# cruft to support booleans in Python <= 2.3 -import sys -if sys.version_info[:2] < (2, 3): - # Python 2.2 and earlier: no booleans - # Python 2.2.x: booleans are ints - class bool(int): - """Imitation of the Python 2.3 bool object.""" - def __new__(cls, value): - return int.__new__(cls, not not value) - def __repr__(self): - if self: - return "True" - else: - return "False" - True = bool(1) - False = bool(0) -else: - # Bind the boolean builtins to local names - True = True - False = False - bool = bool - - -if __name__ == "__main__": - from StringIO import StringIO - import time - if len(sys.argv) == 1: - pl = Dict( - aString="Doodah", - aList=["A", "B", 12, 32.1, [1, 2, 3]], - aFloat = 0.1, - anInt = 728, - aDict=Dict( - anotherString="", - aUnicodeValue=u'M\xe4ssig, Ma\xdf', - aTrueValue=True, - aFalseValue=False, - ), - someData = Data(""), - someMoreData = Data("" * 10), -# aDate = Date(time.mktime(time.gmtime())), - ) - elif len(sys.argv) == 2: - pl = readPlist(sys.argv[1]) - else: - print "Too many arguments: at most 1 plist file can be given." - sys.exit(1) - - # unicode keys are possible, but a little awkward to use: - pl[u'\xc5benraa'] = "That was a unicode key." - f = StringIO() - writePlist(pl, f) - xml = f.getvalue() - print xml - f.seek(0) - pl2 = readPlist(f) - assert pl == pl2 - f = StringIO() - writePlist(pl2, f) - assert xml == f.getvalue() - #print repr(pl2) From bwarsaw at users.sourceforge.net Sun Oct 3 05:16:21 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 05:16:24 2004 Subject: [Python-checkins] python/dist/src/Lib/email/test/data msg_41.txt, NONE, 1.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email/test/data In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32603/Lib/email/test/data Added Files: msg_41.txt Log Message: Big email 3.0 API changes, with updated unit tests and documentation. Briefly (from the NEWS file): - Updates for the email package: + All deprecated APIs that in email 2.x issued warnings have been removed: _encoder argument to the MIMEText constructor, Message.add_payload(), Utils.dump_address_pair(), Utils.decode(), Utils.encode() + New deprecations: Generator.__call__(), Message.get_type(), Message.get_main_type(), Message.get_subtype(), the 'strict' argument to the Parser constructor. These will be removed in email 3.1. + Support for Python earlier than 2.3 has been removed (see PEP 291). + All defect classes have been renamed to end in 'Defect'. + Some FeedParser fixes; also a MultipartInvariantViolationDefect will be added to messages that claim to be multipart but really aren't. + Updates to documentation. --- NEW FILE: msg_41.txt --- From: "Allison Dunlap" To: yyy@example.com Subject: 64423 Date: Sun, 11 Jul 2004 16:09:27 -0300 MIME-Version: 1.0 Content-Type: multipart/alternative; Blah blah blah From bwarsaw at users.sourceforge.net Sun Oct 3 05:16:21 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 05:16:26 2004 Subject: [Python-checkins] python/dist/src/Lib/email/test __init__.py, 1.1, 1.2 test_email.py, 1.61, 1.62 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32603/Lib/email/test Modified Files: __init__.py test_email.py Log Message: Big email 3.0 API changes, with updated unit tests and documentation. Briefly (from the NEWS file): - Updates for the email package: + All deprecated APIs that in email 2.x issued warnings have been removed: _encoder argument to the MIMEText constructor, Message.add_payload(), Utils.dump_address_pair(), Utils.decode(), Utils.encode() + New deprecations: Generator.__call__(), Message.get_type(), Message.get_main_type(), Message.get_subtype(), the 'strict' argument to the Parser constructor. These will be removed in email 3.1. + Support for Python earlier than 2.3 has been removed (see PEP 291). + All defect classes have been renamed to end in 'Defect'. + Some FeedParser fixes; also a MultipartInvariantViolationDefect will be added to messages that claim to be multipart but really aren't. + Updates to documentation. Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/test/__init__.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- __init__.py 19 Jul 2002 22:29:00 -0000 1.1 +++ __init__.py 3 Oct 2004 03:16:18 -0000 1.2 @@ -1,2 +0,0 @@ -# Copyright (C) 2002 Python Software Foundation -# Author: barry@zope.com (Barry Warsaw) Index: test_email.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/test/test_email.py,v retrieving revision 1.61 retrieving revision 1.62 diff -u -d -r1.61 -r1.62 --- test_email.py 16 Aug 2004 15:47:34 -0000 1.61 +++ test_email.py 3 Oct 2004 03:16:18 -0000 1.62 @@ -1,4 +1,5 @@ # Copyright (C) 2001-2004 Python Software Foundation +# Contact: email-sig@python.org # email package unit tests import os @@ -51,25 +52,20 @@ # Base test class class TestEmailBase(unittest.TestCase): - if hasattr(difflib, 'ndiff'): - # Python 2.2 and beyond - def ndiffAssertEqual(self, first, second): - """Like failUnlessEqual except use ndiff for readable output.""" - if first <> second: - sfirst = str(first) - ssecond = str(second) - diff = difflib.ndiff(sfirst.splitlines(), ssecond.splitlines()) - fp = StringIO() - print >> fp, NL, NL.join(diff) - raise self.failureException, fp.getvalue() - else: - # Python 2.1 - ndiffAssertEqual = unittest.TestCase.assertEqual + def ndiffAssertEqual(self, first, second): + """Like failUnlessEqual except use ndiff for readable output.""" + if first <> second: + sfirst = str(first) + ssecond = str(second) + diff = difflib.ndiff(sfirst.splitlines(), ssecond.splitlines()) + fp = StringIO() + print >> fp, NL, NL.join(diff) + raise self.failureException, fp.getvalue() - def _msgobj(self, filename, strict=False): + def _msgobj(self, filename): fp = openfile(findfile(filename)) try: - msg = email.message_from_file(fp, strict=strict) + msg = email.message_from_file(fp) finally: fp.close() return msg @@ -493,44 +489,12 @@ # Test the email.Encoders module class TestEncoders(unittest.TestCase): - def test_encode_noop(self): - eq = self.assertEqual - msg = MIMEText('hello world', _encoder=Encoders.encode_noop) - eq(msg.get_payload(), 'hello world') - - def test_encode_7bit(self): - eq = self.assertEqual - msg = MIMEText('hello world', _encoder=Encoders.encode_7or8bit) - eq(msg.get_payload(), 'hello world') - eq(msg['content-transfer-encoding'], '7bit') - msg = MIMEText('hello \x7f world', _encoder=Encoders.encode_7or8bit) - eq(msg.get_payload(), 'hello \x7f world') - eq(msg['content-transfer-encoding'], '7bit') - - def test_encode_8bit(self): - eq = self.assertEqual - msg = MIMEText('hello \x80 world', _encoder=Encoders.encode_7or8bit) - eq(msg.get_payload(), 'hello \x80 world') - eq(msg['content-transfer-encoding'], '8bit') - def test_encode_empty_payload(self): eq = self.assertEqual msg = Message() msg.set_charset('us-ascii') eq(msg['content-transfer-encoding'], '7bit') - def test_encode_base64(self): - eq = self.assertEqual - msg = MIMEText('hello world', _encoder=Encoders.encode_base64) - eq(msg.get_payload(), 'aGVsbG8gd29ybGQ=') - eq(msg['content-transfer-encoding'], 'base64') - - def test_encode_quoted_printable(self): - eq = self.assertEqual - msg = MIMEText('hello world', _encoder=Encoders.encode_quopri) - eq(msg.get_payload(), 'hello=20world') - eq(msg['content-transfer-encoding'], 'quoted-printable') - def test_default_cte(self): eq = self.assertEqual msg = MIMEText('hello world') @@ -932,16 +896,6 @@ au = MIMEAudio(self._audiodata, 'fish') self.assertEqual(im.get_type(), 'audio/fish') - def test_custom_encoder(self): - eq = self.assertEqual - def encoder(msg): - orig = msg.get_payload() - msg.set_payload(0) - msg['Content-Transfer-Encoding'] = 'broken64' - au = MIMEAudio(self._audiodata, _encoder=encoder) - eq(au.get_payload(), 0) - eq(au['content-transfer-encoding'], 'broken64') - def test_add_header(self): eq = self.assertEqual unless = self.failUnless @@ -985,16 +939,6 @@ im = MIMEImage(self._imgdata, 'fish') self.assertEqual(im.get_type(), 'image/fish') - def test_custom_encoder(self): - eq = self.assertEqual - def encoder(msg): - orig = msg.get_payload() - msg.set_payload(0) - msg['Content-Transfer-Encoding'] = 'broken64' - im = MIMEImage(self._imgdata, _encoder=encoder) - eq(im.get_payload(), 0) - eq(im['content-transfer-encoding'], 'broken64') - def test_add_header(self): eq = self.assertEqual unless = self.failUnless @@ -1396,8 +1340,8 @@ eq = self.assertEqual msg = self._msgobj('msg_14.txt') eq(msg.get_type(), 'text') - eq(msg.get_main_type(), None) - eq(msg.get_subtype(), None) + eq(msg.get_content_maintype(), 'text') + eq(msg.get_content_subtype(), 'plain') def test_same_boundary_inner_outer(self): unless = self.failUnless @@ -1406,14 +1350,17 @@ inner = msg.get_payload(0) unless(hasattr(inner, 'defects')) self.assertEqual(len(inner.defects), 1) - unless(isinstance(inner.defects[0], Errors.StartBoundaryNotFound)) + unless(isinstance(inner.defects[0], + Errors.StartBoundaryNotFoundDefect)) def test_multipart_no_boundary(self): unless = self.failUnless msg = self._msgobj('msg_25.txt') unless(isinstance(msg.get_payload(), str)) - self.assertEqual(len(msg.defects), 1) - unless(isinstance(msg.defects[0], Errors.NoBoundaryInMultipart)) + self.assertEqual(len(msg.defects), 2) + unless(isinstance(msg.defects[0], Errors.NoBoundaryInMultipartDefect)) + unless(isinstance(msg.defects[1], + Errors.MultipartInvariantViolationDefect)) def test_invalid_content_type(self): eq = self.assertEqual @@ -1464,40 +1411,19 @@ counter to RFC 2822, there's no separating newline here """) + def test_lying_multipart(self): + unless = self.failUnless + msg = self._msgobj('msg_41.txt') + unless(hasattr(msg, 'defects')) + self.assertEqual(len(msg.defects), 2) + unless(isinstance(msg.defects[0], Errors.NoBoundaryInMultipartDefect)) + unless(isinstance(msg.defects[1], + Errors.MultipartInvariantViolationDefect)) + # Test RFC 2047 header encoding and decoding class TestRFC2047(unittest.TestCase): - def test_iso_8859_1(self): - eq = self.assertEqual - s = '=?iso-8859-1?q?this=20is=20some=20text?=' - eq(Utils.decode(s), 'this is some text') - s = '=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?=' - eq(Utils.decode(s), u'Keld J\xf8rn Simonsen') - s = '=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=' \ - '=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=' - eq(Utils.decode(s), 'If you can read this you understand the example.') - s = '=?iso-8859-8?b?7eXs+SDv4SDp7Oj08A==?=' - eq(Utils.decode(s), - u'\u05dd\u05d5\u05dc\u05e9 \u05df\u05d1 \u05d9\u05dc\u05d8\u05e4\u05e0') - s = '=?iso-8859-1?q?this=20is?= =?iso-8859-1?q?some=20text?=' - eq(Utils.decode(s), u'this issome text') - s = '=?iso-8859-1?q?this=20is_?= =?iso-8859-1?q?some=20text?=' - eq(Utils.decode(s), u'this is some text') - - def test_encode_header(self): - eq = self.assertEqual - s = 'this is some text' - eq(Utils.encode(s), '=?iso-8859-1?q?this=20is=20some=20text?=') - s = 'Keld_J\xf8rn_Simonsen' - eq(Utils.encode(s), '=?iso-8859-1?q?Keld_J=F8rn_Simonsen?=') - s1 = 'If you can read this yo' - s2 = 'u understand the example.' - eq(Utils.encode(s1, encoding='b'), - '=?iso-8859-1?b?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=') - eq(Utils.encode(s2, charset='iso-8859-2', encoding='b'), - '=?iso-8859-2?b?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=') - def test_rfc2047_multiline(self): eq = self.assertEqual s = """Re: =?mac-iceland?q?r=8Aksm=9Arg=8Cs?= baz @@ -1517,10 +1443,7 @@ s = '=?ISO-8859-1?Q?Andr=E9?= Pirard ' dh = decode_header(s) eq(dh, [('Andr\xe9', 'iso-8859-1'), ('Pirard ', None)]) - # Python 2.1's unicode() builtin doesn't call the object's - # __unicode__() method. Use the following alternative instead. - #hu = unicode(make_header(dh)).encode('latin-1') - hu = make_header(dh).__unicode__().encode('latin-1') + hu = unicode(make_header(dh)).encode('latin-1') eq(hu, 'Andr\xe9 Pirard ') def test_whitespace_eater_unicode_2(self): @@ -1870,8 +1793,8 @@ eq = self.assertEquals msg, text = self._msgobj('msg_01.txt') eq(msg.get_type(), 'text/plain') - eq(msg.get_main_type(), 'text') - eq(msg.get_subtype(), 'plain') + eq(msg.get_content_maintype(), 'text') + eq(msg.get_content_subtype(), 'plain') eq(msg.get_params()[1], ('charset', 'us-ascii')) eq(msg.get_param('charset'), 'us-ascii') eq(msg.preamble, None) @@ -2712,11 +2635,7 @@ eq(decode_header(enc), [(g_head, "iso-8859-1"), (cz_head, "iso-8859-2"), (utf8_head, "utf-8")]) - # Test for conversion to unicode. BAW: Python 2.1 doesn't support the - # __unicode__() protocol, so do things this way for compatibility. - ustr = h.__unicode__() - # For Python 2.2 and beyond - #ustr = unicode(h) + ustr = unicode(h) eq(ustr.encode('utf-8'), 'Die Mieter treten hier ein werden mit einem Foerderband ' 'komfortabel den Korridor entlang, an s\xc3\xbcdl\xc3\xbcndischen ' @@ -2956,6 +2875,15 @@ self.assertEqual(msg.get_content_charset(), 'this is even more ***fun*** is it not.pdf') + def test_rfc2231_unknown_encoding(self): + m = """\ +Content-Transfer-Encoding: 8bit +Content-Disposition: inline; filename*0=X-UNKNOWN''myfile.txt + +""" + msg = email.message_from_string(m) + self.assertEqual(msg.get_filename(), 'myfile.txt') + def _testclasses(): From bwarsaw at users.sourceforge.net Sun Oct 3 05:16:21 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 05:16:26 2004 Subject: [Python-checkins] python/dist/src/Doc/lib email.tex, 1.17, 1.18 emailencoders.tex, 1.4, 1.5 emailexc.tex, 1.3, 1.4 emailmessage.tex, 1.15, 1.16 emailmimebase.tex, 1.3, 1.4 emailparser.tex, 1.9, 1.10 emailutil.tex, 1.8, 1.9 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32603/Doc/lib Modified Files: email.tex emailencoders.tex emailexc.tex emailmessage.tex emailmimebase.tex emailparser.tex emailutil.tex Log Message: Big email 3.0 API changes, with updated unit tests and documentation. Briefly (from the NEWS file): - Updates for the email package: + All deprecated APIs that in email 2.x issued warnings have been removed: _encoder argument to the MIMEText constructor, Message.add_payload(), Utils.dump_address_pair(), Utils.decode(), Utils.encode() + New deprecations: Generator.__call__(), Message.get_type(), Message.get_main_type(), Message.get_subtype(), the 'strict' argument to the Parser constructor. These will be removed in email 3.1. + Support for Python earlier than 2.3 has been removed (see PEP 291). + All defect classes have been renamed to end in 'Defect'. + Some FeedParser fixes; also a MultipartInvariantViolationDefect will be added to messages that claim to be multipart but really aren't. + Updates to documentation. Index: email.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/email.tex,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- email.tex 29 Jan 2003 05:10:27 -0000 1.17 +++ email.tex 3 Oct 2004 03:16:17 -0000 1.18 @@ -1,5 +1,5 @@ -% Copyright (C) 2001,2002 Python Software Foundation -% Author: barry@zope.com (Barry Warsaw) +% Copyright (C) 2001-2004 Python Software Foundation +% Author: barry@python.org (Barry Warsaw) \section{\module{email} --- An email and MIME handling package} @@ -7,8 +7,8 @@ \declaremodule{standard}{email} \modulesynopsis{Package supporting the parsing, manipulating, and generating email messages, including MIME documents.} -\moduleauthor{Barry A. Warsaw}{barry@zope.com} -\sectionauthor{Barry A. Warsaw}{barry@zope.com} +\moduleauthor{Barry A. Warsaw}{barry@python.org} +\sectionauthor{Barry A. Warsaw}{barry@python.org} \versionadded{2.2} @@ -22,7 +22,7 @@ function of the \refmodule{smtplib} module. The \module{email} package attempts to be as RFC-compliant as possible, supporting in addition to \rfc{2822}, such MIME-related RFCs as -\rfc{2045}-\rfc{2047}, and \rfc{2231}. +\rfc{2045}, \rfc{2046}, \rfc{2047}, and \rfc{2231}. The primary distinguishing feature of the \module{email} package is that it splits the parsing and generating of email messages from the @@ -79,7 +79,7 @@ \subsection{Encoders} \input{emailencoders} -\subsection{Exception classes} +\subsection{Exception and Defect classes} \input{emailexc} \subsection{Miscellaneous utilities} @@ -88,14 +88,41 @@ \subsection{Iterators} \input{emailiter} -\subsection{Differences from \module{email} v1 (up to Python 2.2.1)} +\subsection{Package History} Version 1 of the \module{email} package was bundled with Python releases up to Python 2.2.1. Version 2 was developed for the Python 2.3 release, and backported to Python 2.2.2. It was also available as -a separate distutils based package. \module{email} version 2 is -almost entirely backward compatible with version 1, with the -following differences: +a separate distutils-based package, and is compatible back to Python 2.1. + +\module{email} version 3.0 was released with Python 2.4 and as a separate +distutils-based package. It is compatible back to Python 2.3. + +Here are the differences between \module{email} version 3 and version 2: + +\begin{itemize} +\item The \class{FeedParser} class was introduced, and the \class{Parser} + class was implemented in terms of the \class{FeedParser}. All parsing + there for is non-strict, and parsing will make a best effort never to + raise an exception. Problems found while parsing messages are stored in + the message's \var{defect} attribute. + +\item All aspects of the API which raised \exception{DeprecationWarning}s in + version 2 have been removed. These include the \var{_encoder} argument + to the \class{MIMEText} constructor, the \method{Message.add_payload()} + method, the \function{Utils.dump_address_pair()} function, and the + functions \function{Utils.decode()} and \function{Utils.encode()}. + +\item New \exception{DeprecationWarning}s have been added to: + \method{Generator.__call__()}, \method{Message.get_type()}, + \method{Message.get_main_type()}, \method{Message.get_subtype()}, and + the \var{strict} argument to the \class{Parser} class. These are + expected to be removed in email 3.1. + +\item Support for Pythons earlier than 2.3 has been removed. +\end{itemize} + +Here are the differences between \module{email} version 2 and version 1: \begin{itemize} \item The \module{email.Header} and \module{email.Charset} modules Index: emailencoders.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailencoders.tex,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- emailencoders.tex 1 Oct 2002 04:33:14 -0000 1.4 +++ emailencoders.tex 3 Oct 2004 03:16:17 -0000 1.5 @@ -8,11 +8,11 @@ The \module{email} package provides some convenient encodings in its \module{Encoders} module. These encoders are actually used by the -\class{MIMEImage} and \class{MIMEText} class constructors to provide default -encodings. All encoder functions take exactly one argument, the -message object to encode. They usually extract the payload, encode -it, and reset the payload to this newly encoded value. They should also -set the \mailheader{Content-Transfer-Encoding} header as appropriate. +\class{MIMEAudio} and \class{MIMEImage} class constructors to provide default +encodings. All encoder functions take exactly one argument, the message +object to encode. They usually extract the payload, encode it, and reset the +payload to this newly encoded value. They should also set the +\mailheader{Content-Transfer-Encoding} header as appropriate. Here are the encoding functions provided: Index: emailexc.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailexc.tex,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- emailexc.tex 1 Oct 2002 01:05:52 -0000 1.3 +++ emailexc.tex 3 Oct 2004 03:16:17 -0000 1.4 @@ -52,3 +52,36 @@ if the \method{attach()} method is called on an instance of a class derived from \class{MIMENonMultipart} (e.g. \class{MIMEImage}). \end{excclassdesc} + +Here's the list of the defects that the \class{FeedParser} can find while +parsing messages. Note that the defects are added to the message where the +problem was found, so for example, if a message nested inside a +\mimetype{multipart/alternative} had a malformed header, that nested message +object would have a defect, but the containing messages would not. + +All defect classes are subclassed from \class{email.Errors.MessageDefect}, but +this class is \emph{not} an exception! + +\versionadded[All the defect classes were added]{2.4} + +\begin{itemize} +\item \class{NoBoundaryInMultipartDefect} -- A message claimed to be a + multipart, but had no \mimetype{boundary} parameter. + +\item \class{StartBoundaryNotFoundDefect} -- The start boundary claimed in the + \mailheader{Content-Type} header was never found. + +\item \class{FirstHeaderLineIsContinuationDefect} -- The message had a + continuation line as its first header line. + +\item \class{MisplacedEnvelopeHeaderDefect} - A ``Unix From'' header was found + in the middle of a header block. + +\item \class{MalformedHeaderDefect} -- A header was found that was missing a + colon, or was otherwise malformed. + +\item \class{MultipartInvariantViolationDefect} -- A message claimed to be a + \mimetype{multipart}, but no subparts were found. Note that when a + message has this defect, its \method{is_multipart()} method may return + false even though its content type claims to be \mimetype{multipart}. +\end{itemize} Index: emailmessage.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailmessage.tex,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- emailmessage.tex 28 Sep 2004 02:56:45 -0000 1.15 +++ emailmessage.tex 3 Oct 2004 03:16:17 -0000 1.16 @@ -359,13 +359,16 @@ \code{VALUE} to be encoded in the \code{us-ascii} charset. You can usually ignore \code{LANGUAGE}. -Your application should be prepared to deal with 3-tuple return -values, and can convert the parameter to a Unicode string like so: +If your application doesn't care whether the parameter was encoded as in +\rfc{2231}, you can collapse the parameter value by calling +\function{email.Utils.collapse_rfc2231_value()}, passing in the return value +from \method{get_param()}. This will return a suitably decoded Unicode string +whn the value is a tuple, or the original string unquoted if it isn't. For +example: \begin{verbatim} -param = msg.get_param('foo') -if isinstance(param, tuple): - param = unicode(param[2], param[0] or 'us-ascii') +rawparam = msg.get_param('foo') +param = email.Utils.collapse_rfc2231_value(rawparam) \end{verbatim} In any case, the parameter value (either the returned string, or the @@ -549,32 +552,21 @@ set the \var{epilogue} to the empty string. \end{datadesc} -\subsubsection{Deprecated methods} - -The following methods are deprecated in \module{email} version 2. -They are documented here for completeness. +\begin{datadesc}{defects} +The \var{defects} attribute contains a list of all the problems found when +parsing this message. See \refmodule{email.Errors} for a detailed description +of the possible parsing defects. -\begin{methoddesc}[Message]{add_payload}{payload} -Add \var{payload} to the message object's existing payload. If, prior -to calling this method, the object's payload was \code{None} -(i.e. never before set), then after this method is called, the payload -will be the argument \var{payload}. +\versionadded{2.4} +\end{datadesc} -If the object's payload was already a list -(i.e. \method{is_multipart()} returns \code{True}), then \var{payload} is -appended to the end of the existing payload list. +\subsubsection{Deprecated methods} -For any other type of existing payload, \method{add_payload()} will -transform the new payload into a list consisting of the old payload -and \var{payload}, but only if the document is already a MIME -multipart document. This condition is satisfied if the message's -\mailheader{Content-Type} header's main type is either -\mimetype{multipart}, or there is no \mailheader{Content-Type} -header. In any other situation, -\exception{MultipartConversionError} is raised. +\versionchanged[The \method{add_payload()} method was removed; use the +\method{attach()} method instead]{2.4} -\deprecated{2.2.2}{Use the \method{attach()} method instead.} -\end{methoddesc} +The following methods are deprecated. They are documented here for +completeness. \begin{methoddesc}[Message]{get_type}{\optional{failobj}} Return the message's content type, as a string of the form Index: emailmimebase.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailmimebase.tex,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- emailmimebase.tex 11 Mar 2003 05:03:25 -0000 1.3 +++ emailmimebase.tex 3 Oct 2004 03:16:17 -0000 1.4 @@ -142,9 +142,7 @@ to \mimetype{rfc822}. \end{classdesc} -\begin{classdesc}{MIMEText}{_text\optional{, _subtype\optional{, - _charset\optional{, _encoder}}}} - +\begin{classdesc}{MIMEText}{_text\optional{, _subtype\optional{, _charset}}} A subclass of \class{MIMENonMultipart}, the \class{MIMEText} class is used to create MIME objects of major type \mimetype{text}. \var{_text} is the string for the payload. \var{_subtype} is the @@ -153,6 +151,7 @@ \class{MIMENonMultipart} constructor; it defaults to \code{us-ascii}. No guessing or encoding is performed on the text data. -\deprecated{2.2.2}{The \var{_encoding} argument has been deprecated. -Encoding now happens implicitly based on the \var{_charset} argument.} +\versionchanged[The previously deprecated \var{_encoding} argument has +been removed. Encoding happens implicitly based on the \var{_charset} +argument]{2.4} \end{classdesc} Index: emailparser.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailparser.tex,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- emailparser.tex 24 Feb 2004 20:58:10 -0000 1.9 +++ emailparser.tex 3 Oct 2004 03:16:17 -0000 1.10 @@ -18,29 +18,79 @@ \method{is_multipart()} method, and the subparts can be accessed via the \method{get_payload()} and \method{walk()} methods. +There are actually two parser interfaces available for use, the classic +\class{Parser} API and the incremental \class{FeedParser} API. The classic +\class{Parser} API is fine if you have the entire text of the message in +memory as a string, or if the entire message lives in a file on the file +system. \class{FeedParser} is more appropriate for when you're reading the +message from a stream which might block waiting for more input (e.g. reading +an email message from a socket). The \class{FeedParser} can consume and parse +the message incrementally, and only returns the root object when you close the +parser\footnote{As of email package version 3.0, introduced in +Python 2.4, the classic \class{Parser} was re-implemented in terms of the +\class{FeedParser}, so the semantics and results are identical between the two +parsers.}. + Note that the parser can be extended in limited ways, and of course you can implement your own parser completely from scratch. There is no magical connection between the \module{email} package's bundled parser and the \class{Message} class, so your custom parser can create message object trees any way it finds necessary. -The primary parser class is \class{Parser} which parses both the -headers and the payload of the message. In the case of -\mimetype{multipart} messages, it will recursively parse the body of -the container message. Two modes of parsing are supported, -\emph{strict} parsing, which will usually reject any non-RFC compliant -message, and \emph{lax} parsing, which attempts to adjust for common -MIME formatting problems. +\subsubsection{FeedParser API} -The \module{email.Parser} module also provides a second class, called +\versionadded{2.4} + +The \class{FeedParser} provides an API that is conducive to incremental +parsing of email messages, such as would be necessary when reading the text of +an email message from a source that can block (e.g. a socket). The +\class{FeedParser} can of course be used to parse an email message fully +contained in a string or a file, but the classic \class{Parser} API may be +more convenient for such use cases. The semantics and results of the two +parser APIs are identical. + +The \class{FeedParser}'s API is simple; you create an instance, feed it a +bunch of text until there's no more to feed it, then close the parser to +retrieve the root message object. The \class{FeedParser} is extremely +accurate when parsing standards-compliant messages, and it does a very good +job of parsing non-compliant messages, providing information about how a +message was deemed broken. It will populate a message object's \var{defects} +attribute with a list of any problems it found in a message. See the +\refmodule{email.Errors} module for the list of defects that it can find. + +Here is the API for the \class{FeedParser}: + +\begin{classdesc}{FeedParser}{\optional{_factory}} +Create a \class{FeedParser} instance. Optional \var{_factory} is a +no-argument callable that will be called whenever a new message object is +needed. It defaults to the \class{email.Message.Message} class. +\end{classdesc} + +\begin{methoddesc}[FeedParser]{feed}{data} +Feed the \class{FeedParser} some more data. \var{data} should be a +string containing one or more lines. The lines can be partial and the +\class{FeedParser} will stitch such partial lines together properly. The +lines in the string can have any of the common three line endings, carriage +return, newline, or carriage return and newline (they can even be mixed). +\end{methoddesc} + +\begin{methoddesc}[FeedParser]{close}{} +Closing a \class{FeedParser} completes the parsing of all previously fed data, +and returns the root message object. It is undefined what happens if you feed +more data to a closed \class{FeedParser}. +\end{methoddesc} + +\subsubsection{Parser class API} + +The \class{Parser} provides an API that can be used to parse a message when +the complete contents of the message are available in a string or file. The +\module{email.Parser} module also provides a second class, called \class{HeaderParser} which can be used if you're only interested in the headers of the message. \class{HeaderParser} can be much faster in these situations, since it does not attempt to parse the message body, instead setting the payload to the raw body as a string. \class{HeaderParser} has the same API as the \class{Parser} class. -\subsubsection{Parser class API} - \begin{classdesc}{Parser}{\optional{_class\optional{, strict}}} The constructor for the \class{Parser} class takes an optional argument \var{_class}. This must be a callable factory (such as a @@ -49,19 +99,14 @@ \refmodule{email.Message}). The factory will be called without arguments. -The optional \var{strict} flag specifies whether strict or lax parsing -should be performed. Normally, when things like MIME terminating -boundaries are missing, or when messages contain other formatting -problems, the \class{Parser} will raise a -\exception{MessageParseError}. However, when lax parsing is enabled, -the \class{Parser} will attempt to work around such broken formatting -to produce a usable message structure (this doesn't mean -\exception{MessageParseError}s are never raised; some ill-formatted -messages just can't be parsed). The \var{strict} flag defaults to -\code{False} since lax parsing usually provides the most convenient -behavior. +The optional \var{strict} flag is ignored. \deprecated{2.4}{Because the +\class{Parser} class is a backward compatible API wrapper around the +new-in-Python 2.4 \class{FeedParser}, \emph{all} parsing is effectively +non-strict. You should simply stop passing a \var{strict} flag to the +\class{Parser} constructor.} \versionchanged[The \var{strict} flag was added]{2.2.2} +\versionchanged[The \var{strict} flag was deprecated]{2.4} \end{classdesc} The other public \class{Parser} methods are: @@ -149,4 +194,13 @@ object containing a list payload of length 1. Their \method{is_multipart()} method will return \code{True}. The single element in the list payload will be a sub-message object. + +\item Some non-standards compliant messages may not be internally consistent + about their \mimetype{multipart}-edness. Such messages may have a + \mailheader{Content-Type} header of type \mimetype{multipart}, but their + \method{is_multipart()} method may return \code{False}. If such + messages were parsed with the \class{FeedParser}, they will have an + instance of the \class{MultipartInvariantViolationDefect} class in their + \var{defects} attribute list. See \refmodule{email.Errors} for + details. \end{itemize} Index: emailutil.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailutil.tex,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- emailutil.tex 1 Oct 2002 04:33:16 -0000 1.8 +++ emailutil.tex 3 Oct 2004 03:16:17 -0000 1.9 @@ -119,24 +119,33 @@ string is encoded using the empty string for \var{language}. \end{funcdesc} +\begin{funcdesc}{collapse_rfc2231_value}{value\optional{, errors\optional{, + fallback_charset}}} +When a header parameter is encoded in \rfc{2231} format, +\method{Message.get_param()} may return a 3-tuple containing the character +set, language, and value. \function{collapse_rfc2231_value()} turns this into +a unicode string. Optional \var{errors} is passed to the \var{errors} +argument of the built-in \function{unicode()} function; it defaults to +\code{replace}. Optional \var{fallback_charset} specifies the character set +to use if the one in the \rfc{2231} header is not known by Python; it defaults +to \code{us-ascii}. + +For convenience, if the \var{value} passed to +\function{collapse_rfc2231_value()} is not a tuple, it should be a string and +it is returned unquoted. +\end{funcdesc} + \begin{funcdesc}{decode_params}{params} Decode parameters list according to \rfc{2231}. \var{params} is a sequence of 2-tuples containing elements of the form \code{(content-type, string-value)}. \end{funcdesc} -The following functions have been deprecated: - -\begin{funcdesc}{dump_address_pair}{pair} -\deprecated{2.2.2}{Use \function{formataddr()} instead.} -\end{funcdesc} - -\begin{funcdesc}{decode}{s} -\deprecated{2.2.2}{Use \method{Header.decode_header()} instead.} -\end{funcdesc} - +\versionchanged[The \function{dump_address_pair()} function has been removed; +use \function{formataddr()} instead.]{2.4} -\begin{funcdesc}{encode}{s\optional{, charset\optional{, encoding}}} -\deprecated{2.2.2}{Use \method{Header.encode()} instead.} -\end{funcdesc} +\versionchanged[The \function{decode()} function has been removed; use the +\method{Header.decode_header()} method instead.]{2.4} +\versionchanged[The \function{encode()} function has been removed; use the +\method{Header.encode()} method instead.]{2.4} From bwarsaw at users.sourceforge.net Sun Oct 3 05:16:22 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 05:16:27 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1147,1.1148 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32603/Misc Modified Files: NEWS Log Message: Big email 3.0 API changes, with updated unit tests and documentation. Briefly (from the NEWS file): - Updates for the email package: + All deprecated APIs that in email 2.x issued warnings have been removed: _encoder argument to the MIMEText constructor, Message.add_payload(), Utils.dump_address_pair(), Utils.decode(), Utils.encode() + New deprecations: Generator.__call__(), Message.get_type(), Message.get_main_type(), Message.get_subtype(), the 'strict' argument to the Parser constructor. These will be removed in email 3.1. + Support for Python earlier than 2.3 has been removed (see PEP 291). + All defect classes have been renamed to end in 'Defect'. + Some FeedParser fixes; also a MultipartInvariantViolationDefect will be added to messages that claim to be multipart but really aren't. + Updates to documentation. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1147 retrieving revision 1.1148 diff -u -d -r1.1147 -r1.1148 --- NEWS 1 Oct 2004 02:13:16 -0000 1.1147 +++ NEWS 3 Oct 2004 03:16:19 -0000 1.1148 @@ -34,6 +34,19 @@ Library ------- +- Updates for the email package: + + All deprecated APIs that in email 2.x issued warnings have been removed: + _encoder argument to the MIMEText constructor, Message.add_payload(), + Utils.dump_address_pair(), Utils.decode(), Utils.encode() + + New deprecations: Generator.__call__(), Message.get_type(), + Message.get_main_type(), Message.get_subtype(), the 'strict' argument to + the Parser constructor. These will be removed in email 3.1. + + Support for Python earlier than 2.3 has been removed (see PEP 291). + + All defect classes have been renamed to end in 'Defect'. + + Some FeedParser fixes; also a MultipartInvariantViolationDefect will be + added to messages that claim to be multipart but really aren't. + + Updates to documentation. + - re's findall() and finditer() functions now take an optional flags argument just like the compile(), search(), and match() functions. Also, documented the previously existing start and stop parameters for the findall() and From bwarsaw at users.sourceforge.net Sun Oct 3 05:16:25 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 05:16:30 2004 Subject: [Python-checkins] python/dist/src/Lib/email Charset.py, 1.15, 1.16 Encoders.py, 1.8, 1.9 Errors.py, 1.6, 1.7 FeedParser.py, 1.9, 1.10 Generator.py, 1.23, 1.24 Header.py, 1.29, 1.30 Iterators.py, 1.14, 1.15 MIMEAudio.py, 1.4, 1.5 MIMEBase.py, 1.6, 1.7 MIMEImage.py, 1.6, 1.7 MIMEMessage.py, 1.6, 1.7 MIMEMultipart.py, 1.4, 1.5 MIMENonMultipart.py, 1.2, 1.3 MIMEText.py, 1.8, 1.9 Message.py, 1.37, 1.38 Parser.py, 1.22, 1.23 Utils.py, 1.26, 1.27 __init__.py, 1.32, 1.33 _parseaddr.py, 1.9, 1.10 base64MIME.py, 1.7, 1.8 quopriMIME.py, 1.6, 1.7 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32603/Lib/email Modified Files: Charset.py Encoders.py Errors.py FeedParser.py Generator.py Header.py Iterators.py MIMEAudio.py MIMEBase.py MIMEImage.py MIMEMessage.py MIMEMultipart.py MIMENonMultipart.py MIMEText.py Message.py Parser.py Utils.py __init__.py _parseaddr.py base64MIME.py quopriMIME.py Log Message: Big email 3.0 API changes, with updated unit tests and documentation. Briefly (from the NEWS file): - Updates for the email package: + All deprecated APIs that in email 2.x issued warnings have been removed: _encoder argument to the MIMEText constructor, Message.add_payload(), Utils.dump_address_pair(), Utils.decode(), Utils.encode() + New deprecations: Generator.__call__(), Message.get_type(), Message.get_main_type(), Message.get_subtype(), the 'strict' argument to the Parser constructor. These will be removed in email 3.1. + Support for Python earlier than 2.3 has been removed (see PEP 291). + All defect classes have been renamed to end in 'Defect'. + Some FeedParser fixes; also a MultipartInvariantViolationDefect will be added to messages that claim to be multipart but really aren't. + Updates to documentation. Index: Charset.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Charset.py,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- Charset.py 9 May 2004 03:24:43 -0000 1.15 +++ Charset.py 3 Oct 2004 03:16:18 -0000 1.16 @@ -1,18 +1,6 @@ # Copyright (C) 2001-2004 Python Software Foundation -# Author: che@debian.org (Ben Gertzfield), barry@python.org (Barry Warsaw) - -# XXX The following information needs updating. - -# Python 2.3 doesn't come with any Asian codecs by default. Two packages are -# currently available and supported as of this writing (30-Dec-2003): -# -# CJKCodecs -# http://cjkpython.i18n.org -# This package contains Chinese, Japanese, and Korean codecs - -# JapaneseCodecs -# http://www.asahi-net.or.jp/~rd6t-kjym/python -# Some Japanese users prefer this codec package +# Author: Ben Gertzfield, Barry Warsaw +# Contact: email-sig@python.org import email.base64MIME import email.quopriMIME @@ -21,9 +9,9 @@ # Flags for types of header encodings -QP = 1 # Quoted-Printable -BASE64 = 2 # Base64 -SHORTEST = 3 # the shorter of QP and base64, but only for headers +QP = 1 # Quoted-Printable +BASE64 = 2 # Base64 +SHORTEST = 3 # the shorter of QP and base64, but only for headers # In "=?charset?q?hello_world?=", the =?, ?q?, and ?= add up to 7 MISC_LEN = 7 @@ -128,7 +116,7 @@ documentation for more information. """ if body_enc == SHORTEST: - raise ValueError, 'SHORTEST not allowed for body_enc' + raise ValueError('SHORTEST not allowed for body_enc') CHARSETS[charset] = (header_enc, body_enc, output_charset) Index: Encoders.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Encoders.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- Encoders.py 13 May 2004 22:50:12 -0000 1.8 +++ Encoders.py 3 Oct 2004 03:16:18 -0000 1.9 @@ -1,37 +1,16 @@ # Copyright (C) 2001-2004 Python Software Foundation -# Author: barry@python.org (Barry Warsaw) +# Author: Barry Warsaw +# Contact: email-sig@python.org """Encodings and related functions.""" import base64 +from quopri import encodestring as _encodestring - - -# Helpers -try: - from quopri import encodestring as _encodestring - - def _qencode(s): - enc = _encodestring(s, quotetabs=1) - # Must encode spaces, which quopri.encodestring() doesn't do - return enc.replace(' ', '=20') -except ImportError: - # Python 2.1 doesn't have quopri.encodestring() - from cStringIO import StringIO - import quopri as _quopri - - def _qencode(s): - if not s: - return s - hasnewline = (s[-1] == '\n') - infp = StringIO(s) - outfp = StringIO() - _quopri.encode(infp, outfp, quotetabs=1) - # Python 2.x's encode() doesn't encode spaces even when quotetabs==1 - value = outfp.getvalue().replace(' ', '=20') - if not hasnewline and value[-1] == '\n': - return value[:-1] - return value +def _qencode(s): + enc = _encodestring(s, quotetabs=True) + # Must encode spaces, which quopri.encodestring() doesn't do + return enc.replace(' ', '=20') def _bencode(s): Index: Errors.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Errors.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- Errors.py 9 May 2004 03:26:07 -0000 1.6 +++ Errors.py 3 Oct 2004 03:16:18 -0000 1.7 @@ -1,5 +1,6 @@ # Copyright (C) 2001-2004 Python Software Foundation -# Author: barry@python.org (Barry Warsaw) +# Author: Barry Warsaw +# Contact: email-sig@python.org """email package exception classes.""" @@ -33,17 +34,20 @@ def __init__(self, line=None): self.line = line -class NoBoundaryInMultipart(MessageDefect): +class NoBoundaryInMultipartDefect(MessageDefect): """A message claimed to be a multipart but had no boundary parameter.""" -class StartBoundaryNotFound(MessageDefect): +class StartBoundaryNotFoundDefect(MessageDefect): """The claimed start boundary was never found.""" -class FirstHeaderLineIsContinuation(MessageDefect): +class FirstHeaderLineIsContinuationDefect(MessageDefect): """A message had a continuation line as its first header line.""" -class MisplacedEnvelopeHeader(MessageDefect): +class MisplacedEnvelopeHeaderDefect(MessageDefect): """A 'Unix-from' header was found in the middle of a header block.""" -class MalformedHeader(MessageDefect): - """Found a header that was missing a colon, or was otherwise malformed""" +class MalformedHeaderDefect(MessageDefect): + """Found a header that was missing a colon, or was otherwise malformed.""" + +class MultipartInvariantViolationDefect(MessageDefect): + """A message claimed to be a multipart but no subparts were found.""" Index: FeedParser.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/FeedParser.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- FeedParser.py 7 Aug 2004 15:57:51 -0000 1.9 +++ FeedParser.py 3 Oct 2004 03:16:18 -0000 1.10 @@ -1,5 +1,6 @@ # Copyright (C) 2004 Python Software Foundation # Authors: Baxter, Wouters and Warsaw +# Contact: email-sig@python.org """FeedParser - An email feed parser. @@ -15,7 +16,7 @@ The other advantage of this parser is that it will never throw a parsing exception. Instead, when it finds something unexpected, it adds a 'defect' to the current message. Defects are just instances that live on the message -object's .defect attribute. +object's .defects attribute. """ import re @@ -100,7 +101,7 @@ # and the eol character(s). Gather up a list of lines after # re-attaching the newlines. lines = [] - for i in range(len(parts) / 2): + for i in range(len(parts) // 2): lines.append(parts[i*2] + parts[i*2+1]) self.pushlines(lines) @@ -156,6 +157,10 @@ self._call_parse() root = self._pop_message() assert not self._msgstack + # Look for final set of defects + if root.get_content_maintype() == 'multipart' \ + and not root.is_multipart(): + root.defects.append(Errors.MultipartInvariantViolationDefect()) return root def _new_message(self): @@ -166,7 +171,6 @@ self._msgstack[-1].attach(msg) self._msgstack.append(msg) self._cur = msg - self._cur.defects = [] self._last = msg def _pop_message(self): @@ -259,7 +263,7 @@ # defined a boundary. That's a problem which we'll handle by # reading everything until the EOF and marking the message as # defective. - self._cur.defects.append(Errors.NoBoundaryInMultipart()) + self._cur.defects.append(Errors.NoBoundaryInMultipartDefect()) lines = [] for line in self._input: if line is NeedMoreData: @@ -305,6 +309,8 @@ if eolmo: preamble[-1] = lastline[:-len(eolmo.group(0))] self._cur.preamble = EMPTYSTRING.join(preamble) + #import pdb ; pdb.set_trace() + # See SF bug #1030941 capturing_preamble = False self._input.unreadline(line) continue @@ -363,7 +369,7 @@ # that as a defect and store the captured text as the payload. # Otherwise everything from here to the EOF is epilogue. if capturing_preamble: - self._cur.defects.append(Errors.StartBoundaryNotFound()) + self._cur.defects.append(Errors.StartBoundaryNotFoundDefect()) self._cur.set_payload(EMPTYSTRING.join(preamble)) return # If the end boundary ended in a newline, we'll need to make sure @@ -408,7 +414,7 @@ # The first line of the headers was a continuation. This # is illegal, so let's note the defect, store the illegal # line, and ignore it for purposes of headers. - defect = Errors.FirstHeaderLineIsContinuation(line) + defect = Errors.FirstHeaderLineIsContinuationDefect(line) self._cur.defects.append(defect) continue lastvalue.append(line) @@ -436,13 +442,13 @@ else: # Weirdly placed unix-from line. Note this as a defect # and ignore it. - defect = Errors.MisplacedEnvelopeHeader(line) + defect = Errors.MisplacedEnvelopeHeaderDefect(line) self._cur.defects.append(defect) continue # Split the line on the colon separating field name from value. i = line.find(':') if i < 0: - defect = Errors.MalformedHeader(line) + defect = Errors.MalformedHeaderDefect(line) self._cur.defects.append(defect) continue lastheader = line[:i] Index: Generator.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Generator.py,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- Generator.py 9 May 2004 03:35:17 -0000 1.23 +++ Generator.py 3 Oct 2004 03:16:18 -0000 1.24 @@ -1,13 +1,14 @@ # Copyright (C) 2001-2004 Python Software Foundation -# Author: barry@python.org (Barry Warsaw) +# Author: Barry Warsaw +# Contact: email-sig@python.org -"""Classes to generate plain text from a message object tree. -""" +"""Classes to generate plain text from a message object tree.""" import re import sys import time import random +import warnings from cStringIO import StringIO from email.Header import Header @@ -81,7 +82,10 @@ self._write(msg) # For backwards compatibility, but this is slower - __call__ = flatten + def __call__(self, msg, unixfrom=False): + warnings.warn('__call__() deprecated; use flatten()', + DeprecationWarning, 2) + self.flatten(msg, unixfrom) def clone(self, fp): """Clone this generator with the exact same options.""" @@ -175,7 +179,7 @@ if cset is not None: payload = cset.body_encode(payload) if not isinstance(payload, basestring): - raise TypeError, 'string payload expected: %s' % type(payload) + raise TypeError('string payload expected: %s' % type(payload)) if self._mangle_from_: payload = fcre.sub('>From ', payload) self._fp.write(payload) @@ -271,6 +275,8 @@ +_FMT = '[Non-text (%(type)s) part of message omitted, filename %(filename)s]' + class DecodedGenerator(Generator): """Generator a text representation of a message. @@ -301,13 +307,13 @@ """ Generator.__init__(self, outfp, mangle_from_, maxheaderlen) if fmt is None: - fmt = ('[Non-text (%(type)s) part of message omitted, ' - 'filename %(filename)s]') - self._fmt = fmt + self._fmt = _FMT + else: + self._fmt = fmt def _dispatch(self, msg): for part in msg.walk(): - maintype = part.get_main_type('text') + maintype = part.get_content_maintype() if maintype == 'text': print >> self, part.get_payload(decode=True) elif maintype == 'multipart': @@ -315,9 +321,9 @@ pass else: print >> self, self._fmt % { - 'type' : part.get_type('[no MIME type]'), - 'maintype' : part.get_main_type('[no main MIME type]'), - 'subtype' : part.get_subtype('[no sub-MIME type]'), + 'type' : part.get_content_type(), + 'maintype' : part.get_content_maintype(), + 'subtype' : part.get_content_subtype(), 'filename' : part.get_filename('[no filename]'), 'description': part.get('Content-Description', '[no description]'), Index: Header.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Header.py,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- Header.py 10 May 2004 14:44:04 -0000 1.29 +++ Header.py 3 Oct 2004 03:16:18 -0000 1.30 @@ -1,5 +1,6 @@ # Copyright (C) 2002-2004 Python Software Foundation -# Author: che@debian.org (Ben Gertzfield), barry@python.org (Barry Warsaw) +# Author: Ben Gertzfield, Barry Warsaw +# Contact: email-sig@python.org """Header encoding and decoding functionality.""" Index: Iterators.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Iterators.py,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- Iterators.py 13 May 2004 20:14:20 -0000 1.14 +++ Iterators.py 3 Oct 2004 03:16:18 -0000 1.15 @@ -1,8 +1,8 @@ # Copyright (C) 2001-2004 Python Software Foundation -# Author: Barry Warsaw +# Author: Barry Warsaw +# Contact: email-sig@python.org -"""Various types of useful iterators and generators. -""" +"""Various types of useful iterators and generators.""" import sys from cStringIO import StringIO Index: MIMEAudio.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEAudio.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- MIMEAudio.py 30 Sep 2002 21:29:10 -0000 1.4 +++ MIMEAudio.py 3 Oct 2004 03:16:18 -0000 1.5 @@ -1,7 +1,8 @@ +# Copyright (C) 2001-2004 Python Software Foundation # Author: Anthony Baxter +# Contact: email-sig@python.org -"""Class representing audio/* type MIME documents. -""" +"""Class representing audio/* type MIME documents.""" import sndhdr from cStringIO import StringIO @@ -65,7 +66,7 @@ if _subtype is None: _subtype = _whatsnd(_audiodata) if _subtype is None: - raise TypeError, 'Could not find audio MIME subtype' + raise TypeError('Could not find audio MIME subtype') MIMENonMultipart.__init__(self, 'audio', _subtype, **_params) self.set_payload(_audiodata) _encoder(self) Index: MIMEBase.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEBase.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- MIMEBase.py 2 Jun 2002 19:04:39 -0000 1.6 +++ MIMEBase.py 3 Oct 2004 03:16:18 -0000 1.7 @@ -1,8 +1,8 @@ -# Copyright (C) 2001,2002 Python Software Foundation -# Author: barry@zope.com (Barry Warsaw) +# Copyright (C) 2001-2004 Python Software Foundation +# Author: Barry Warsaw +# Contact: email-sig@python.org -"""Base class for MIME specializations. -""" +"""Base class for MIME specializations.""" from email import Message Index: MIMEImage.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEImage.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- MIMEImage.py 30 Sep 2002 22:15:00 -0000 1.6 +++ MIMEImage.py 3 Oct 2004 03:16:18 -0000 1.7 @@ -1,8 +1,8 @@ -# Copyright (C) 2001,2002 Python Software Foundation -# Author: barry@zope.com (Barry Warsaw) +# Copyright (C) 2001-2004 Python Software Foundation +# Author: Barry Warsaw +# Contact: email-sig@python.org -"""Class representing image/* type MIME documents. -""" +"""Class representing image/* type MIME documents.""" import imghdr @@ -39,7 +39,7 @@ if _subtype is None: _subtype = imghdr.what(None, _imagedata) if _subtype is None: - raise TypeError, 'Could not guess image MIME subtype' + raise TypeError('Could not guess image MIME subtype') MIMENonMultipart.__init__(self, 'image', _subtype, **_params) self.set_payload(_imagedata) _encoder(self) Index: MIMEMessage.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEMessage.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- MIMEMessage.py 9 Jul 2002 02:40:35 -0000 1.6 +++ MIMEMessage.py 3 Oct 2004 03:16:18 -0000 1.7 @@ -1,8 +1,8 @@ -# Copyright (C) 2001,2002 Python Software Foundation -# Author: barry@zope.com (Barry Warsaw) +# Copyright (C) 2001-2004 Python Software Foundation +# Author: Barry Warsaw +# Contact: email-sig@python.org -"""Class representing message/* MIME documents. -""" +"""Class representing message/* MIME documents.""" from email import Message from email.MIMENonMultipart import MIMENonMultipart @@ -24,7 +24,7 @@ """ MIMENonMultipart.__init__(self, 'message', _subtype) if not isinstance(_msg, Message.Message): - raise TypeError, 'Argument is not an instance of Message' + raise TypeError('Argument is not an instance of Message') # It's convenient to use this base class method. We need to do it # this way or we'll get an exception Message.Message.attach(self, _msg) Index: MIMEMultipart.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEMultipart.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- MIMEMultipart.py 9 May 2004 18:04:24 -0000 1.4 +++ MIMEMultipart.py 3 Oct 2004 03:16:18 -0000 1.5 @@ -1,8 +1,8 @@ # Copyright (C) 2002-2004 Python Software Foundation -# Author: barry@python.org (Barry Warsaw) +# Author: Barry Warsaw +# Contact: email-sig@python.org -"""Base class for MIME multipart/* type messages. -""" +"""Base class for MIME multipart/* type messages.""" from email import MIMEBase Index: MIMENonMultipart.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMENonMultipart.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- MIMENonMultipart.py 28 Sep 2002 20:25:15 -0000 1.2 +++ MIMENonMultipart.py 3 Oct 2004 03:16:18 -0000 1.3 @@ -1,8 +1,8 @@ -# Copyright (C) 2002 Python Software Foundation -# Author: barry@zope.com (Barry Warsaw) +# Copyright (C) 2002-2004 Python Software Foundation +# Author: Barry Warsaw +# Contact: email-sig@python.org -"""Base class for MIME type messages that are not multipart. -""" +"""Base class for MIME type messages that are not multipart.""" from email import Errors from email import MIMEBase Index: MIMEText.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/MIMEText.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- MIMEText.py 11 Mar 2003 05:04:09 -0000 1.8 +++ MIMEText.py 3 Oct 2004 03:16:18 -0000 1.9 @@ -1,10 +1,9 @@ -# Copyright (C) 2001,2002 Python Software Foundation -# Author: barry@zope.com (Barry Warsaw) +# Copyright (C) 2001-2004 Python Software Foundation +# Author: Barry Warsaw +# Contact: email-sig@python.org -"""Class representing text/* type MIME documents. -""" +"""Class representing text/* type MIME documents.""" -import warnings from email.MIMENonMultipart import MIMENonMultipart from email.Encoders import encode_7or8bit @@ -13,8 +12,7 @@ class MIMEText(MIMENonMultipart): """Class for generating text/* type MIME documents.""" - def __init__(self, _text, _subtype='plain', _charset='us-ascii', - _encoder=None): + def __init__(self, _text, _subtype='plain', _charset='us-ascii'): """Create a text/* type MIME document. _text is the string for this message object. @@ -24,22 +22,7 @@ _charset is the character set parameter added to the Content-Type header. This defaults to "us-ascii". Note that as a side-effect, the Content-Transfer-Encoding header will also be set. - - The use of the _encoder is deprecated. The encoding of the payload, - and the setting of the character set parameter now happens implicitly - based on the _charset argument. If _encoder is supplied, then a - DeprecationWarning is used, and the _encoder functionality may - override any header settings indicated by _charset. This is probably - not what you want. """ MIMENonMultipart.__init__(self, 'text', _subtype, **{'charset': _charset}) self.set_payload(_text, _charset) - if _encoder is not None: - warnings.warn('_encoder argument is obsolete.', - DeprecationWarning, 2) - # Because set_payload() with a _charset will set its own - # Content-Transfer-Encoding header, we need to delete the - # existing one or will end up with two of them. :( - del self['content-transfer-encoding'] - _encoder(self) Index: Message.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Message.py,v retrieving revision 1.37 retrieving revision 1.38 diff -u -d -r1.37 -r1.38 --- Message.py 16 Aug 2004 15:47:34 -0000 1.37 +++ Message.py 3 Oct 2004 03:16:18 -0000 1.38 @@ -1,5 +1,6 @@ # Copyright (C) 2001-2004 Python Software Foundation -# Author: barry@python.org (Barry Warsaw) +# Author: Barry Warsaw +# Contact: email-sig@python.org """Basic message object for the email package object model.""" @@ -69,6 +70,10 @@ def _unquotevalue(value): + # This is different than Utils.collapse_rfc2231_value() because it doesn't + # try to convert the value to a unicode. Message.get_param() and + # Message.get_params() are both currently defined to return the tuple in + # the face of RFC 2231 parameters. if isinstance(value, tuple): return value[0], value[1], Utils.unquote(value[2]) else: @@ -98,6 +103,7 @@ self._charset = None # Defaults for multipart messages self.preamble = self.epilogue = None + self.defects = [] # Default content type self._default_type = 'text/plain' @@ -124,9 +130,7 @@ def is_multipart(self): """Return True if the message consists of multiple parts.""" - if isinstance(self._payload, list): - return True - return False + return isinstance(self._payload, list) # # Unix From_ line @@ -140,26 +144,6 @@ # # Payload manipulation. # - def add_payload(self, payload): - """Add the given payload to the current payload. - - If the current payload is empty, then the current payload will be made - a scalar, set to the given value. - - Note: This method is deprecated. Use .attach() instead. - """ - warnings.warn('add_payload() is deprecated, use attach() instead.', - DeprecationWarning, 2) - if self._payload is None: - self._payload = payload - elif isinstance(self._payload, list): - self._payload.append(payload) - elif self.get_main_type() not in (None, 'multipart'): - raise Errors.MultipartConversionError( - 'Message main content type must be "multipart" or missing') - else: - self._payload = [self._payload, payload] - def attach(self, payload): """Add the given payload to the current payload. @@ -195,7 +179,7 @@ if i is None: payload = self._payload elif not isinstance(self._payload, list): - raise TypeError, 'Expected list, got %s' % type(self._payload) + raise TypeError('Expected list, got %s' % type(self._payload)) else: payload = self._payload[i] if decode: @@ -254,7 +238,7 @@ if isinstance(charset, str): charset = Charset.Charset(charset) if not isinstance(charset, Charset.Charset): - raise TypeError, charset + raise TypeError(charset) # BAW: should we accept strings that can serve as arguments to the # Charset constructor? self._charset = charset @@ -267,9 +251,9 @@ self.set_param('charset', charset.get_output_charset()) if not self.has_key('Content-Transfer-Encoding'): cte = charset.get_body_encoding() - if callable(cte): + try: cte(self) - else: + except TypeError: self.add_header('Content-Transfer-Encoding', cte) def get_charset(self): @@ -290,7 +274,7 @@ Return None if the header is missing instead of raising an exception. Note that if the header appeared multiple times, exactly which - occurrance gets returned is undefined. Use getall() to get all + occurrance gets returned is undefined. Use get_all() to get all the values matching a header field name. """ return self.get(name) @@ -320,7 +304,7 @@ def has_key(self, name): """Return true if the message contains the header.""" - missing = [] + missing = object() return self.get(name, missing) is not missing def keys(self): @@ -422,11 +406,10 @@ self._headers[i] = (k, _value) break else: - raise KeyError, _name + raise KeyError(_name) # - # These methods are silently deprecated in favor of get_content_type() and - # friends (see below). They will be noisily deprecated in email 3.0. + # Deprecated methods. These will be removed in email 3.1. # def get_type(self, failobj=None): @@ -436,7 +419,9 @@ string of the form `maintype/subtype'. If there was no Content-Type header in the message, failobj is returned (defaults to None). """ - missing = [] + warnings.warn('get_type() deprecated; use get_content_type()', + DeprecationWarning, 2) + missing = object() value = self.get('content-type', missing) if value is missing: return failobj @@ -444,7 +429,9 @@ def get_main_type(self, failobj=None): """Return the message's main content type if present.""" - missing = [] + warnings.warn('get_main_type() deprecated; use get_content_maintype()', + DeprecationWarning, 2) + missing = object() ctype = self.get_type(missing) if ctype is missing: return failobj @@ -454,7 +441,9 @@ def get_subtype(self, failobj=None): """Return the message's content subtype if present.""" - missing = [] + warnings.warn('get_subtype() deprecated; use get_content_subtype()', + DeprecationWarning, 2) + missing = object() ctype = self.get_type(missing) if ctype is missing: return failobj @@ -479,7 +468,7 @@ appears inside a multipart/digest container, in which case it would be message/rfc822. """ - missing = [] + missing = object() value = self.get('content-type', missing) if value is missing: # This should have no parameters @@ -529,7 +518,7 @@ def _get_params_preserve(self, failobj, header): # Like get_params() but preserves the quoting of values. BAW: # should this be part of the public interface? - missing = [] + missing = object() value = self.get(header, missing) if value is missing: return failobj @@ -560,7 +549,7 @@ header. Optional header is the header to search instead of Content-Type. If unquote is True, the value is unquoted. """ - missing = [] + missing = object() params = self._get_params_preserve(missing, header) if params is missing: return failobj @@ -713,17 +702,11 @@ The filename is extracted from the Content-Disposition header's `filename' parameter, and it is unquoted. """ - missing = [] + missing = object() filename = self.get_param('filename', missing, 'content-disposition') if filename is missing: return failobj - if isinstance(filename, tuple): - # It's an RFC 2231 encoded parameter - newvalue = _unquotevalue(filename) - return unicode(newvalue[2], newvalue[0] or 'us-ascii') - else: - newvalue = _unquotevalue(filename.strip()) - return newvalue + return Utils.collapse_rfc2231_value(filename).strip() def get_boundary(self, failobj=None): """Return the boundary associated with the payload if present. @@ -731,15 +714,11 @@ The boundary is extracted from the Content-Type header's `boundary' parameter, and it is unquoted. """ - missing = [] + missing = object() boundary = self.get_param('boundary', missing) if boundary is missing: return failobj - if isinstance(boundary, tuple): - # RFC 2231 encoded, so decode. It better end up as ascii - charset = boundary[0] or 'us-ascii' - return unicode(boundary[2], charset).encode('us-ascii') - return _unquotevalue(boundary.strip()) + return Utils.collapse_rfc2231_value(boundary).strip() def set_boundary(self, boundary): """Set the boundary parameter in Content-Type to 'boundary'. @@ -751,7 +730,7 @@ HeaderParseError is raised if the message has no Content-Type header. """ - missing = [] + missing = object() params = self._get_params_preserve(missing, 'content-type') if params is missing: # There was no Content-Type header, and we don't know what type @@ -793,7 +772,7 @@ Content-Type header, or if that header has no charset parameter, failobj is returned. """ - missing = [] + missing = object() charset = self.get_param('charset', missing) if charset is missing: return failobj Index: Parser.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Parser.py,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- Parser.py 9 May 2004 03:46:42 -0000 1.22 +++ Parser.py 3 Oct 2004 03:16:18 -0000 1.23 @@ -4,17 +4,15 @@ """A parser of RFC 2822 and MIME email messages.""" -import re +import warnings from cStringIO import StringIO from email.FeedParser import FeedParser from email.Message import Message -NLCRE = re.compile('\r\n|\r|\n') - class Parser: - def __init__(self, _class=Message, strict=False): + def __init__(self, *args, **kws): """Parser of RFC 2822 and MIME email messages. Creates an in-memory object tree representing the email message, which @@ -29,14 +27,28 @@ _class is the class to instantiate for new message objects when they must be created. This class must have a constructor that can take zero arguments. Default is Message.Message. - - Optional strict tells the parser to be strictly RFC compliant or to be - more forgiving in parsing of ill-formatted MIME documents. When - non-strict mode is used, the parser will try to make up for missing or - erroneous boundaries and other peculiarities seen in the wild. - Default is non-strict parsing. """ - self._class = _class + if len(args) >= 1: + if '_class' in kws: + raise TypeError("Multiple values for keyword arg '_class'") + kws['_class'] = args[0] + if len(args) == 2: + if 'strict' in kws: + raise TypeError("Multiple values for keyword arg 'strict'") + kws['strict'] = args[1] + if len(args) > 2: + raise TypeError('Too many arguments') + if '_class' in kws: + self._class = kws['_class'] + del kws['_class'] + else: + self._class = Message + if 'strict' in kws: + warnings.warn("'strict' argument is deprecated (and ignored)", + DeprecationWarning, 2) + del kws['strict'] + if kws: + raise TypeError('Unexpected keyword arguments') def parse(self, fp, headersonly=False): """Create a message structure from the data in a file. Index: Utils.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Utils.py,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- Utils.py 9 May 2004 03:50:04 -0000 1.26 +++ Utils.py 3 Oct 2004 03:16:18 -0000 1.27 @@ -1,5 +1,6 @@ # Copyright (C) 2001-2004 Python Software Foundation -# Author: barry@python.org (Barry Warsaw) +# Author: Barry Warsaw +# Contact: email-sig@python.org """Miscellaneous utilities.""" @@ -80,12 +81,6 @@ return '%s%s%s <%s>' % (quotes, name, quotes, address) return address -# For backwards compatibility -def dump_address_pair(pair): - warnings.warn('Use email.Utils.formataddr() instead', - DeprecationWarning, 2) - return formataddr(pair) - def getaddresses(fieldvalues): @@ -107,46 +102,6 @@ ''', re.VERBOSE | re.IGNORECASE) -def decode(s): - """Return a decoded string according to RFC 2047, as a unicode string. - - NOTE: This function is deprecated. Use Header.decode_header() instead. - """ - warnings.warn('Use Header.decode_header() instead.', DeprecationWarning, 2) - # Intra-package import here to avoid circular import problems. - from email.Header import decode_header - L = decode_header(s) - if not isinstance(L, list): - # s wasn't decoded - return s - - rtn = [] - for atom, charset in L: - if charset is None: - rtn.append(atom) - else: - # Convert the string to Unicode using the given encoding. Leave - # Unicode conversion errors to strict. - rtn.append(unicode(atom, charset)) - # Now that we've decoded everything, we just need to join all the parts - # together into the final string. - return UEMPTYSTRING.join(rtn) - - - -def encode(s, charset='iso-8859-1', encoding='q'): - """Encode a string according to RFC 2047.""" - warnings.warn('Use Header.Header.encode() instead.', DeprecationWarning, 2) - encoding = encoding.lower() - if encoding == 'q': - estr = _qencode(s) - elif encoding == 'b': - estr = _bencode(s) - else: - raise ValueError, 'Illegal encoding code: ' + encoding - return '=?%s?%s?%s?=' % (charset.lower(), encoding, estr) - - def formatdate(timeval=None, localtime=False): """Returns a date string as specified by RFC 2822, e.g.: @@ -179,7 +134,7 @@ sign = '-' else: sign = '+' - zone = '%s%02d%02d' % (sign, hours, minutes / 60) + zone = '%s%02d%02d' % (sign, hours, minutes // 60) else: now = time.gmtime(timeval) # Timezone offset is always -0000 @@ -314,3 +269,16 @@ new_params.append( (name, (charset, language, '"%s"' % quote(value)))) return new_params + +def collapse_rfc2231_value(value, errors='replace', + fallback_charset='us-ascii'): + if isinstance(value, tuple): + rawval = unquote(value[2]) + charset = value[0] or 'us-ascii' + try: + return unicode(rawval, charset, errors) + except LookupError: + # XXX charset is unknown to Python. + return unicode(rawval, fallback_charset, errors) + else: + return unquote(value) Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/__init__.py,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- __init__.py 9 May 2004 03:51:39 -0000 1.32 +++ __init__.py 3 Oct 2004 03:16:18 -0000 1.33 @@ -1,5 +1,6 @@ # Copyright (C) 2001-2004 Python Software Foundation -# Author: barry@python.org (Barry Warsaw) +# Author: Barry Warsaw +# Contact: email-sig@python.org """A package for parsing, handling, and generating email messages.""" @@ -33,25 +34,19 @@ # Some convenience routines. Don't import Parser and Message as side-effects # of importing email since those cascadingly import most of the rest of the # email package. -def message_from_string(s, _class=None, strict=False): +def message_from_string(s, *args, **kws): """Parse a string into a Message object model. Optional _class and strict are passed to the Parser constructor. """ from email.Parser import Parser - if _class is None: - from email.Message import Message - _class = Message - return Parser(_class, strict=strict).parsestr(s) + return Parser(*args, **kws).parsestr(s) -def message_from_file(fp, _class=None, strict=False): +def message_from_file(fp, *args, **kws): """Read a file and parse its contents into a Message object model. Optional _class and strict are passed to the Parser constructor. """ from email.Parser import Parser - if _class is None: - from email.Message import Message - _class = Message - return Parser(_class, strict=strict).parse(fp) + return Parser(*args, **kws).parse(fp) Index: _parseaddr.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/_parseaddr.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- _parseaddr.py 7 Aug 2004 16:38:39 -0000 1.9 +++ _parseaddr.py 3 Oct 2004 03:16:18 -0000 1.10 @@ -1,4 +1,5 @@ # Copyright (C) 2002-2004 Python Software Foundation +# Contact: email-sig@python.org """Email address parsing code. @@ -115,7 +116,7 @@ tzoffset = -tzoffset else: tzsign = 1 - tzoffset = tzsign * ( (tzoffset/100)*3600 + (tzoffset % 100)*60) + tzoffset = tzsign * ( (tzoffset//100)*3600 + (tzoffset % 100)*60) tuple = (yy, mm, dd, thh, tmm, tss, 0, 1, 0, tzoffset) return tuple Index: base64MIME.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/base64MIME.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- base64MIME.py 9 May 2004 03:53:50 -0000 1.7 +++ base64MIME.py 3 Oct 2004 03:16:18 -0000 1.8 @@ -1,5 +1,6 @@ -# Copyright (C) 2002 Python Software Foundation -# Author: che@debian.org (Ben Gertzfield) +# Copyright (C) 2002-2004 Python Software Foundation +# Author: Ben Gertzfield +# Contact: email-sig@python.org """Base64 content transfer encoding per RFCs 2045-2047. Index: quopriMIME.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/quopriMIME.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- quopriMIME.py 9 May 2004 03:55:11 -0000 1.6 +++ quopriMIME.py 3 Oct 2004 03:16:18 -0000 1.7 @@ -1,5 +1,6 @@ # Copyright (C) 2001-2004 Python Software Foundation -# Author: che@debian.org (Ben Gertzfield) +# Author: Ben Gertzfield +# Contact: email-sig@python.org """Quoted-printable content transfer encoding per RFCs 2045-2047. @@ -43,12 +44,12 @@ # Helpers def header_quopri_check(c): """Return True if the character should be escaped with header quopri.""" - return hqre.match(c) and True + return bool(hqre.match(c)) def body_quopri_check(c): """Return True if the character should be escaped with body quopri.""" - return bqre.match(c) and True + return bool(bqre.match(c)) def header_quopri_len(s): From bwarsaw at users.sourceforge.net Sun Oct 3 05:38:09 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 05:38:12 2004 Subject: [Python-checkins] python/dist/src/Lib/email Message.py,1.38,1.39 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3748 Modified Files: Message.py Log Message: as_string(): Indicate that this mangles From_ lines. Index: Message.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Message.py,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- Message.py 3 Oct 2004 03:16:18 -0000 1.38 +++ Message.py 3 Oct 2004 03:38:07 -0000 1.39 @@ -119,7 +119,8 @@ header. This is a convenience method and may not generate the message exactly - as you intend. For more flexibility, use the flatten() method of a + as you intend because by default it mangles lines that begin with + "From ". For more flexibility, use the flatten() method of a Generator instance. """ from email.Generator import Generator From bwarsaw at users.sourceforge.net Sun Oct 3 05:39:50 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 05:39:53 2004 Subject: [Python-checkins] python/dist/src/Doc/lib emailmessage.tex, 1.16, 1.17 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3989 Modified Files: emailmessage.tex Log Message: Add documentation about as_string() mangling From_ lines. Index: emailmessage.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailmessage.tex,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- emailmessage.tex 3 Oct 2004 03:16:17 -0000 1.16 +++ emailmessage.tex 3 Oct 2004 03:39:47 -0000 1.17 @@ -37,9 +37,10 @@ \var{unixfrom} is \code{True}, the envelope header is included in the returned string. \var{unixfrom} defaults to \code{False}. -Note that this method is provided as a convenience and may not always -format the message the way you want. For more flexibility, -instantiate a \class{Generator} instance and use its +Note that this method is provided as a convenience and may not always format +the message the way you want. For example, by default it mangels lines that +begin with \code{From }. For more flexibility, instantiate a +\class{Generator} instance and use its \method{flatten()} method directly. For example: \begin{verbatim} From bwarsaw at users.sourceforge.net Sun Oct 3 05:57:39 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 05:57:42 2004 Subject: [Python-checkins] python/dist/src/Doc/lib mimelib.tex,1.6,1.7 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7304 Modified Files: mimelib.tex Log Message: Updates for distutils package. Index: mimelib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/mimelib.tex,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- mimelib.tex 21 Mar 2003 21:14:48 -0000 1.6 +++ mimelib.tex 3 Oct 2004 03:57:37 -0000 1.7 @@ -9,7 +9,7 @@ \title{email Package Reference} \author{Barry Warsaw} -\authoraddress{\email{barry@zope.com}} +\authoraddress{\email{barry@python.org}} \date{\today} \release{2.5} % software release, not documentation @@ -38,19 +38,12 @@ parse, generate, and modify email messages, conforming to all the relevant email and MIME related RFCs. -This document describes the current version of the \module{email} -package, which is available to Python programmers in a number of ways. -Python 2.2.2 and 2.3 come with \module{email} version 2, while earlier -versions of Python 2.2.x come with \module{email} version 1. Python -2.1.x and earlier do not come with any version of the \module{email} -package. - -The \module{email} package is also available as a standalone distutils -package, and is compatible with Python 2.1.3 and beyond. Thus, if -you're using Python 2.1.3 you can download the standalone package and -install it in your \file{site-packages} directory. The standalone -\module{email} package is available on the -\ulink{SourceForge \module{mimelib} project}{http://mimelib.sf.net}. +This document describes version 3.0 of the \module{email} package, which is +distributed with Python 2.4 and is availble as a standalone distutils-based +package for use with Python 2.3. \module{email} 3.0 is not compatible with +Python versions earlier than 2.3. For more information about the +\module{email} package, including download links and mailing lists, see +\ulink{Python's email SIG}{http://www.python.org/sigs/email-sig}. The documentation that follows was written for the Python project, so if you're reading this as part of the standalone \module{email} @@ -58,28 +51,7 @@ \begin{itemize} \item Deprecation and ``version added'' notes are relative to the - Python version a feature was added or deprecated. To find out - what version of the \module{email} package a particular item was - added, changed, or removed, refer to the package's - \ulink{\file{NEWS} file}{http://cvs.sf.net/cgi-bin/viewcvs.cgi/mimelib/mimelib/NEWS?rev=1.36&content-type=text/vnd.viewcvs-markup}. - -\item The code samples are written with Python 2.2 in mind. For - Python 2.1.3, some adjustments are necessary. For example, this - code snippet; - - \begin{verbatim} - if isinstance(s, str): - # ... - \end{verbatim} - - would need to be written this way in Python 2.1.3: - - \begin{verbatim} - from types import StringType - # ... - if isinstance(s, StringType): - # ... - \end{verbatim} + Python version a feature was added or deprecated. \item If you're reading this documentation as part of the standalone \module{email} package, some of the internal links to From bwarsaw at users.sourceforge.net Sun Oct 3 05:58:03 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 05:58:06 2004 Subject: [Python-checkins] python/dist/src/Doc/lib mimelib.tex,1.7,1.8 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7421 Modified Files: mimelib.tex Log Message: Blarg, fix the versions. Index: mimelib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/mimelib.tex,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- mimelib.tex 3 Oct 2004 03:57:37 -0000 1.7 +++ mimelib.tex 3 Oct 2004 03:58:01 -0000 1.8 @@ -12,9 +12,9 @@ \authoraddress{\email{barry@python.org}} \date{\today} -\release{2.5} % software release, not documentation +\release{3.0} % software release, not documentation \setreleaseinfo{} % empty for final release -\setshortversion{2.5} % major.minor only for software +\setshortversion{3.0} % major.minor only for software \begin{document} From bwarsaw at users.sourceforge.net Sun Oct 3 06:02:45 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 3 06:02:47 2004 Subject: [Python-checkins] python/dist/src/Lib/email/test test_email_torture.py, 1.5, 1.6 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8612 Modified Files: test_email_torture.py Log Message: Fix test for FeedParser results. Index: test_email_torture.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/test/test_email_torture.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- test_email_torture.py 7 Oct 2002 17:27:55 -0000 1.5 +++ test_email_torture.py 3 Oct 2004 04:02:43 -0000 1.6 @@ -1,4 +1,4 @@ -# Copyright (C) 2002 Python Software Foundation +# Copyright (C) 2002-2004 Python Software Foundation # # A torture test of the email package. This should not be run as part of the # standard Python test suite since it requires several meg of email messages @@ -53,7 +53,7 @@ eq(type(payload), ListType) eq(len(payload), 12) eq(msg.preamble, None) - eq(msg.epilogue, '\n\n') + eq(msg.epilogue, '\n') # Probably the best way to verify the message is parsed correctly is to # dump its structure and compare it against the known structure. fp = StringIO() From aimacintyre at users.sourceforge.net Sun Oct 3 10:11:32 2004 From: aimacintyre at users.sourceforge.net (aimacintyre@users.sourceforge.net) Date: Sun Oct 3 10:11:37 2004 Subject: [Python-checkins] python/dist/src/PC/os2emx python24.def, NONE, 1.1 Makefile, 1.17, 1.18 config.c, 1.7, 1.8 python23.def, 1.8, NONE Message-ID: Update of /cvsroot/python/python/dist/src/PC/os2emx In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17611 Modified Files: Makefile config.c Added Files: python24.def Removed Files: python23.def Log Message: bring modules up to date, correct .DEF file version --- NEW FILE: python24.def --- LIBRARY python24 INITINSTANCE TERMINSTANCE DESCRIPTION "Python 2.4 Core DLL" PROTMODE DATA MULTIPLE NONSHARED EXPORTS ; From python24_s.lib(config) "_PyImport_Inittab" ; From python24_s.lib(dlfcn) ; "dlopen" ; "dlsym" ; "dlclose" ; "dlerror" ; From python24_s.lib(getpathp) "Py_GetProgramFullPath" "Py_GetPrefix" "Py_GetExecPrefix" [...1148 lines suppressed...] ; From python24_s.lib(termios) ; "inittermios" ; From python24_s.lib(timemodule) ; "inittime" "_PyTime_DoubleToTimet" ; "inittimezone" ; From python24_s.lib(timingmodule) ; "inittiming" ; From python24_s.lib(_weakref) ; "init_weakref" ; From python24_s.lib(xxsubtype) ; "initxxsubtype" ; From python24_s.lib(zipimport) ; "initzipimport" Index: Makefile =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/os2emx/Makefile,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- Makefile 7 Jul 2004 13:55:24 -0000 1.17 +++ Makefile 3 Oct 2004 08:11:29 -0000 1.18 @@ -40,8 +40,6 @@ HAVE_UFC= no # Do you have the Tcl/Tk library installed? HAVE_TCLTK= no -# Do you have the GNU multiprecision library installed? -HAVE_GMPZ= no # Do you have the GNU readline library installed? # NOTE: I'm using a modified version of Kai Uwe Rommel's port that # - is compiled with multithreading enabled @@ -251,7 +249,6 @@ DESCRIPTION.zlib$(MODULE.EXT)= Python Extension DLL for accessing the InfoZip compression library DESCRIPTION.crypt$(MODULE.EXT)= Python Extension DLL implementing the crypt$(BRO)$(BRC) function DESCRIPTION._tkinter$(MODULE.EXT)= Python Extension DLL for access to Tcl/Tk Environment -DESCRIPTION.mpz$(MODULE.EXT)= Python Extension DLL for access to GNU multi-precision library DESCRIPTION.readline$(MODULE.EXT)= Python Extension DLL for access to GNU ReadLine library DESCRIPTION.bsddb185$(MODULE.EXT)= Python Extension DLL for access to BSD DB (v1.85) library DESCRIPTION._curses$(MODLIB.EXT)= Python Extension DLL for access to ncurses library @@ -301,7 +298,6 @@ Modules/timemodule.c \ Modules/timingmodule.c \ Modules/_weakref.c \ - Modules/xreadlinesmodule.c \ Modules/xxsubtype.c \ Modules/zipimport.c) SRC.PARSE1= $(addprefix $(TOP), \ @@ -422,7 +418,6 @@ fpetest \ parser \ pwd \ - rotor \ select # Python modules to be dynamically loaded that need explicit build rules @@ -449,9 +444,6 @@ CFLAGS+= -DHAS_DIRENT -I/TclTk80/include TK_LIBS+= -L/TclTk80/lib -ltcl80 -ltk80 endif -ifeq ($(HAVE_GMPZ),yes) - HARDEXTMODULES+= mpz -endif ifeq ($(HAVE_GREADLINE),yes) HARDEXTMODULES+= readline endif @@ -635,8 +627,6 @@ gdbm$(MODULE.EXT): $(OUT)gdbmmodule$O $(OUT)gdbm_m.def $(PYTHON.IMPLIB) $(LD) $(LDFLAGS.DLL) -o $@ $(^^) $(L^) $(LIBS) -lgdbm -mpz$(MODULE.EXT): $(OUT)mpzmodule$O $(OUT)mpz_m.def $(PYTHON.IMPLIB) - $(LD) $(LDFLAGS.DLL) -o $@ $(^^) $(L^) $(LIBS) -lgmp # Expat is now distributed with Python, so use the included version $(OUT)pyexpat$O: ../../Modules/pyexpat.c Index: config.c =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/os2emx/config.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- config.c 7 Jul 2004 13:55:25 -0000 1.7 +++ config.c 3 Oct 2004 08:11:30 -0000 1.8 @@ -72,7 +72,6 @@ extern void inittermios(); extern void inittime(); extern void inittiming(); -extern void initxreadlines(); extern void initxxsubtype(); extern void initzipimport(); #if !HAVE_DYNAMIC_LOADING @@ -86,7 +85,6 @@ extern void initfpetest(); extern void initparser(); extern void initpwd(); -extern void initrotor(); extern void initunicodedata(); extern void initzlib(); #ifdef USE_SOCKET @@ -138,7 +136,6 @@ {"termios", inittermios}, {"time", inittime}, {"timing", inittiming}, - {"xreadlines", initxreadlines}, {"xxsubtype", initxxsubtype}, {"zipimport", initzipimport}, #if !HAVE_DYNAMIC_LOADING @@ -152,7 +149,6 @@ {"fpetest", initfpetest}, {"parser", initparser}, {"pwd", initpwd}, - {"rotor", initrotor}, {"unicodedata", initunicodedata}, {"zlib", initzlib}, #ifdef USE_SOCKET --- python23.def DELETED --- From aimacintyre at users.sourceforge.net Sun Oct 3 10:26:39 2004 From: aimacintyre at users.sourceforge.net (aimacintyre@users.sourceforge.net) Date: Sun Oct 3 10:26:42 2004 Subject: [Python-checkins] python/dist/src/PC/os2emx README.os2emx,1.9,1.10 Message-ID: Update of /cvsroot/python/python/dist/src/PC/os2emx In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20622 Modified Files: README.os2emx Log Message: note module removals, update on BitTorrent issue Index: README.os2emx =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/os2emx/README.os2emx,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- README.os2emx 11 Apr 2004 12:05:28 -0000 1.9 +++ README.os2emx 3 Oct 2004 08:26:36 -0000 1.10 @@ -26,8 +26,8 @@ Eberhard Mattes' porting changes to BSD DB v1.85 are also GPL'ed (BSD DB itself is BSD Licenced). ncurses and expat appear to be covered by MIT style licences - please refer to the source distributions for more detail. -zlib is distributable under a very free license. GNU MP and GNU UFC are -under the GNU LGPL (see file COPYING.lib). +zlib is distributable under a very free license. GNU UFC is under the +GNU LGPL (see file COPYING.lib). My patches to the Python-2.x source distributions, and any other packages used in this port, are placed in the public domain. @@ -77,7 +77,6 @@ - GNU GDBM (Kai Uwe Rommel's port available from Hobbes or LEO, v1.7.3) - zlib (derived from Hung-Chi Chu's port of v1.1.3, v1.1.4) - expat (distributed with Python, v1.95.6) -- GNU MP (Peter Meerwald's port available from LEO, v2.0.2) - GNU UFC (Kai Uwe Rommel's port available from LEO, v2.0.4) @@ -125,8 +124,8 @@ ported to OS/2, I've built and included them. These include ncurses (_curses, _curses_panel), BSD DB (bsddb185), -GNU GDBM (gdbm, dbm), zlib (zlib), GNU Readline (readline), GNU MP (mpz) -and GNU UFC (crypt). +GNU GDBM (gdbm, dbm), zlib (zlib), GNU Readline (readline), and GNU UFC +(crypt). Expat is now included in the Python release sourceball, and the pyexpat module is always built. @@ -326,7 +325,6 @@ zlib (1.1.4) HAVE_ZLIB GNU UltraFast Crypt HAVE_UFC Tcl/Tk HAVE_TCLTK (not known to work) - GNU MP HAVE_GMPZ GNU Readline HAVE_GREADLINE BSD DB (v1.85) HAVE_BSDDB ncurses HAVE_NCURSES @@ -625,8 +623,9 @@ appreciate any success or failure reports with BitTorrent, though I've regretfully recommended that the person who reported the failure take this up with eCS support. Since this report, I have received a -followup which suggests that the problem may have been a buggy network -card driver. I think it suffices to say that BitTorrent is a fair stress +followup which suggests that the problem may be addressed by TCP/IP +fixes (IC35005+PJ29457, contained in NEWSTACK.ZIP in the Hobbes +archive). I think it suffices to say that BitTorrent is a fair stress test of a system's networking capability. 25. In the absence of an EMX implementation of the link() function, I've @@ -649,6 +648,9 @@ - unlike Unix, the socket endpoints don't exist in the filesystem; - by default, sockets are in binary mode. +27. As of Python 2.4, the mpz, rotor and xreadlines modules have been +dropped from the Python source tree. + ... probably other issues that I've not encountered, or don't remember :-( If you encounter other difficulties with this port, which can be @@ -688,4 +690,4 @@ E-mail: andymac@bullseye.apana.org.au, or andymac@pcug.org.au Web: http://www.andymac.org/ -11 April, 2004. +3 October, 2004. From aimacintyre at users.sourceforge.net Sun Oct 3 10:29:57 2004 From: aimacintyre at users.sourceforge.net (aimacintyre@users.sourceforge.net) Date: Sun Oct 3 10:30:01 2004 Subject: [Python-checkins] python/dist/src/PC/os2vacpp config.c,1.9,1.10 Message-ID: Update of /cvsroot/python/python/dist/src/PC/os2vacpp In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21032 Modified Files: config.c Log Message: remove rotor module Index: config.c =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/os2vacpp/config.c,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- config.c 16 Jun 2002 01:37:36 -0000 1.9 +++ config.c 3 Oct 2004 08:29:55 -0000 1.10 @@ -29,7 +29,6 @@ extern void initposix(void); extern void initregex(void); extern void initrgbimg(void); -extern void initrotor(void); extern void initsignal(void); extern void initselect(void); extern void init_socket(void); @@ -73,7 +72,6 @@ {"operator", initoperator}, {"regex", initregex}, // {"rgbimg", initrgbimg}, -// {"rotor", initrotor}, {"signal", initsignal}, #ifdef USE_SOCKET {"_socket", init_socket}, From loewis at users.sourceforge.net Sun Oct 3 10:51:38 2004 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun Oct 3 10:51:41 2004 Subject: [Python-checkins] python/dist/src/Python dynload_shlib.c,2.16,2.17 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24858 Modified Files: dynload_shlib.c Log Message: Print verbose messages to stderr. Fixes #1036752. Index: dynload_shlib.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/dynload_shlib.c,v retrieving revision 2.16 retrieving revision 2.17 diff -u -d -r2.16 -r2.17 --- dynload_shlib.c 25 Mar 2004 02:16:23 -0000 2.16 +++ dynload_shlib.c 3 Oct 2004 08:51:35 -0000 2.17 @@ -113,7 +113,8 @@ #endif if (Py_VerboseFlag) - printf("dlopen(\"%s\", %x);\n", pathname, dlopenflags); + PySys_WriteStderr("dlopen(\"%s\", %x);\n", pathname, + dlopenflags); #ifdef __VMS /* VMS currently don't allow a pathname, use a logical name instead */ From mwh at users.sourceforge.net Sun Oct 3 11:41:28 2004 From: mwh at users.sourceforge.net (mwh@users.sourceforge.net) Date: Sun Oct 3 11:41:31 2004 Subject: [Python-checkins] python/dist/src/Doc/lib emailmessage.tex, 1.17, 1.18 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1554 Modified Files: emailmessage.tex Log Message: typo Index: emailmessage.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailmessage.tex,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- emailmessage.tex 3 Oct 2004 03:39:47 -0000 1.17 +++ emailmessage.tex 3 Oct 2004 09:41:26 -0000 1.18 @@ -38,7 +38,7 @@ returned string. \var{unixfrom} defaults to \code{False}. Note that this method is provided as a convenience and may not always format -the message the way you want. For example, by default it mangels lines that +the message the way you want. For example, by default it mangles lines that begin with \code{From }. For more flexibility, instantiate a \class{Generator} instance and use its \method{flatten()} method directly. For example: From goodger at users.sourceforge.net Sun Oct 3 17:40:27 2004 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sun Oct 3 17:40:29 2004 Subject: [Python-checkins] python/dist/src/Lib ConfigParser.py,1.66,1.67 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20319/Lib Modified Files: ConfigParser.py Log Message: SF bug #1017864: ConfigParser now correctly handles default keys, processing them with ``ConfigParser.optionxform`` when supplied, consistent with the handling of config file entries and runtime-set options. Index: ConfigParser.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/ConfigParser.py,v retrieving revision 1.66 retrieving revision 1.67 diff -u -d -r1.66 -r1.67 --- ConfigParser.py 18 May 2004 04:24:02 -0000 1.66 +++ ConfigParser.py 3 Oct 2004 15:40:24 -0000 1.67 @@ -202,10 +202,10 @@ class RawConfigParser: def __init__(self, defaults=None): self._sections = {} - if defaults is None: - self._defaults = {} - else: - self._defaults = defaults + self._defaults = {} + if defaults: + for key, value in defaults.items(): + self._defaults[self.optionxform(key)] = value def defaults(self): return self._defaults @@ -511,8 +511,9 @@ if section != DEFAULTSECT: raise NoSectionError(section) # Update with the entry specific variables - if vars is not None: - d.update(vars) + if vars: + for key, value in vars.items(): + d[self.optionxform(key)] = value option = self.optionxform(option) try: value = d[option] @@ -544,7 +545,8 @@ raise NoSectionError(section) # Update with the entry specific variables if vars: - d.update(vars) + for key, value in vars.items(): + d[self.optionxform(key)] = value options = d.keys() if "__name__" in options: options.remove("__name__") From goodger at users.sourceforge.net Sun Oct 3 17:40:27 2004 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sun Oct 3 17:40:31 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_cfgparser.py, 1.23, 1.24 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20319/Lib/test Modified Files: test_cfgparser.py Log Message: SF bug #1017864: ConfigParser now correctly handles default keys, processing them with ``ConfigParser.optionxform`` when supplied, consistent with the handling of config file entries and runtime-set options. Index: test_cfgparser.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_cfgparser.py,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- test_cfgparser.py 18 May 2004 04:24:02 -0000 1.23 +++ test_cfgparser.py 3 Oct 2004 15:40:25 -0000 1.24 @@ -115,6 +115,16 @@ self.failUnless(cf.has_option("section", "Key")) + def test_default_case_sensitivity(self): + cf = self.newconfig({"foo": "Bar"}) + self.assertEqual( + cf.get("DEFAULT", "Foo"), "Bar", + "could not locate option, expecting case-insensitive option names") + cf = self.newconfig({"Foo": "Bar"}) + self.assertEqual( + cf.get("DEFAULT", "Foo"), "Bar", + "could not locate option, expecting case-insensitive defaults") + def test_parse_errors(self): self.newconfig() self.parse_error(ConfigParser.ParsingError, From goodger at users.sourceforge.net Sun Oct 3 17:40:27 2004 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sun Oct 3 17:40:31 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1148,1.1149 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20319/Misc Modified Files: NEWS Log Message: SF bug #1017864: ConfigParser now correctly handles default keys, processing them with ``ConfigParser.optionxform`` when supplied, consistent with the handling of config file entries and runtime-set options. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1148 retrieving revision 1.1149 diff -u -d -r1.1148 -r1.1149 --- NEWS 3 Oct 2004 03:16:19 -0000 1.1148 +++ NEWS 3 Oct 2004 15:40:25 -0000 1.1149 @@ -94,6 +94,11 @@ - httplib now handles ipv6 address/port pairs. +- SF bug #1017864: ConfigParser now correctly handles default keys, + processing them with ``ConfigParser.optionxform`` when supplied, + consistent with the handling of config file entries and runtime-set + options. + Build ----- From goodger at users.sourceforge.net Sun Oct 3 17:55:11 2004 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sun Oct 3 17:55:14 2004 Subject: [Python-checkins] python/dist/src/Lib ConfigParser.py,1.67,1.68 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23768/Lib Modified Files: ConfigParser.py Log Message: SF bug #997050: Document, test, & check for non-string values in ConfigParser. Moved the new string-only restriction added in rev. 1.65 to the SafeConfigParser class, leaving existing ConfigParser & RawConfigParser behavior alone, and documented the conditions under which non-string values work. Index: ConfigParser.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/ConfigParser.py,v retrieving revision 1.67 retrieving revision 1.68 diff -u -d -r1.67 -r1.68 --- ConfigParser.py 3 Oct 2004 15:40:24 -0000 1.67 +++ ConfigParser.py 3 Oct 2004 15:55:09 -0000 1.68 @@ -92,7 +92,8 @@ __all__ = ["NoSectionError", "DuplicateSectionError", "NoOptionError", "InterpolationError", "InterpolationDepthError", "InterpolationSyntaxError", "ParsingError", - "MissingSectionHeaderError", "ConfigParser", "SafeConfigParser", + "MissingSectionHeaderError", + "ConfigParser", "SafeConfigParser", "RawConfigParser", "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"] DEFAULTSECT = "DEFAULT" @@ -348,8 +349,6 @@ def set(self, section, option, value): """Set an option.""" - if not isinstance(value, basestring): - raise TypeError("option values must be strings") if not section or section == DEFAULTSECT: sectdict = self._defaults else: @@ -633,3 +632,9 @@ raise InterpolationSyntaxError( option, section, "'%%' must be followed by '%%' or '(', found: %r" % (rest,)) + + def set(self, section, option, value): + """Set an option. Extend ConfigParser.set: check for string values.""" + if not isinstance(value, basestring): + raise TypeError("option values must be strings") + ConfigParser.set(self, section, option, value) From goodger at users.sourceforge.net Sun Oct 3 17:55:12 2004 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sun Oct 3 17:55:17 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_cfgparser.py, 1.24, 1.25 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23768/Lib/test Modified Files: test_cfgparser.py Log Message: SF bug #997050: Document, test, & check for non-string values in ConfigParser. Moved the new string-only restriction added in rev. 1.65 to the SafeConfigParser class, leaving existing ConfigParser & RawConfigParser behavior alone, and documented the conditions under which non-string values work. Index: test_cfgparser.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_cfgparser.py,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- test_cfgparser.py 3 Oct 2004 15:40:25 -0000 1.24 +++ test_cfgparser.py 3 Oct 2004 15:55:09 -0000 1.25 @@ -240,18 +240,6 @@ cf.set("sect", "option1", unicode("splat")) cf.set("sect", "option2", unicode("splat")) - def test_set_nonstring_types(self): - cf = self.fromstring("[sect]\n" - "option1=foo\n") - # Check that we get a TypeError when setting non-string values - # in an existing section: - self.assertRaises(TypeError, cf.set, "sect", "option1", 1) - self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0) - self.assertRaises(TypeError, cf.set, "sect", "option1", object()) - self.assertRaises(TypeError, cf.set, "sect", "option2", 1) - self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0) - self.assertRaises(TypeError, cf.set, "sect", "option2", object()) - def test_read_returns_file_list(self): file1 = test_support.findfile("cfgparser.1") # check when we pass a mix of readable and non-readable files: @@ -344,6 +332,27 @@ ('key', '|value|'), ('name', 'value')]) + def test_set_nonstring_types(self): + cf = self.newconfig() + cf.add_section('non-string') + cf.set('non-string', 'int', 1) + cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%(']) + cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1, + '%(list)': '%(list)'}) + cf.set('non-string', 'string_with_interpolation', '%(list)s') + self.assertEqual(cf.get('non-string', 'int', raw=True), 1) + self.assertRaises(TypeError, cf.get, 'non-string', 'int') + self.assertEqual(cf.get('non-string', 'list', raw=True), + [0, 1, 1, 2, 3, 5, 8, 13, '%(']) + self.assertRaises(TypeError, cf.get, 'non-string', 'list') + self.assertEqual(cf.get('non-string', 'dict', raw=True), + {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'}) + self.assertRaises(TypeError, cf.get, 'non-string', 'dict') + self.assertEqual(cf.get('non-string', 'string_with_interpolation', + raw=True), '%(list)s') + self.assertRaises(ValueError, cf.get, 'non-string', + 'string_with_interpolation', raw=False) + class RawConfigParserTestCase(TestCaseBase): config_class = ConfigParser.RawConfigParser @@ -368,6 +377,17 @@ ('key', '|%(name)s|'), ('name', 'value')]) + def test_set_nonstring_types(self): + cf = self.newconfig() + cf.add_section('non-string') + cf.set('non-string', 'int', 1) + cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13]) + cf.set('non-string', 'dict', {'pi': 3.14159}) + self.assertEqual(cf.get('non-string', 'int'), 1) + self.assertEqual(cf.get('non-string', 'list'), + [0, 1, 1, 2, 3, 5, 8, 13]) + self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159}) + class SafeConfigParserTestCase(ConfigParserTestCase): config_class = ConfigParser.SafeConfigParser @@ -382,6 +402,18 @@ self.assertEqual(cf.get("section", "ok"), "xxx/%s") self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s") + def test_set_nonstring_types(self): + cf = self.fromstring("[sect]\n" + "option1=foo\n") + # Check that we get a TypeError when setting non-string values + # in an existing section: + self.assertRaises(TypeError, cf.set, "sect", "option1", 1) + self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0) + self.assertRaises(TypeError, cf.set, "sect", "option1", object()) + self.assertRaises(TypeError, cf.set, "sect", "option2", 1) + self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0) + self.assertRaises(TypeError, cf.set, "sect", "option2", object()) + def test_main(): test_support.run_unittest( From goodger at users.sourceforge.net Sun Oct 3 17:55:12 2004 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sun Oct 3 17:55:17 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libcfgparser.tex, 1.38, 1.39 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23768/Doc/lib Modified Files: libcfgparser.tex Log Message: SF bug #997050: Document, test, & check for non-string values in ConfigParser. Moved the new string-only restriction added in rev. 1.65 to the SafeConfigParser class, leaving existing ConfigParser & RawConfigParser behavior alone, and documented the conditions under which non-string values work. Index: libcfgparser.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcfgparser.tex,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- libcfgparser.tex 18 May 2004 04:24:02 -0000 1.38 +++ libcfgparser.tex 3 Oct 2004 15:55:09 -0000 1.39 @@ -238,10 +238,12 @@ \end{methoddesc} \begin{methoddesc}{set}{section, option, value} -If the given section exists, set the given option to the specified value; -otherwise raise \exception{NoSectionError}. \var{value} must be a -string (\class{str} or \class{unicode}); if not, \exception{TypeError} -is raised. +If the given section exists, set the given option to the specified +value; otherwise raise \exception{NoSectionError}. While it is +possible to use \class{RawConfigParser} (or \class{ConfigParser} with +\var{raw} parameters set to true) for \emph{internal} storage of +non-string values, full functionality (including interpolation and +output to files) can only be achieved using string values. \versionadded{1.6} \end{methoddesc} @@ -281,8 +283,6 @@ The \class{ConfigParser} class extends some methods of the \class{RawConfigParser} interface, adding some optional arguments. -The \class{SafeConfigParser} class implements the same extended -interface. \begin{methoddesc}{get}{section, option\optional{, raw\optional{, vars}}} Get an \var{option} value for the named \var{section}. All the @@ -297,3 +297,17 @@ same meaning as for the \method{get()} method. \versionadded{2.3} \end{methoddesc} + + +\subsection{SafeConfigParser Objects \label{SafeConfigParser-objects}} + +The \class{SafeConfigParser} class implements the same extended +interface as \class{ConfigParser}, with the following addition: + +\begin{methoddesc}{set}{section, option, value} +If the given section exists, set the given option to the specified +value; otherwise raise \exception{NoSectionError}. \var{value} must +be a string (\class{str} or \class{unicode}); if not, +\exception{TypeError} is raised. +\versionadded{2.4} +\end{methoddesc} From goodger at users.sourceforge.net Sun Oct 3 17:55:12 2004 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sun Oct 3 17:55:17 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1149,1.1150 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23768/Misc Modified Files: NEWS Log Message: SF bug #997050: Document, test, & check for non-string values in ConfigParser. Moved the new string-only restriction added in rev. 1.65 to the SafeConfigParser class, leaving existing ConfigParser & RawConfigParser behavior alone, and documented the conditions under which non-string values work. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1149 retrieving revision 1.1150 diff -u -d -r1.1149 -r1.1150 --- NEWS 3 Oct 2004 15:40:25 -0000 1.1149 +++ NEWS 3 Oct 2004 15:55:09 -0000 1.1150 @@ -99,6 +99,12 @@ consistent with the handling of config file entries and runtime-set options. +- SF bug #997050: Document, test, & check for non-string values in + ConfigParser. Moved the new string-only restriction added in + rev. 1.65 to the SafeConfigParser class, leaving existing + ConfigParser & RawConfigParser behavior alone, and documented the + conditions under which non-string values work. + Build ----- From jvr at users.sourceforge.net Sun Oct 3 18:27:11 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Sun Oct 3 18:27:13 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1150,1.1151 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv467 Modified Files: NEWS Log Message: added plistlib news item Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1150 retrieving revision 1.1151 diff -u -d -r1.1150 -r1.1151 --- NEWS 3 Oct 2004 15:55:09 -0000 1.1150 +++ NEWS 3 Oct 2004 16:27:09 -0000 1.1151 @@ -145,7 +145,9 @@ Mac --- -... +- ``plistlib`` now supports non-dict root objects. There is also a new + interface for reading and writing plist files: ``readPlist(pathOrFile)`` + and ``writePlist(rootObject, pathOrFile)`` New platforms ------------- From tim_one at users.sourceforge.net Sun Oct 3 20:35:21 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 3 20:35:24 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_cfgparser.py, 1.25, 1.26 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29991/Lib/test Modified Files: test_cfgparser.py Log Message: Whitespace normalization. Index: test_cfgparser.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_cfgparser.py,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- test_cfgparser.py 3 Oct 2004 15:55:09 -0000 1.25 +++ test_cfgparser.py 3 Oct 2004 18:35:19 -0000 1.26 @@ -387,7 +387,7 @@ self.assertEqual(cf.get('non-string', 'list'), [0, 1, 1, 2, 3, 5, 8, 13]) self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159}) - + class SafeConfigParserTestCase(ConfigParserTestCase): config_class = ConfigParser.SafeConfigParser From tim_one at users.sourceforge.net Sun Oct 3 21:03:22 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 3 21:03:25 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1151,1.1152 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3376/Misc Modified Files: NEWS Log Message: Read the text files to be compared in universal-newline mode. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1151 retrieving revision 1.1152 diff -u -d -r1.1151 -r1.1152 --- NEWS 3 Oct 2004 16:27:09 -0000 1.1151 +++ NEWS 3 Oct 2004 19:03:19 -0000 1.1152 @@ -157,7 +157,11 @@ Tools/Demos ----------- -... +- The text file comparison scripts ``ndiff.py`` and ``diff.py`` now + read the input files in universal-newline mode. This spares them + from consuming a great deal of time to deduce the useless result that, + e.g., a file with Windows line ends and a file with Linux line ends + have no lines in common. What's New in Python 2.4 alpha 3? From tim_one at users.sourceforge.net Sun Oct 3 21:03:22 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 3 21:03:25 2004 Subject: [Python-checkins] python/dist/src/Tools/scripts diff.py, 1.4, 1.5 ndiff.py, 1.13, 1.14 Message-ID: Update of /cvsroot/python/python/dist/src/Tools/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3376/Tools/scripts Modified Files: diff.py ndiff.py Log Message: Read the text files to be compared in universal-newline mode. Index: diff.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Tools/scripts/diff.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- diff.py 29 Aug 2004 16:34:40 -0000 1.4 +++ diff.py 3 Oct 2004 19:03:19 -0000 1.5 @@ -31,8 +31,8 @@ fromdate = time.ctime(os.stat(fromfile).st_mtime) todate = time.ctime(os.stat(tofile).st_mtime) - fromlines = open(fromfile).readlines() - tolines = open(tofile).readlines() + fromlines = open(fromfile, 'U').readlines() + tolines = open(tofile, 'U').readlines() if options.u: diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n) Index: ndiff.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Tools/scripts/ndiff.py,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- ndiff.py 13 May 2003 17:56:07 -0000 1.13 +++ ndiff.py 3 Oct 2004 19:03:19 -0000 1.14 @@ -60,7 +60,7 @@ # couldn't be opened def fopen(fname): try: - return open(fname, 'r') + return open(fname, 'U') except IOError, detail: return fail("couldn't open " + fname + ": " + str(detail)) From vsajip at users.sourceforge.net Sun Oct 3 21:10:08 2004 From: vsajip at users.sourceforge.net (vsajip@users.sourceforge.net) Date: Sun Oct 3 21:10:11 2004 Subject: [Python-checkins] python/dist/src/Doc/lib liblogging.tex,1.26,1.27 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5047/lib Modified Files: liblogging.tex Log Message: Clarified documentation about exc_info keyword parameter Index: liblogging.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liblogging.tex,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- liblogging.tex 24 Sep 2004 11:46:44 -0000 1.26 +++ liblogging.tex 3 Oct 2004 19:10:05 -0000 1.27 @@ -162,8 +162,10 @@ The \var{msg} is the message format string, and the \var{args} are the arguments which are merged into \var{msg}. The only keyword argument in \var{kwargs} which is inspected is \var{exc_info} which, if it does not -evaluate as false, causes exception information (via a call to -\function{sys.exc_info()}) to be added to the logging message. +evaluate as false, causes exception information to be added to the logging +message. If an exception tuple (in the format returned by +\function{sys.exc_info()}) is provided, it is used; otherwise, +\function{sys.exc_info()} is called to get the exception information. \end{funcdesc} \begin{funcdesc}{info}{msg\optional{, *args\optional{, **kwargs}}} @@ -310,8 +312,10 @@ The \var{msg} is the message format string, and the \var{args} are the arguments which are merged into \var{msg}. The only keyword argument in \var{kwargs} which is inspected is \var{exc_info} which, if it does not -evaluate as false, causes exception information (via a call to -\function{sys.exc_info()}) to be added to the logging message. +evaluate as false, causes exception information to be added to the logging +message. If an exception tuple (as provided by \function{sys.exc_info()}) +is provided, it is used; otherwise, \function{sys.exc_info()} is called +to get the exception information. \end{methoddesc} \begin{methoddesc}{info}{msg\optional{, *args\optional{, **kwargs}}} From vsajip at users.sourceforge.net Sun Oct 3 21:10:55 2004 From: vsajip at users.sourceforge.net (vsajip@users.sourceforge.net) Date: Sun Oct 3 21:10:57 2004 Subject: [Python-checkins] python/dist/src/Lib/logging __init__.py, 1.21, 1.22 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/logging In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5228 Modified Files: __init__.py Log Message: Version number updated to 0.4.9.5 Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/logging/__init__.py,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- __init__.py 24 Sep 2004 11:45:52 -0000 1.21 +++ __init__.py 3 Oct 2004 19:10:53 -0000 1.22 @@ -36,8 +36,8 @@ __author__ = "Vinay Sajip " __status__ = "beta" -__version__ = "0.4.9.4" -__date__ = "22 September 2004" +__version__ = "0.4.9.5" +__date__ = "02 October 2004" #--------------------------------------------------------------------------- # Miscellaneous module data From vsajip at users.sourceforge.net Sun Oct 3 21:12:09 2004 From: vsajip at users.sourceforge.net (vsajip@users.sourceforge.net) Date: Sun Oct 3 21:12:12 2004 Subject: [Python-checkins] python/dist/src/Lib/logging handlers.py, 1.18, 1.19 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/logging In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5624 Modified Files: handlers.py Log Message: Changes made to maintain 1.5.2 compatibility. Index: handlers.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/logging/handlers.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- handlers.py 24 Aug 2004 09:36:23 -0000 1.18 +++ handlers.py 3 Oct 2004 19:12:07 -0000 1.19 @@ -182,7 +182,7 @@ else: raise ValueError("Invalid rollover interval specified: %s" % self.when) - self.interval *= interval # multiply by units requested + self.interval = self.interval * interval # multiply by units requested self.rolloverAt = currentTime + self.interval # If we are rolling over at midnight or weekly, then the interval is already known. @@ -200,8 +200,8 @@ currentSecond = t[5] # r is the number of seconds left between now and midnight r = (24 - currentHour) * 60 * 60 # number of hours in seconds - r += (59 - currentMinute) * 60 # plus the number of minutes (in secs) - r += (59 - currentSecond) # plus the number of seconds + r = r + (59 - currentMinute) * 60 # plus the number of minutes (in secs) + r = r + (59 - currentSecond) # plus the number of seconds self.rolloverAt = currentTime + r # If we are rolling over on a certain day, add in the number of days until # the next rollover, but offset by 1 since we just calculated the time @@ -219,10 +219,10 @@ day = t[6] # 0 is Monday if day > self.dayOfWeek: daysToWait = (day - self.dayOfWeek) - 1 - self.rolloverAt += (daysToWait * (60 * 60 * 24)) + self.rolloverAt = self.rolloverAt + (daysToWait * (60 * 60 * 24)) if day < self.dayOfWeek: daysToWait = (6 - self.dayOfWeek) + day - self.rolloverAt += (daysToWait * (60 * 60 * 24)) + self.rolloverAt = self.rolloverAt + (daysToWait * (60 * 60 * 24)) #print "Will rollover at %d, %d seconds from now" % (self.rolloverAt, self.rolloverAt - currentTime) @@ -656,6 +656,24 @@ """ return self.subject + weekdayname = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'] + + monthname = [None, + 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + + def date_time(self): + """ + Return the current date and time formatted for a MIME header. + Needed for Python 1.5.2 (no email package available) + """ + year, month, day, hh, mm, ss, wd, y, z = time.gmtime(time.time()) + s = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % ( + self.weekdayname[wd], + day, self.monthname[month], year, + hh, mm, ss) + return s + def emit(self, record): """ Emit a record. @@ -664,7 +682,10 @@ """ try: import smtplib - from email.Utils import formatdate + try: + from email.Utils import formatdate + except: + formatdate = self.date_time port = self.mailport if not port: port = smtplib.SMTP_PORT From bcannon at users.sourceforge.net Mon Oct 4 01:21:47 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 4 01:21:49 2004 Subject: [Python-checkins] python/dist/src/Lib SimpleXMLRPCServer.py, 1.8, 1.9 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1716/Lib Modified Files: SimpleXMLRPCServer.py Log Message: Fix a small typo in the docstring for system_methodSignature . Closes bug #1038935. Thanks Malte Helmert for spotting it. Index: SimpleXMLRPCServer.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/SimpleXMLRPCServer.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- SimpleXMLRPCServer.py 2 Nov 2003 09:47:05 -0000 1.8 +++ SimpleXMLRPCServer.py 3 Oct 2004 23:21:44 -0000 1.9 @@ -266,7 +266,7 @@ def system_methodSignature(self, method_name): """system.methodSignature('add') => [double, int, int] - Returns a list describing the signiture of the method. In the + Returns a list describing the signature of the method. In the above example, the add method takes two integers as arguments and returns a double result. From bcannon at users.sourceforge.net Mon Oct 4 01:23:02 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 4 01:23:06 2004 Subject: [Python-checkins] python/dist/src/Lib SimpleXMLRPCServer.py, 1.7, 1.7.8.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2227/Lib Modified Files: Tag: release23-maint SimpleXMLRPCServer.py Log Message: Fix typo in docstring for system_methodSignature . Backport of fix for bug #1038935 . Index: SimpleXMLRPCServer.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/SimpleXMLRPCServer.py,v retrieving revision 1.7 retrieving revision 1.7.8.1 diff -u -d -r1.7 -r1.7.8.1 --- SimpleXMLRPCServer.py 29 Jun 2003 04:19:37 -0000 1.7 +++ SimpleXMLRPCServer.py 3 Oct 2004 23:23:00 -0000 1.7.8.1 @@ -267,7 +267,7 @@ def system_methodSignature(self, method_name): """system.methodSignature('add') => [double, int, int] - Returns a list describing the signiture of the method. In the + Returns a list describing the signature of the method. In the above example, the add method takes two integers as arguments and returns a double result. From tim_one at users.sourceforge.net Mon Oct 4 05:34:35 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Mon Oct 4 05:34:38 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libdoctest.tex,1.64,1.65 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18702/Doc/lib Modified Files: libdoctest.tex Log Message: The docs claimed a test would pass that actually wouldn't pass. Repaired the example so it does pass. Index: libdoctest.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libdoctest.tex,v retrieving revision 1.64 retrieving revision 1.65 diff -u -d -r1.64 -r1.65 --- libdoctest.tex 30 Sep 2004 17:18:18 -0000 1.64 +++ libdoctest.tex 4 Oct 2004 03:34:32 -0000 1.65 @@ -501,7 +501,7 @@ case where you need to test a \exception{SyntaxError} that omits the traceback header, you will need to manually add the traceback header line to your test example. - + \item For some \exception{SyntaxError}s, Python displays the character position of the syntax error, using a \code{\^} marker: @@ -520,6 +520,7 @@ \begin{verbatim} >>> 1 1 +Traceback (most recent call last): File "", line 1 1 1 ^ From ngilbert at cyberway.com.sg Mon Oct 4 14:20:22 2004 From: ngilbert at cyberway.com.sg (Gilbert Ng) Date: Mon Oct 4 14:14:21 2004 Subject: [Python-checkins] Global Business Opportunity In New Industry Message-ID: <20041004121419.ACF2D1E4003@bag.python.org> Dear Business Owner/Professional, I am Gilbert Ng, a Singapore based businessman with global business operation. Our Company is currently open up a New Industry in the Philippines and globally. We will be traveling and conducting our Global Business previews in the city of Makati, Quezon, Davao and Lipa respectively. Of these, the major business preview will be conducted in Makati. If you are open to new business ideas/opportunity and interested to find out more, kindly provide your particular as follow: Name: Country/City: Profession: Contact No. (HP/Office): We will invite you and revert you with more information. Hear from you soon...& God Bless! Sincerely, Gilbert Ng Email: ngilbert@cyberway.com.sg Email: ngilbert@L88edc.com L88 International Singapore Disclaimer: This email, together with any attachments, is intended ONLY for the use of the individual or entity to which it is addressed, and may contain information that is legally privileged, confidential, and/or subject to copyright. If you are not the intended recipient, please be informed that any dissemination, distribution or copying of this email, any attachment, or part thereof is strictly prohibited. Kindly note that Internet communications are not secure, and therefore are susceptible to alterations. If you have received this email in error, please advise the sender by reply email, and delete this message. Your co-operation on this matter is highly appreciated. Thank you. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20041004/835922fe/attachment.htm From akuchling at users.sourceforge.net Tue Oct 5 22:23:37 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 5 22:23:40 2004 Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew24.tex, 1.104, 1.105 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2421 Modified Files: whatsnew24.tex Log Message: Add some items Index: whatsnew24.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew24.tex,v retrieving revision 1.104 retrieving revision 1.105 diff -u -d -r1.104 -r1.105 --- whatsnew24.tex 23 Sep 2004 20:17:26 -0000 1.104 +++ whatsnew24.tex 5 Oct 2004 20:23:34 -0000 1.105 @@ -1000,9 +1000,15 @@ \item Korean: cp949, euc-kr, johab, iso-2022-kr \end{itemize} +\item The UTF-8 and UTF-16 codecs now cope better with receiving partial input. +Previously the \class{StreamReader} class would try to read more data, +which made it impossible to resume decoding from the stream. The +\method{read()} method will now return as much data as it can and future +calls will resume decoding where previous ones left off. +(Implemented by Walter D\"orwald.) + \item Some other new encodings were added: HP Roman8, -ISO_8859-11, ISO_8859-16, PCTP-154, -and TIS-620. +ISO_8859-11, ISO_8859-16, PCTP-154, and TIS-620. \item There is a new \module{collections} module for various specialized collection datatypes. @@ -1046,12 +1052,15 @@ that creates an HTML table showing a side by side comparison of two versions of a text. (Contributed by Dan Gass.) -\item The \module{email} package uses a new incremental parser for MIME -message, available in the \module{email.FeedParser} module. -The new parser doesn't require reading the entire message into memory, -and doesn't throw exceptions if a message is malformed; instead it records -any problems as a \member{defect} attribute of the message. -(Developed by Anthony Baxter, Barry Warsaw, Thomas Wouters, and others.) +\item The \module{email} package was updated to version 3.0, +which dropped various deprecated APIs and removes support for Python +versions earlier than 2.3. The 3.0 version of the package uses a new +incremental parser for MIME message, available in the +\module{email.FeedParser} module. The new parser doesn't require +reading the entire message into memory, and doesn't throw exceptions +if a message is malformed; instead it records any problems as a +\member{defect} attribute of the message. (Developed by Anthony +Baxter, Barry Warsaw, Thomas Wouters, and others.) \item The \module{heapq} module has been converted to C. The resulting tenfold improvement in speed makes the module suitable for handling @@ -1170,13 +1179,16 @@ format='%(levelname):%(process):%(thread):%(message)') \end{verbatim} -Another addition to \module{logging} is a -\class{TimedRotatingFileHandler} class which rotates its log files at +Other additions to \module{logging} include a \method{log(\var{level}, +\var{msg})} convenience method, and a +\class{TimedRotatingFileHandler} class that rotates its log files at a timed interval. The module already had \class{RotatingFileHandler}, which rotated logs once the file exceeded a certain size. Both classes derive from a new \class{BaseRotatingHandler} class that can be used to implement other rotating handlers. +(Changes implemented by Vinay Sajip.) + \item The \module{marshal} module now shares interned strings on unpacking a data structure. This may shrink the size of certain pickle strings, but the primary effect is to make \file{.pyc} files significantly smaller. From bcannon at users.sourceforge.net Wed Oct 6 04:11:41 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed Oct 6 04:11:45 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1152,1.1153 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16270/Misc Modified Files: NEWS Log Message: Locale data that contains regex metacharacters are now properly escaped. Closes bug #1039270. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1152 retrieving revision 1.1153 diff -u -d -r1.1152 -r1.1153 --- NEWS 3 Oct 2004 19:03:19 -0000 1.1152 +++ NEWS 6 Oct 2004 02:11:37 -0000 1.1153 @@ -34,6 +34,11 @@ Library ------- +- time.strptime() now properly escapes timezones and all other locale-specific + strings for regex-specific symbols. Was breaking under Japanese Windows when + the timezone was specified as "Tokyo (standard time)". + Closes bug #1039270. + - Updates for the email package: + All deprecated APIs that in email 2.x issued warnings have been removed: _encoder argument to the MIMEText constructor, Message.add_payload(), From bcannon at users.sourceforge.net Wed Oct 6 04:12:09 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed Oct 6 04:12:12 2004 Subject: [Python-checkins] python/dist/src/Lib _strptime.py,1.32,1.33 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16270/Lib Modified Files: _strptime.py Log Message: Locale data that contains regex metacharacters are now properly escaped. Closes bug #1039270. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- _strptime.py 4 May 2004 09:21:43 -0000 1.32 +++ _strptime.py 6 Oct 2004 02:11:36 -0000 1.33 @@ -15,6 +15,7 @@ import calendar from re import compile as re_compile from re import IGNORECASE +from re import escape as re_escape from datetime import date as datetime_date try: from thread import allocate_lock as _thread_allocate_lock @@ -232,7 +233,7 @@ return '' to_convert = to_convert[:] to_convert.sort(key=len, reverse=True) - regex = '|'.join(to_convert) + regex = '|'.join(re_escape(stuff) for stuff in to_convert) regex = '(?P<%s>%s' % (directive, regex) return '%s)' % regex @@ -245,7 +246,8 @@ """ processed_format = '' # The sub() call escapes all characters that might be misconstrued - # as regex syntax. + # as regex syntax. Cannot use re.escape since we have to deal with + # format directives (%m, etc.). regex_chars = re_compile(r"([\\.^$*+?\(\){}\[\]|])") format = regex_chars.sub(r"\\\1", format) whitespace_replacement = re_compile('\s+') From bcannon at users.sourceforge.net Wed Oct 6 04:12:09 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed Oct 6 04:12:13 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_strptime.py, 1.26, 1.27 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16270/Lib/test Modified Files: test_strptime.py Log Message: Locale data that contains regex metacharacters are now properly escaped. Closes bug #1039270. Index: test_strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_strptime.py,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- test_strptime.py 14 Jul 2004 00:43:51 -0000 1.26 +++ test_strptime.py 6 Oct 2004 02:11:36 -0000 1.27 @@ -176,6 +176,19 @@ found = compiled_re.match("\w+ 10") self.failUnless(found, "Escaping failed of format '\w+ 10'") + def test_locale_data_w_regex_metacharacters(self): + # Check that if locale data contains regex metacharacters they are + # escaped properly. + # Discovered by bug #1039270 . + locale_time = _strptime.LocaleTime() + locale_time.timezone = (frozenset(("utc", "gmt", + "Tokyo (standard time)")), + frozenset("Tokyo (daylight time)")) + time_re = _strptime.TimeRE(locale_time) + self.failUnless(time_re.compile("%Z").match("Tokyo (standard time)"), + "locale data that contains regex metacharacters is not" + " properly escaped") + class StrptimeTests(unittest.TestCase): """Tests for _strptime.strptime.""" From bcannon at users.sourceforge.net Wed Oct 6 04:16:47 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed Oct 6 04:16:50 2004 Subject: [Python-checkins] python/dist/src/Lib _strptime.py, 1.23.4.4, 1.23.4.5 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17243/Lib Modified Files: Tag: release23-maint _strptime.py Log Message: Escape locale data for regex metacharacters. Closes bug #1039270. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.23.4.4 retrieving revision 1.23.4.5 diff -u -d -r1.23.4.4 -r1.23.4.5 --- _strptime.py 29 Aug 2003 02:34:22 -0000 1.23.4.4 +++ _strptime.py 6 Oct 2004 02:16:45 -0000 1.23.4.5 @@ -18,6 +18,7 @@ import calendar from re import compile as re_compile from re import IGNORECASE +from re import escape as re_escape from datetime import date as datetime_date __author__ = "Brett Cannon" @@ -367,7 +368,7 @@ else: return '' to_convert.sort(sorter) - regex = '|'.join(to_convert) + regex = '|'.join([re_escape(stuff) for stuff in to_convert]) regex = '(?P<%s>%s' % (directive, regex) return '%s)' % regex From bcannon at users.sourceforge.net Wed Oct 6 04:16:48 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed Oct 6 04:16:51 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.831.4.152, 1.831.4.153 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17243/Misc Modified Files: Tag: release23-maint NEWS Log Message: Escape locale data for regex metacharacters. Closes bug #1039270. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.831.4.152 retrieving revision 1.831.4.153 diff -u -d -r1.831.4.152 -r1.831.4.153 --- NEWS 26 Sep 2004 17:22:11 -0000 1.831.4.152 +++ NEWS 6 Oct 2004 02:16:45 -0000 1.831.4.153 @@ -53,6 +53,8 @@ Library ------- +- Bug #1039270: Locale data is now escaped for regex metacharacters. + - Bug #807871: Fix tkMessageBox.askyesno result. - Patch #1014992: In tarfile.readline, never return more than a line. From bcannon at users.sourceforge.net Wed Oct 6 04:23:16 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed Oct 6 04:23:18 2004 Subject: [Python-checkins] python/dist/src/Lib _strptime.py,1.33,1.34 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18051/Lib Modified Files: _strptime.py Log Message: Convert a listcomp to a gencomp (was already editing code). Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.33 retrieving revision 1.34 diff -u -d -r1.33 -r1.34 --- _strptime.py 6 Oct 2004 02:11:36 -0000 1.33 +++ _strptime.py 6 Oct 2004 02:23:14 -0000 1.34 @@ -208,8 +208,8 @@ 'B': self.__seqToRE(self.locale_time.f_month[1:], 'B'), 'b': self.__seqToRE(self.locale_time.a_month[1:], 'b'), 'p': self.__seqToRE(self.locale_time.am_pm, 'p'), - 'Z': self.__seqToRE([tz for tz_names in self.locale_time.timezone - for tz in tz_names], + 'Z': self.__seqToRE((tz for tz_names in self.locale_time.timezone + for tz in tz_names), 'Z'), '%': '%'}) base.__setitem__('W', base.__getitem__('U')) From pje at users.sourceforge.net Wed Oct 6 08:23:58 2004 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Wed Oct 6 08:24:01 2004 Subject: [Python-checkins] python/nondist/peps pep-0333.txt,1.20,1.21 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30001 Modified Files: pep-0333.txt Log Message: Fix misc. coding errors found while testing the reference library. Index: pep-0333.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0333.txt,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- pep-0333.txt 1 Oct 2004 20:03:01 -0000 1.20 +++ pep-0333.txt 6 Oct 2004 06:23:54 -0000 1.21 @@ -221,7 +221,7 @@ environ['wsgi.version'] = (1,0) environ['wsgi.multithread'] = False environ['wsgi.multiprocess'] = True - environ['wsgi.last_call'] = True + environ['wsgi.run_once'] = True if environ.get('HTTPS','off') in ('on','1'): environ['wsgi.url_scheme'] = 'https' @@ -254,8 +254,8 @@ raise exc_info[0], exc_info[1], exc_info[2] finally: exc_info = None # avoid dangling circular ref - elif headers_sent: - raise AssertionError("Headers already sent!") + elif headers_set: + raise AssertionError("Headers already set!") headers_set[:] = [status,response_headers] return write @@ -1239,6 +1239,7 @@ If an application wishes to reconstruct a request's complete URL, it may do so using the following algorithm, contributed by Ian Bicking:: + from urllib import quote url = environ['wsgi.url_scheme']+'://' if environ.get('HTTP_HOST'): @@ -1247,14 +1248,14 @@ url += environ['SERVER_NAME'] if environ['wsgi.url_scheme'] == 'https': - if environ['SERVER_PORT'] != '443' + if environ['SERVER_PORT'] != '443': url += ':' + environ['SERVER_PORT'] else: if environ['SERVER_PORT'] != '80': url += ':' + environ['SERVER_PORT'] - url += environ.get('SCRIPT_NAME','') - url += environ.get('PATH_INFO','') + url += quote(environ.get('SCRIPT_NAME','')) + url += quote(environ.get('PATH_INFO','')) if environ.get('QUERY_STRING'): url += '?' + environ['QUERY_STRING'] From rhettinger at users.sourceforge.net Wed Oct 6 19:51:56 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed Oct 6 19:52:00 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.32, 1.33 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27377 Modified Files: collectionsmodule.c Log Message: Armin's patch to prevent overflows. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- collectionsmodule.c 2 Oct 2004 13:59:33 -0000 1.32 +++ collectionsmodule.c 6 Oct 2004 17:51:54 -0000 1.33 @@ -52,8 +52,21 @@ } block; static block * -newblock(block *leftlink, block *rightlink) { - block *b = PyMem_Malloc(sizeof(block)); +newblock(block *leftlink, block *rightlink, int len) { + block *b; + /* To prevent len from overflowing INT_MAX on 64-bit machines, we + * refuse to allocate new blocks if the current len is dangerously + * close. There is some extra margin to prevent spurious arithmetic + * overflows at various places. The following check ensures that + * the blocks allocated to the deque, in the worst case, can only + * have INT_MAX-2 entries in total. + */ + if (len >= INT_MAX - 2*BLOCKLEN) { + PyErr_SetString(PyExc_OverflowError, + "cannot add more blocks to the deque"); + return NULL; + } + b = PyMem_Malloc(sizeof(block)); if (b == NULL) { PyErr_NoMemory(); return NULL; @@ -87,7 +100,7 @@ if (deque == NULL) return NULL; - b = newblock(NULL, NULL); + b = newblock(NULL, NULL, 0); if (b == NULL) { Py_DECREF(deque); return NULL; @@ -110,7 +123,7 @@ { deque->state++; if (deque->rightindex == BLOCKLEN-1) { - block *b = newblock(deque->rightblock, NULL); + block *b = newblock(deque->rightblock, NULL, deque->len); if (b == NULL) return NULL; assert(deque->rightblock->rightlink == NULL); @@ -132,7 +145,7 @@ { deque->state++; if (deque->leftindex == 0) { - block *b = newblock(NULL, deque->leftblock); + block *b = newblock(NULL, deque->leftblock, deque->len); if (b == NULL) return NULL; assert(deque->leftblock->leftlink == NULL); @@ -235,7 +248,8 @@ while ((item = PyIter_Next(it)) != NULL) { deque->state++; if (deque->rightindex == BLOCKLEN-1) { - block *b = newblock(deque->rightblock, NULL); + block *b = newblock(deque->rightblock, NULL, + deque->len); if (b == NULL) { Py_DECREF(item); Py_DECREF(it); @@ -271,7 +285,8 @@ while ((item = PyIter_Next(it)) != NULL) { deque->state++; if (deque->leftindex == 0) { - block *b = newblock(NULL, deque->leftblock); + block *b = newblock(NULL, deque->leftblock, + deque->len); if (b == NULL) { Py_DECREF(item); Py_DECREF(it); From bcannon at users.sourceforge.net Thu Oct 7 00:49:01 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Thu Oct 7 00:49:04 2004 Subject: [Python-checkins] python/dist/src/Lib _strptime.py,1.34,1.35 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4995/Lib Modified Files: _strptime.py Log Message: Fix bug introduced by the previous patch by changing TimeRE.__seqToRe() to accept any iterable instead of only a sliceable object. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.34 retrieving revision 1.35 diff -u -d -r1.34 -r1.35 --- _strptime.py 6 Oct 2004 02:23:14 -0000 1.34 +++ _strptime.py 6 Oct 2004 22:48:58 -0000 1.35 @@ -226,13 +226,12 @@ matching when 'abcdef' should have been the match). """ + to_convert = sorted(to_convert, key=len, reverse=True) for value in to_convert: if value != '': break else: return '' - to_convert = to_convert[:] - to_convert.sort(key=len, reverse=True) regex = '|'.join(re_escape(stuff) for stuff in to_convert) regex = '(?P<%s>%s' % (directive, regex) return '%s)' % regex From fdrake at users.sourceforge.net Thu Oct 7 03:33:57 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Thu Oct 7 03:34:00 2004 Subject: [Python-checkins] python/nondist/peps pep-0000.txt,1.290,1.291 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9181 Modified Files: pep-0000.txt Log Message: since PEP 262 was deferred, mark it consistently on both entries Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.290 retrieving revision 1.291 diff -u -d -r1.290 -r1.291 --- pep-0000.txt 9 Sep 2004 13:48:44 -0000 1.290 +++ pep-0000.txt 7 Oct 2004 01:33:55 -0000 1.291 @@ -84,7 +84,7 @@ S 254 Making Classes Look More Like Types GvR S 256 Docstring Processing System Framework Goodger S 258 Docutils Design Specification Goodger - S 262 Database of Installed Python Packages Kuchling + SD 262 Database of Installed Python Packages Kuchling S 265 Sorting Dictionaries by Value Griffin S 266 Optimizing Global Variable/Attribute Access Montanaro S 267 Optimized Access to Module Namespaces Hylton From rhettinger at users.sourceforge.net Thu Oct 7 05:58:09 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu Oct 7 05:58:12 2004 Subject: [Python-checkins] python/dist/src/Include pythonrun.h,2.64,2.65 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2208/Include Modified Files: pythonrun.h Log Message: Finalize the freelist of list objects. Index: pythonrun.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/pythonrun.h,v retrieving revision 2.64 retrieving revision 2.65 diff -u -d -r2.64 -r2.65 --- pythonrun.h 19 Aug 2004 11:31:56 -0000 2.64 +++ pythonrun.h 7 Oct 2004 03:58:06 -0000 2.65 @@ -113,6 +113,7 @@ PyAPI_FUNC(void) PyFrame_Fini(void); PyAPI_FUNC(void) PyCFunction_Fini(void); PyAPI_FUNC(void) PyTuple_Fini(void); +PyAPI_FUNC(void) PyList_Fini(void); PyAPI_FUNC(void) PyString_Fini(void); PyAPI_FUNC(void) PyInt_Fini(void); PyAPI_FUNC(void) PyFloat_Fini(void); From rhettinger at users.sourceforge.net Thu Oct 7 05:58:10 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu Oct 7 05:58:14 2004 Subject: [Python-checkins] python/dist/src/Python pythonrun.c,2.208,2.209 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2208/Python Modified Files: pythonrun.c Log Message: Finalize the freelist of list objects. Index: pythonrun.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pythonrun.c,v retrieving revision 2.208 retrieving revision 2.209 diff -u -d -r2.208 -r2.209 --- pythonrun.c 19 Aug 2004 11:31:58 -0000 2.208 +++ pythonrun.c 7 Oct 2004 03:58:07 -0000 2.209 @@ -416,6 +416,7 @@ PyFrame_Fini(); PyCFunction_Fini(); PyTuple_Fini(); + PyList_Fini(); PyString_Fini(); PyInt_Fini(); PyFloat_Fini(); From rhettinger at users.sourceforge.net Thu Oct 7 05:58:11 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu Oct 7 05:58:14 2004 Subject: [Python-checkins] python/dist/src/Objects listobject.c,2.224,2.225 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2208/Objects Modified Files: listobject.c Log Message: Finalize the freelist of list objects. Index: listobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v retrieving revision 2.224 retrieving revision 2.225 diff -u -d -r2.224 -r2.225 --- listobject.c 26 Sep 2004 19:24:20 -0000 2.224 +++ listobject.c 7 Oct 2004 03:58:07 -0000 2.225 @@ -68,6 +68,19 @@ static PyListObject *free_lists[MAXFREELISTS]; static int num_free_lists = 0; +void +PyList_Fini(void) +{ + PyListObject *op; + + while (num_free_lists) { + num_free_lists--; + op = free_lists[num_free_lists]; + assert(PyList_CheckExact(op)); + PyObject_GC_Del(op); + } +} + PyObject * PyList_New(int size) { From rhettinger at users.sourceforge.net Thu Oct 7 08:46:26 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu Oct 7 08:46:29 2004 Subject: [Python-checkins] python/dist/src/Include import.h,2.29,2.30 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27294/Include Modified Files: import.h Log Message: SF patch #1035498: -m option to run a module as a script (Contributed by Nick Coghlan.) Index: import.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/import.h,v retrieving revision 2.29 retrieving revision 2.30 diff -u -d -r2.29 -r2.30 --- import.h 29 Jul 2002 13:41:59 -0000 2.29 +++ import.h 7 Oct 2004 06:46:23 -0000 2.30 @@ -21,6 +21,10 @@ PyAPI_FUNC(void) PyImport_Cleanup(void); PyAPI_FUNC(int) PyImport_ImportFrozenModule(char *); +PyAPI_FUNC(struct filedescr *) _PyImport_FindModule( + const char *, PyObject *, char *, size_t, FILE **, PyObject **); +PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr *); + PyAPI_FUNC(PyObject *)_PyImport_FindExtension(char *, char *); PyAPI_FUNC(PyObject *)_PyImport_FixupExtension(char *, char *); From rhettinger at users.sourceforge.net Thu Oct 7 08:46:27 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu Oct 7 08:46:30 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1153,1.1154 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27294/Misc Modified Files: NEWS Log Message: SF patch #1035498: -m option to run a module as a script (Contributed by Nick Coghlan.) Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1153 retrieving revision 1.1154 diff -u -d -r1.1153 -r1.1154 --- NEWS 6 Oct 2004 02:11:37 -0000 1.1153 +++ NEWS 7 Oct 2004 06:46:24 -0000 1.1154 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Added a command line option, -m module, which searches sys.path for the + module and then runs it. (Contributed by Nick Coghlan.) + - The bytecode optimizer now folds tuples of constants into a single constant. @@ -29,7 +32,9 @@ - ``collections.deque`` objects didn't play quite right with garbage collection, which could lead to a segfault in a release build, or - an assert failure in a debug build. + an assert failure in a debug build. Also, added overflow checks, + better detection of mutation during iteration, and shielded deque + comparisons from unusual subclass overrides of the __iter__() method. Library ------- From rhettinger at users.sourceforge.net Thu Oct 7 08:46:28 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu Oct 7 08:46:32 2004 Subject: [Python-checkins] python/dist/src/Python import.c,2.239,2.240 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27294/Python Modified Files: import.c Log Message: SF patch #1035498: -m option to run a module as a script (Contributed by Nick Coghlan.) Index: import.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/import.c,v retrieving revision 2.239 retrieving revision 2.240 diff -u -d -r2.239 -r2.240 --- import.c 23 Sep 2004 04:37:36 -0000 2.239 +++ import.c 7 Oct 2004 06:46:25 -0000 2.240 @@ -1334,6 +1334,22 @@ return fdp; } +/* Helpers for main.c + * Find the source file corresponding to a named module + */ +struct filedescr * +_PyImport_FindModule(const char *name, PyObject *path, char *buf, + size_t buflen, FILE **p_fp, PyObject **p_loader) +{ + return find_module((char *) name, (char *) name, path, + buf, buflen, p_fp, p_loader); +} + +PyAPI_FUNC(int) _PyImport_IsScript(struct filedescr * fd) +{ + return fd->type == PY_SOURCE || fd->type == PY_COMPILED; +} + /* case_ok(char* buf, int len, int namelen, char* name) * The arguments here are tricky, best shown by example: * /a/b/c/d/e/f/g/h/i/j/k/some_long_module_name.py\0 From rhettinger at users.sourceforge.net Thu Oct 7 08:46:28 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu Oct 7 08:46:33 2004 Subject: [Python-checkins] python/dist/src/Modules main.c,1.83,1.84 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27294/Modules Modified Files: main.c Log Message: SF patch #1035498: -m option to run a module as a script (Contributed by Nick Coghlan.) Index: main.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/main.c,v retrieving revision 1.83 retrieving revision 1.84 diff -u -d -r1.83 -r1.84 --- main.c 19 Aug 2004 11:07:49 -0000 1.83 +++ main.c 7 Oct 2004 06:46:25 -0000 1.84 @@ -3,6 +3,7 @@ #include "Python.h" #include "osdefs.h" #include "compile.h" /* For CO_FUTURE_DIVISION */ +#include "import.h" #ifdef __VMS #include @@ -33,7 +34,7 @@ static int orig_argc; /* command line options */ -#define BASE_OPTS "c:dEhiOQ:StuUvVW:xX" +#define BASE_OPTS "c:dEhim:OQ:StuUvVW:xX" #ifndef RISCOS #define PROGRAM_OPTS BASE_OPTS @@ -47,7 +48,7 @@ /* Short usage message (with %s for argv0) */ static char *usage_line = -"usage: %s [option] ... [-c cmd | file | -] [arg] ...\n"; +"usage: %s [option] ... [-c cmd | -m mod | file | -] [arg] ...\n"; /* Long usage message, split into parts < 512 bytes */ static char *usage_1 = "\ @@ -60,15 +61,16 @@ and force prompts, even if stdin does not appear to be a terminal\n\ "; static char *usage_2 = "\ +-m mod : run library module as a script (terminates option list)\n\ -O : optimize generated bytecode (a tad; also PYTHONOPTIMIZE=x)\n\ -OO : remove doc-strings in addition to the -O optimizations\n\ -Q arg : division options: -Qold (default), -Qwarn, -Qwarnall, -Qnew\n\ -S : don't imply 'import site' on initialization\n\ -t : issue warnings about inconsistent tab usage (-tt: issue errors)\n\ -u : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x)\n\ - see man page for details on internal buffering relating to '-u'\n\ "; static char *usage_3 = "\ + see man page for details on internal buffering relating to '-u'\n\ -v : verbose (trace import statements) (also PYTHONVERBOSE=x)\n\ -V : print the Python version number and exit\n\ -W arg : warning control (arg is action:message:category:module:lineno)\n\ @@ -130,6 +132,28 @@ } } +/* Get the path to a top-level module */ +static struct filedescr * FindModule(const char *module, + FILE **fp, char **filename) +{ + struct filedescr *fdescr = NULL; + *fp = NULL; + *filename = malloc(MAXPATHLEN); + + if (*filename == NULL) + return NULL; + + /* Find the actual module source code */ + fdescr = _PyImport_FindModule(module, NULL, + *filename, MAXPATHLEN, fp, NULL); + + if (fdescr == NULL) { + free(*filename); + *filename = NULL; + } + + return fdescr; +} /* Main program */ @@ -140,6 +164,7 @@ int sts; char *command = NULL; char *filename = NULL; + char *module = NULL; FILE *fp = stdin; char *p; int inspect = 0; @@ -177,6 +202,18 @@ break; } + if (c == 'm') { + /* -m is the last option; following arguments + that look like options are left for the + module to interpret. */ + module = malloc(strlen(_PyOS_optarg) + 2); + if (module == NULL) + Py_FatalError( + "not enough memory to copy -m argument"); + strcpy(module, _PyOS_optarg); + break; + } + switch (c) { case 'd': @@ -289,7 +326,7 @@ (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0') unbuffered = 1; - if (command == NULL && _PyOS_optind < argc && + if (command == NULL && module == NULL && _PyOS_optind < argc && strcmp(argv[_PyOS_optind], "-") != 0) { #ifdef __VMS @@ -381,7 +418,7 @@ Py_Initialize(); if (Py_VerboseFlag || - (command == NULL && filename == NULL && stdin_is_interactive)) { + (command == NULL && filename == NULL && module == NULL && stdin_is_interactive)) { fprintf(stderr, "Python %s on %s\n", Py_GetVersion(), Py_GetPlatform()); if (!Py_NoSiteFlag) @@ -394,9 +431,34 @@ argv[_PyOS_optind] = "-c"; } + if (module != NULL) { + /* Backup _PyOS_optind and find the real file */ + struct filedescr *fdescr = NULL; + _PyOS_optind--; + if ((fdescr = FindModule(module, &fp, &filename))) { + argv[_PyOS_optind] = filename; + } else { + fprintf(stderr, "%s: module %s not found\n", + argv[0], module); + return 2; + } + if (!fp) { + fprintf(stderr, + "%s: module %s has no associated file\n", + argv[0], module); + return 2; + } + if (!_PyImport_IsScript(fdescr)) { + fprintf(stderr, + "%s: module %s not usable as script\n (%s)\n", + argv[0], module, filename); + return 2; + } + } + PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind); - if ((inspect || (command == NULL && filename == NULL)) && + if ((inspect || (command == NULL && filename == NULL && module == NULL)) && isatty(fileno(stdin))) { PyObject *v; v = PyImport_ImportModule("readline"); @@ -409,6 +471,10 @@ if (command) { sts = PyRun_SimpleStringFlags(command, &cf) != 0; free(command); + } else if (module) { + sts = PyRun_AnyFileExFlags(fp, filename, 1, &cf) != 0; + free(module); + free(filename); } else { if (filename == NULL && stdin_is_interactive) { @@ -431,7 +497,7 @@ } if (inspect && stdin_is_interactive && - (filename != NULL || command != NULL)) + (filename != NULL || command != NULL || module != NULL)) /* XXX */ sts = PyRun_AnyFileFlags(stdin, "", &cf) != 0; From rhettinger at users.sourceforge.net Thu Oct 7 08:46:55 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu Oct 7 08:46:58 2004 Subject: [Python-checkins] python/dist/src/Doc/tut tut.tex,1.253,1.254 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27294/Doc/tut Modified Files: tut.tex Log Message: SF patch #1035498: -m option to run a module as a script (Contributed by Nick Coghlan.) Index: tut.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/tut.tex,v retrieving revision 1.253 retrieving revision 1.254 diff -u -d -r1.253 -r1.254 --- tut.tex 28 Sep 2004 16:12:50 -0000 1.253 +++ tut.tex 7 Oct 2004 06:46:22 -0000 1.254 @@ -205,6 +205,11 @@ or other characters that are special to the shell, it is best to quote \var{command} in its entirety with double quotes. +Some Python modules are also useful as scripts. These can be invoked using +\samp{\program{python} \programopt{-m} \var{module} [arg] ...}, which +executes the source file for \var{module} as if you had spelled out its +full name on the command line. + Note that there is a difference between \samp{python file} and \samp{python Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28397 Modified Files: whatsnew24.tex Log Message: Add item Index: whatsnew24.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew24.tex,v retrieving revision 1.105 retrieving revision 1.106 diff -u -d -r1.105 -r1.106 --- whatsnew24.tex 5 Oct 2004 20:23:34 -0000 1.105 +++ whatsnew24.tex 7 Oct 2004 12:00:33 -0000 1.106 @@ -868,6 +868,12 @@ \item Integer operations will no longer trigger an \exception{OverflowWarning}. The \exception{OverflowWarning} warning will disappear in Python 2.5. +\item The interpreter gained a new switch, \programopt{-m}, that +takes a name, searches for the corresponding module on \code{sys.path}, +and runs the module as a script. For example, +you can now run the Python profiler with \code{python -m profile}. +(Contributed by Nick Coghlan.) + \item The \function{eval(\var{expr}, \var{globals}, \var{locals})} and \function{execfile(\var{filename}, \var{globals}, \var{locals})} functions and the \keyword{exec} statement now accept any mapping type From akuchling at users.sourceforge.net Thu Oct 7 14:04:53 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Thu Oct 7 14:04:55 2004 Subject: [Python-checkins] python/dist/src/Misc python.man,1.27,1.28 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29310 Modified Files: python.man Log Message: Add -m to man page Index: python.man =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/python.man,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- python.man 26 May 2003 05:15:35 -0000 1.27 +++ python.man 7 Oct 2004 12:04:50 -0000 1.28 @@ -16,6 +16,10 @@ .B \-i ] [ +.B \-m +.I module-name +] +[ .B \-O ] .br @@ -107,6 +111,13 @@ useful to inspect global variables or a stack trace when a script raises an exception. .TP +.BI "\-m " module-name +Searches +.I sys.path +for the named module and runs the corresponding +.I .py +file as a script. +.TP .B \-O Turn on basic optimizations. This changes the filename extension for compiled (bytecode) files from From akuchling at users.sourceforge.net Thu Oct 7 14:23:15 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Thu Oct 7 14:23:17 2004 Subject: [Python-checkins] python/dist/src/Misc python.man,1.28,1.29 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv937 Modified Files: python.man Log Message: Update two URLs Index: python.man =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/python.man,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- python.man 7 Oct 2004 12:04:50 -0000 1.28 +++ python.man 7 Oct 2004 12:23:12 -0000 1.29 @@ -381,11 +381,11 @@ .SH INTERNET RESOURCES Main website: http://www.python.org/ .br -Documentation: http://www.python.org/doc/ +Documentation: http://docs.python.org/ .br Community website: http://starship.python.net/ .br -Developer resources: http://sourceforge.net/project/python/ +Developer resources: http://www.python.org/dev/ .br FTP: ftp://ftp.python.org/pub/python/ .br From akuchling at users.sourceforge.net Thu Oct 7 14:27:33 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Thu Oct 7 14:27:37 2004 Subject: [Python-checkins] python/dist/src/Misc python.man,1.29,1.30 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1882 Modified Files: python.man Log Message: Take out Guido's name and put in the PSF Index: python.man =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/python.man,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- python.man 7 Oct 2004 12:23:12 -0000 1.29 +++ python.man 7 Oct 2004 12:27:31 -0000 1.30 @@ -371,13 +371,7 @@ the \fB\-v\fP option. If set to an integer, it is equivalent to specifying \fB\-v\fP multiple times. .SH AUTHOR -.nf -Guido van Rossum -.PP -E-mail: guido@python.org -.fi -.PP -And a cast of thousands. +The Python Software Foundation: http://www.python.org/psf .SH INTERNET RESOURCES Main website: http://www.python.org/ .br From akuchling at users.sourceforge.net Thu Oct 7 14:30:57 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Thu Oct 7 14:31:00 2004 Subject: [Python-checkins] python/dist/src/Misc python.man,1.30,1.31 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2549 Modified Files: python.man Log Message: Add helpful comment Index: python.man =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/python.man,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- python.man 7 Oct 2004 12:27:31 -0000 1.30 +++ python.man 7 Oct 2004 12:30:54 -0000 1.31 @@ -1,4 +1,8 @@ .TH PYTHON "1" "$Date$" + +./" To view this file while editing, run it through groff: +./" groff -Tascii -man python.man | less + .SH NAME python \- an interpreted, interactive, object-oriented programming language .SH SYNOPSIS From mwh at users.sourceforge.net Thu Oct 7 15:46:39 2004 From: mwh at users.sourceforge.net (mwh@users.sourceforge.net) Date: Thu Oct 7 15:46:41 2004 Subject: [Python-checkins] python/dist/src/Modules readline.c,2.77,2.78 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19228/Modules Modified Files: readline.c Log Message: This is Michiel de Hoon's patch, as attached to the bug report: [ 1030629 ] PyOS_InputHook broken with a couple of utterly inconsequential changes by me. Index: readline.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/readline.c,v retrieving revision 2.77 retrieving revision 2.78 diff -u -d -r2.77 -r2.78 --- readline.c 25 Aug 2004 01:20:18 -0000 2.77 +++ readline.c 7 Oct 2004 13:46:33 -0000 2.78 @@ -11,6 +11,7 @@ #include #include #include +#include #if defined(HAVE_SETLOCALE) /* GNU readline() mistakenly sets the LC_CTYPE locale. @@ -749,15 +750,21 @@ rl_callback_handler_install (prompt, rlhandler); FD_ZERO(&selectset); - FD_SET(fileno(rl_instream), &selectset); completed_input_string = not_done_reading; - while(completed_input_string == not_done_reading) { - int has_input; + while (completed_input_string == not_done_reading) { + int has_input = 0; + + while (!has_input) + { struct timeval timeout = {0, 100000}; /* 0.1 seconds */ + FD_SET(fileno(rl_instream), &selectset); + /* select resets selectset if no input was available */ + has_input = select(fileno(rl_instream) + 1, &selectset, + NULL, NULL, &timeout); + if(PyOS_InputHook) PyOS_InputHook(); + } - has_input = select(fileno(rl_instream) + 1, &selectset, - NULL, NULL, NULL); if(has_input > 0) { rl_callback_read_char(); } @@ -812,6 +819,7 @@ *signal = 1; return NULL; } + rl_event_hook = PyOS_InputHook; p = readline(prompt); PyOS_setsig(SIGINT, old_inthandler); @@ -834,8 +842,6 @@ setlocale(LC_CTYPE, ""); #endif - rl_event_hook = PyOS_InputHook; - if (sys_stdin != rl_instream || sys_stdout != rl_outstream) { rl_instream = sys_stdin; rl_outstream = sys_stdout; From jlgijsbers at users.sourceforge.net Thu Oct 7 23:10:13 2004 From: jlgijsbers at users.sourceforge.net (jlgijsbers@users.sourceforge.net) Date: Thu Oct 7 23:10:15 2004 Subject: [Python-checkins] python/dist/src/Lib shutil.py,1.32,1.33 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31268 Modified Files: shutil.py Log Message: Rewrite rmtree using os.walk to fix bug #1025127: The shutils.rmtree() implementation uses an excessive amount of memory when deleting large directory hierarchies. Before actually deleting any files, it builds up a list of (function, filename) tuples for all the files that it is going to remove. Index: shutil.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/shutil.py,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- shutil.py 14 Aug 2004 14:51:01 -0000 1.32 +++ shutil.py 7 Oct 2004 21:10:08 -0000 1.33 @@ -127,6 +127,9 @@ if errors: raise Error, errors +def _raise_err(err): + raise err + def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. @@ -134,12 +137,20 @@ onerror is set, it is called to handle the error; otherwise, an exception is raised. """ - cmdtuples = [] + # This strange way of calling functions is necessary to keep the onerror + # argument working. Maybe sys._getframe hackery would work as well, but + # this is simple. + func = os.listdir arg = path try: - func = os.listdir # Make sure it isn't unset - _build_cmdtuple(path, cmdtuples) - for func, arg in cmdtuples: + for (dirpath, dirnames, filenames) in os.walk(path, topdown=False, + onerror=_raise_err): + for filename in filenames: + func = os.remove + arg = os.path.join(dirpath, filename) + func(arg) + func = os.rmdir + arg = dirpath func(arg) except OSError: exc = sys.exc_info() @@ -150,17 +161,6 @@ else: raise exc[0], (exc[1][0], exc[1][1] + ' removing '+arg) -# Helper for rmtree() -def _build_cmdtuple(path, cmdtuples): - for f in os.listdir(path): - real_f = os.path.join(path,f) - if os.path.isdir(real_f) and not os.path.islink(real_f): - _build_cmdtuple(real_f, cmdtuples) - else: - cmdtuples.append((os.remove, real_f)) - cmdtuples.append((os.rmdir, path)) - - def move(src, dst): """Recursively move a file or directory to another location. From rhettinger at users.sourceforge.net Fri Oct 8 03:52:18 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri Oct 8 03:52:21 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libstdtypes.tex, 1.166, 1.167 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29497 Modified Files: libstdtypes.tex Log Message: SF patch #1041364: True/False instead of 1/0 in libstdtypes.tex (Contributed by Gerrit Holl. Reviewed by Jeff Epler.) Index: libstdtypes.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libstdtypes.tex,v retrieving revision 1.166 retrieving revision 1.167 diff -u -d -r1.166 -r1.167 --- libstdtypes.tex 10 Sep 2004 12:57:46 -0000 1.166 +++ libstdtypes.tex 8 Oct 2004 01:52:15 -0000 1.167 @@ -451,9 +451,9 @@ and \var{j} are integers: \begin{tableiii}{c|l|c}{code}{Operation}{Result}{Notes} - \lineiii{\var{x} in \var{s}}{\code{1} if an item of \var{s} is equal to \var{x}, else \code{0}}{(1)} - \lineiii{\var{x} not in \var{s}}{\code{0} if an item of \var{s} is -equal to \var{x}, else \code{1}}{(1)} + \lineiii{\var{x} in \var{s}}{\code{True} if an item of \var{s} is equal to \var{x}, else \code{False}}{(1)} + \lineiii{\var{x} not in \var{s}}{\code{False} if an item of \var{s} is +equal to \var{x}, else \code{True}}{(1)} \hline \lineiii{\var{s} + \var{t}}{the concatenation of \var{s} and \var{t}}{(6)} \lineiii{\var{s} * \var{n}\textrm{,} \var{n} * \var{s}}{\var{n} shallow copies of \var{s} concatenated}{(2)} From pierslauder at users.sourceforge.net Fri Oct 8 06:05:42 2004 From: pierslauder at users.sourceforge.net (pierslauder@users.sourceforge.net) Date: Fri Oct 8 06:05:45 2004 Subject: [Python-checkins] python/dist/src/Lib imaplib.py,1.73,1.74 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19775/dist/src/Lib Modified Files: imaplib.py Log Message: Fix bug in _checkquote that raised an exception on empty "arg". Index: imaplib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/imaplib.py,v retrieving revision 1.73 retrieving revision 1.74 diff -u -d -r1.73 -r1.74 --- imaplib.py 27 Sep 2004 15:29:02 -0000 1.73 +++ imaplib.py 8 Oct 2004 04:05:39 -0000 1.74 @@ -1008,9 +1008,9 @@ if type(arg) is not type(''): return arg - if (arg[0],arg[-1]) in (('(',')'),('"','"')): + if len(arg) >= 2 and (arg[0],arg[-1]) in (('(',')'),('"','"')): return arg - if self.mustquote.search(arg) is None: + if arg and self.mustquote.search(arg) is None: return arg return self._quote(arg) From goodger at users.sourceforge.net Fri Oct 8 15:03:25 2004 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Fri Oct 8 15:03:28 2004 Subject: [Python-checkins] python/nondist/peps pep-0000.txt, 1.291, 1.292 pep-0324.txt, 1.2, 1.3 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25124 Modified Files: pep-0000.txt pep-0324.txt Log Message: update from Peter Astrand; title change Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.291 retrieving revision 1.292 diff -u -d -r1.291 -r1.292 --- pep-0000.txt 7 Oct 2004 01:33:55 -0000 1.291 +++ pep-0000.txt 8 Oct 2004 13:03:22 -0000 1.292 @@ -116,7 +116,7 @@ S 319 Python Synchronize/Asynchronize Block Pelletier S 321 Date/Time Parsing and Formatting Kuchling S 323 Copyable Iterators Martelli - S 324 process - New POSIX process module Astrand + S 324 subprocess - New process module Astrand S 325 Resource-Release Support for Generators Pedroni S 330 Python Bytecode Verification Pelletier S 331 Locale-Independent Float/String conversions Reis @@ -354,7 +354,7 @@ S 321 Date/Time Parsing and Formatting Kuchling SF 322 Reverse Iteration Hettinger S 323 Copyable Iterators Martelli - S 324 process - New POSIX process module Astrand + S 324 subprocess - New POSIX process module Astrand S 325 Resource-Release Support for Generators Pedroni SR 326 A Case for Top and Bottom Values Carlson, Reedy SF 327 Decimal Data Type Batista Index: pep-0324.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0324.txt,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- pep-0324.txt 3 Aug 2004 13:13:43 -0000 1.2 +++ pep-0324.txt 8 Oct 2004 13:03:22 -0000 1.3 @@ -1,5 +1,5 @@ PEP: 324 -Title: process - New POSIX process module +Title: subprocess - New process module Version: $Revision$ Last-Modified: $Date$ Author: Peter Astrand @@ -13,7 +13,7 @@ Abstract This PEP describes a new module for starting and communicating - with processes on POSIX systems. + with processes. Motivation @@ -31,9 +31,9 @@ over-complicated shell scripts. Currently, Python has a large number of different functions for - process creation. This makes it hard for developers to choose. + process creation. This makes it hard for developers to choose. - The process module provides the following enhancements over + The subprocess module provides the following enhancements over previous functions: - One "unified" module provides all functionality from previous @@ -56,7 +56,7 @@ and redirect stderr, but not stdout. This is not possible with current functions, without using temporary files. - - With the process module, it's possible to control if all open + - With the subprocess module, it's possible to control if all open file descriptors should be closed before the new program is executed. @@ -78,22 +78,22 @@ The following points summarizes the design: - - process was based on popen2, which is tried-and-tested. + - subprocess was based on popen2, which is tried-and-tested. - The factory functions in popen2 have been removed, because I consider the class constructor equally easy to work with. - popen2 contains several factory functions and classes for - different combinations of redirection. process, however, - contains one single class. Since the process module supports 12 - different combinations of redirection, providing a class or + different combinations of redirection. subprocess, however, + contains one single class. Since the subprocess module supports + 12 different combinations of redirection, providing a class or function for each of them would be cumbersome and not very intuitive. Even with popen2, this is a readability problem. For example, many people cannot tell the difference between popen2.popen2 and popen2.popen4 without using the documentation. - - Two small utility functions are provided: process.call() and - process.callv(). These aims to be an enhancement over + - Two small utility functions are provided: subprocess.call() and + subprocess.callv(). These aims to be an enhancement over os.system(), while still very easy to use: - It does not use the Standard C function system(), which has @@ -106,8 +106,8 @@ - The return value is easier to work with. The call() utility function accepts an 'args' argument, just - like the Popen class constructor. It waits for the command to - complete, then returns the returncode attribute. The + like the Popen class constructor. It waits for the command to + complete, then returns the returncode attribute. The implementation is very simple: def call(*args, **kwargs): @@ -117,30 +117,30 @@ process and wait for it to finish is a common task. The callv() function is identical to call(), except that each - non-keyword argument is treated as a program argument. This - gives a slightly nicer syntax. The drawback is that callv() does - not allow specifying the program and it's arguments as a + non-keyword argument is treated as a program argument. This + gives a slightly nicer syntax. The drawback is that callv() + does not allow specifying the program and it's arguments as a whitespace-separated string: The entire (first) string would be - intepreted as the executable. The implementation of callv() is + interpreted as the executable. The implementation of callv() is also very simple: def callv(*args, **kwargs): return Popen(args, **kwargs).wait() While Popen supports a wide range of options, many users have - simple needs. Many people are using os.system() today, mainly - because it provides a simple interface. Consider this example: + simple needs. Many people are using os.system() today, mainly + because it provides a simple interface. Consider this example: os.system("stty sane -F " + device) - With process.call(), this would look like: + With subprocess.call(), this would look like: - process.call(["stty", "sane", "-F", device]) + subprocess.call(["stty", "sane", "-F", device]) - Some people feel that the list brackets are clumsy. With + Some people feel that the list brackets are clumsy. With callv(), they are not needed: - process.callv("stty", "sane", "-F", device) + subprocess.callv("stty", "sane", "-F", device) - The "preexec" functionality makes it possible to run arbitrary code between fork and exec. One might ask why there are special @@ -156,6 +156,13 @@ - env and cwd are considered quite cross-platform: They make sense even on Windows. + - On POSIX platforms, no extension module is required: the module + uses os.fork(), os.execvp() etc. + + - On Windows platforms, the module requires either Mark Hammond's + Windows extensions[5], or a small extension module called + _subprocess. + Specification @@ -163,24 +170,24 @@ class Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, + preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0): - - + + Arguments are: - + - args should be a sequence of program arguments. The program to execute is normally the first item in the args sequence, but can be explicitly set by using the executable argument. - + - On UNIX: the Popen class uses os.execvp() to execute the child program, which operates on sequences. If args is a string, it will be converted to a sequence using the cmdline2list method. Please note that syntax for quoting arguments is different from a typical UNIX shell. See the documentation of the cmdline2list method for more information. - + - On Windows: the Popen class uses CreateProcess() to execute the child program, which operates on strings. If args is a sequence, it will be converted to a string using the @@ -188,7 +195,7 @@ applications interpret the command line the same way: The list2cmdline is designed for applications using the same rules as the MS C runtime. - + - bufsize, if given, has the same meaning as the corresponding argument to the built-in open() function: 0 means unbuffered, 1 means line buffered, any other positive value means use a buffer @@ -213,6 +220,13 @@ - If close_fds is true, all file descriptors except 0, 1 and 2 will be closed before the child process is executed. + - If shell is true, the specified command will be executed through + the shell. Note: When executing through the shell on UNIX + systems and the args argument is a sequence, only the first + element in the sequence will be passed as a command string to + the shell. The remaining arguments can be used to specify + additional shell options. + - If cwd is not None, the current directory will be changed to cwd before the child is executed. @@ -233,66 +247,74 @@ the underlying CreateProcess() function. They can specify things such as appearance of the main window and priority for the new process. (Windows only) - - + + This module also defines two shortcut functions: - + - call(*args, **kwargs): - Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - The arguments are the same as for the Popen constructor. Example: - + Run command with arguments. Wait for command to complete, + then return the returncode attribute. + + The arguments are the same as for the Popen constructor. + Example: + retcode = call(["ls", "-l"]) - - + + - callv(*args, **kwargs): - Run command with arguments. Wait for command to complete, then - return the returncode attribute. - - This function is identical to call(), except that each non-keyword - argument is treated as a program argument. Example: - + Run command with arguments. Wait for command to complete, + then return the returncode attribute. + + This function is identical to call(), except that each + non-keyword argument is treated as a program argument. + Example: + retcode = callv("ls", "-l") - + This is equivalent to: - + retcode = call(["ls", "-l"]) - - + + Exceptions ---------- + Exceptions raised in the child process, before the new program has started to execute, will be re-raised in the parent. Additionally, the exception object will have one extra attribute called 'child_traceback', which is a string containing traceback - information from the childs point of view. - + information from the child's point of view. + The most common exception raised is OSError. This occurs, for example, when trying to execute a non-existent file. Applications should prepare for OSErrors. - - A ValueError will be raised if Popen is called with invalid arguments. - - + + A ValueError will be raised if Popen is called with invalid + arguments. + + Security -------- - Unlike some other popen functions, this implementation will never call - /bin/sh implicitly. This means that all characters, including shell - metacharacters, can safely be passed to child processes. - - + + Unlike some other popen functions, this implementation will never + call /bin/sh implicitly. This means that all characters, + including shell meta-characters, can safely be passed to child + processes. + + Popen objects ------------- + Instances of the Popen class have the following methods: poll() Check if child process has terminated. Returns returncode attribute. - + wait() - Wait for child process to terminate. Returns returncode attribute. - + Wait for child process to terminate. Returns returncode + attribute. + communicate(input=None) Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for @@ -306,21 +328,22 @@ method if the data size is large or unlimited. The following attributes are also available: - + stdin If the stdin argument is PIPE, this attribute is a file object - that provides input to the child process. Otherwise, it is None. - - stdout - If the stdout argument is PIPE, this attribute is a file object - that provides output from the child process. Otherwise, it is + that provides input to the child process. Otherwise, it is None. - + + stdout + If the stdout argument is PIPE, this attribute is a file + object that provides output from the child process. + Otherwise, it is None. + stderr - If the stderr argument is PIPE, this attribute is file object that - provides error output from the child process. Otherwise, it is - None. - + If the stderr argument is PIPE, this attribute is file object + that provides error output from the child process. Otherwise, + it is None. + pid The process ID of the child process. @@ -328,14 +351,200 @@ The child return code. A None value indicates that the process hasn't terminated yet. A negative value -N indicates that the child was terminated by signal N (UNIX only). - - + + +Replacing older functions with the subprocess module + + In this section, "a ==> b" means that b can be used as a + replacement for a. + + Note: All functions in this section fail (more or less) silently + if the executed program cannot be found; this module raises an + OSError exception. + + In the following examples, we assume that the subprocess module is + imported with "from subprocess import *". + + + Replacing /bin/sh shell backquote + --------------------------------- + + output=`mycmd myarg` + ==> + output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] + + + Replacing shell pipe line + ------------------------- + + output=`dmesg | grep hda` + ==> + p1 = Popen(["dmesg"], stdout=PIPE) + p2 = Popen(["grep", "hda"], stdin=p1.stdout) + output = p2.communicate()[0] + + + Replacing os.system() + --------------------- + + sts = os.system("mycmd" + " myarg") + ==> + p = Popen(["mycmd" + " myarg"], shell=True) + sts = os.waitpid(p.pid, 0) + + Note: + + * Calling the program through the shell is usually not required. + + * It's easier to look at the returncode attribute than the + exit status. + + A more real-world example would look like this: + + try: + retcode = callv("mycmd", "myarg") + if retcode < 0: + print >>sys.stderr, "Child was terminated by signal", -retcode + else: + print >>sys.stderr, "Child returned", retcode + except OSError, e: + print >>sys.stderr, "Execution failed:", e + + + Replacing os.spawn* + ------------------- + + P_NOWAIT example: + + pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") + ==> + pid = Popen(["/bin/mycmd", "myarg"]).pid + + + P_WAIT example: + + retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") + ==> + retcode = callv("/bin/mycmd", "myarg") + + + Vector example: + + os.spawnvp(os.P_NOWAIT, path, args) + ==> + Popen([path] + args[1:]) + + + Environment example: + + os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) + ==> + Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) + + + Replacing os.popen* + ------------------- + + pipe = os.popen(cmd, mode='r', bufsize) + ==> + pipe = Popen([cmd], shell=True, bufsize=bufsize, stdout=PIPE).stdout + + pipe = os.popen(cmd, mode='w', bufsize) + ==> + pipe = Popen([cmd], shell=True, bufsize=bufsize, stdin=PIPE).stdin + + + (child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) + ==> + p = Popen([cmd], shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) + (child_stdin, child_stdout) = (p.stdin, p.stdout) + + + (child_stdin, + child_stdout, + child_stderr) = os.popen3(cmd, mode, bufsize) + ==> + p = Popen([cmd], shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) + (child_stdin, + child_stdout, + child_stderr) = (p.stdin, p.stdout, p.stderr) + + + (child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) + ==> + p = Popen([cmd], shell=True, bufsize=bufsize, + stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) + (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) + + + Replacing popen2.* + ------------------ + + Note: If the cmd argument to popen2 functions is a string, the + command is executed through /bin/sh. If it is a list, the command + is directly executed. + + (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) + ==> + p = Popen(["somestring"], shell=True, bufsize=bufsize + stdin=PIPE, stdout=PIPE, close_fds=True) + (child_stdout, child_stdin) = (p.stdout, p.stdin) + + + (child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) + ==> + p = Popen(["mycmd", "myarg"], bufsize=bufsize, + stdin=PIPE, stdout=PIPE, close_fds=True) + (child_stdout, child_stdin) = (p.stdout, p.stdin) + + The popen2.Popen3 and popen3.Popen4 basically works as + subprocess.Popen, except that: + + * subprocess.Popen raises an exception if the execution fails + * the capturestderr argument is replaced with the stderr argument. + * stdin=PIPE and stdout=PIPE must be specified. + * popen2 closes all file descriptors by default, but you have to + specify close_fds=True with subprocess.Popen. + + Open Issues - Currently, the reference implementation requires the "win32all" - extensions when running on the Windows platform. This dependency - could probably be eliminated by providing a small "glue" module - written in C, just like the _winreg module. + Some features have been requested but is not yet implemented. + This includes: + + * Support for managing a whole flock of subprocesses + + * Support for managing "daemon" processes + + * Built-in method for killing subprocesses + + While these are useful features, it's expected that these can be + added later without problems. + + * expect-like functionality, including pty support. + + pty support is highly platform-dependent, which is a + problem. Also, there are already other modules that provides this + kind of functionality[6]. + + +Backwards Compatibility + + Since this is a new module, no major backward compatible issues + are expected. The module name "subprocess" might collide with + other, previous modules[3] with the same name, but the name + "subprocess" seems to be the best suggested name so far. The + first name of this module was "popen5", but this name was + considered too unintuitive. For a while, the module was called + "process", but this name is already used by Trent Mick's + module[4]. + + The functions and modules that this new module is trying to + replace (os.system, os.spawn*, os.popen*, popen2.*, commands.*) + are expected to be available in future Python versions for a long + time, to preserve backwards compatibility. Reference Implementation @@ -352,6 +561,14 @@ [2] Python Dialog http://pythondialog.sourceforge.net/ + [3] http://www.iol.ie/~padraiga/libs/subProcess.py + + [4] http://starship.python.net/crew/tmick/ + + [5] http://starship.python.net/crew/mhammond/win32/ + + [6] http://www.lysator.liu.se/~ceder/pcl-expect/ + Copyright From akuchling at users.sourceforge.net Fri Oct 8 20:29:32 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Fri Oct 8 20:29:33 2004 Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew24.tex, 1.106, 1.107 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6599 Modified Files: whatsnew24.tex Log Message: [Bug #1031897] Fix order of decorator application Index: whatsnew24.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew24.tex,v retrieving revision 1.106 retrieving revision 1.107 diff -u -d -r1.106 -r1.107 --- whatsnew24.tex 7 Oct 2004 12:00:33 -0000 1.106 +++ whatsnew24.tex 8 Oct 2004 18:29:29 -0000 1.107 @@ -302,7 +302,7 @@ \begin{verbatim} def f(): ... -f = C(B(A(f))) +f = A(B(C(f))) \end{verbatim} Decorators must come on the line before a function definition, and @@ -364,7 +364,7 @@ \begin{verbatim} def f(): ... _deco = C(args) -f = _deco(B(A(f))) +f = A(B(_deco(f))) \end{verbatim} Getting this right can be slightly brain-bending, but it's not too @@ -1455,6 +1455,6 @@ The author would like to thank the following people for offering suggestions, corrections and assistance with various drafts of this -article: Hye-Shik Chang, Michael Dyck, Raymond Hettinger. +article: Hye-Shik Chang, Michael Dyck, Raymond Hettinger, Hamish Lawson. \end{document} From akuchling at users.sourceforge.net Fri Oct 8 20:34:50 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Fri Oct 8 20:34:52 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libsimplexmlrpc.tex, 1.6, 1.7 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8144 Modified Files: libsimplexmlrpc.tex Log Message: [Bug #1041501] Fix example code Index: libsimplexmlrpc.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libsimplexmlrpc.tex,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- libsimplexmlrpc.tex 3 Sep 2004 00:04:05 -0000 1.6 +++ libsimplexmlrpc.tex 8 Oct 2004 18:34:47 -0000 1.7 @@ -89,7 +89,7 @@ \begin{verbatim} class MyFuncs: - def div(self, x, y) : return div(x,y) + def div(self, x, y) : return x // y server = SimpleXMLRPCServer(("localhost", 8000)) From akuchling at users.sourceforge.net Fri Oct 8 20:35:49 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Fri Oct 8 20:35:51 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libsimplexmlrpc.tex, 1.5, 1.5.14.1 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8556 Modified Files: Tag: release23-maint libsimplexmlrpc.tex Log Message: [Bug #1041501] Fix example code Index: libsimplexmlrpc.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libsimplexmlrpc.tex,v retrieving revision 1.5 retrieving revision 1.5.14.1 diff -u -d -r1.5 -r1.5.14.1 --- libsimplexmlrpc.tex 17 Jan 2003 22:47:33 -0000 1.5 +++ libsimplexmlrpc.tex 8 Oct 2004 18:35:46 -0000 1.5.14.1 @@ -84,7 +84,7 @@ \begin{verbatim} class MyFuncs: - def div(self, x, y) : return div(x,y) + def div(self, x, y) : return x // y server = SimpleXMLRPCServer(("localhost", 8000)) From akuchling at users.sourceforge.net Fri Oct 8 20:49:01 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Fri Oct 8 20:49:05 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libcurses.tex,1.46,1.47 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11792 Modified Files: libcurses.tex Log Message: [Bug #1022311] curses module uses y,x ordering of arguments, not x,y Index: libcurses.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcurses.tex,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- libcurses.tex 7 Dec 2003 13:00:24 -0000 1.46 +++ libcurses.tex 8 Oct 2004 18:48:43 -0000 1.47 @@ -670,7 +670,7 @@ to reflect the current cursor position of the window. \end{methoddesc} -\begin{methoddesc}[window]{delch}{\optional{x, y}} +\begin{methoddesc}[window]{delch}{\optional{y, x}} Delete any character at \code{(\var{y}, \var{x})}. \end{methoddesc} @@ -708,14 +708,14 @@ corner. \end{methoddesc} -\begin{methoddesc}[window]{getch}{\optional{x, y}} +\begin{methoddesc}[window]{getch}{\optional{y, x}} Get a character. Note that the integer returned does \emph{not} have to be in \ASCII{} range: function keys, keypad keys and so on return numbers higher than 256. In no-delay mode, -1 is returned if there is no input. \end{methoddesc} -\begin{methoddesc}[window]{getkey}{\optional{x, y}} +\begin{methoddesc}[window]{getkey}{\optional{y, x}} Get a character, returning a string instead of an integer, as \method{getch()} does. Function keys, keypad keys and so on return a multibyte string containing the key name. In no-delay mode, an @@ -733,7 +733,7 @@ \code{-1,-1} if this window has no parent. \end{methoddesc} -\begin{methoddesc}[window]{getstr}{\optional{x, y}} +\begin{methoddesc}[window]{getstr}{\optional{y, x}} Read a string from the user, with primitive line editing capacity. \end{methoddesc} @@ -769,7 +769,7 @@ wrefresh. This option is disabled by default. \end{methoddesc} -\begin{methoddesc}[window]{inch}{\optional{x, y}} +\begin{methoddesc}[window]{inch}{\optional{y, x}} Return the character at the given position in the window. The bottom 8 bits are the character proper, and upper bits are the attributes. \end{methoddesc} From akuchling at users.sourceforge.net Fri Oct 8 20:56:42 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Fri Oct 8 20:56:46 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libcurses.tex, 1.42.8.2, 1.42.8.3 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14234 Modified Files: Tag: release23-maint libcurses.tex Log Message: [Bug #1022311] curses module uses y,x ordering of arguments, not x,y Index: libcurses.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcurses.tex,v retrieving revision 1.42.8.2 retrieving revision 1.42.8.3 diff -u -d -r1.42.8.2 -r1.42.8.3 --- libcurses.tex 7 Dec 2003 13:05:15 -0000 1.42.8.2 +++ libcurses.tex 8 Oct 2004 18:56:40 -0000 1.42.8.3 @@ -661,7 +661,7 @@ to reflect the current cursor position of the window. \end{methoddesc} -\begin{methoddesc}[window]{delch}{\optional{x, y}} +\begin{methoddesc}[window]{delch}{\optional{y, x}} Delete any character at \code{(\var{y}, \var{x})}. \end{methoddesc} @@ -699,14 +699,14 @@ corner. \end{methoddesc} -\begin{methoddesc}[window]{getch}{\optional{x, y}} +\begin{methoddesc}[window]{getch}{\optional{y, x}} Get a character. Note that the integer returned does \emph{not} have to be in \ASCII{} range: function keys, keypad keys and so on return numbers higher than 256. In no-delay mode, -1 is returned if there is no input. \end{methoddesc} -\begin{methoddesc}[window]{getkey}{\optional{x, y}} +\begin{methoddesc}[window]{getkey}{\optional{y, x}} Get a character, returning a string instead of an integer, as \method{getch()} does. Function keys, keypad keys and so on return a multibyte string containing the key name. In no-delay mode, an @@ -724,7 +724,7 @@ \code{-1,-1} if this window has no parent. \end{methoddesc} -\begin{methoddesc}[window]{getstr}{\optional{x, y}} +\begin{methoddesc}[window]{getstr}{\optional{y, x}} Read a string from the user, with primitive line editing capacity. \end{methoddesc} @@ -760,7 +760,7 @@ wrefresh. This option is disabled by default. \end{methoddesc} -\begin{methoddesc}[window]{inch}{\optional{x, y}} +\begin{methoddesc}[window]{inch}{\optional{y, x}} Return the character at the given position in the window. The bottom 8 bits are the character proper, and upper bits are the attributes. \end{methoddesc} From rhettinger at users.sourceforge.net Sat Oct 9 09:10:48 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat Oct 9 09:10:50 2004 Subject: [Python-checkins] python/dist/src/Lib decimal.py,1.25,1.26 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25485 Modified Files: decimal.py Log Message: SF patch #1043218 Simplify internal calls and logic for _fix() and _fixexponents(). (Contributed by Facundo Batista.) Index: decimal.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/decimal.py,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- decimal.py 27 Sep 2004 14:23:40 -0000 1.25 +++ decimal.py 9 Oct 2004 07:10:44 -0000 1.26 @@ -459,7 +459,7 @@ # (-1)**_sign * _int * 10**_exp # Special values are signified by _is_special == True - # We're immutable, so use _new__ not __init__ + # We're immutable, so use __new__ not __init__ def __new__(cls, value="0", context=None): """Create a decimal point instance. @@ -851,7 +851,7 @@ if context is None: context = getcontext() if context._rounding_decision == ALWAYS_ROUND: - return Decimal((sign, self._int, self._exp))._fix(context=context) + return Decimal((sign, self._int, self._exp))._fix(context) return Decimal( (sign, self._int, self._exp)) def __pos__(self, context=None): @@ -873,7 +873,7 @@ context = getcontext() if context._rounding_decision == ALWAYS_ROUND: - ans = self._fix(context=context) + ans = self._fix(context) else: ans = Decimal(self) ans._sign = sign @@ -943,14 +943,14 @@ exp = other._exp - context.prec-1 ans = other._rescale(exp, watchexp=0, context=context) if shouldround: - ans = ans._fix(context=context) + ans = ans._fix(context) return ans if not other: if exp < self._exp - context.prec-1: exp = self._exp - context.prec-1 ans = self._rescale(exp, watchexp=0, context=context) if shouldround: - ans = ans._fix(context=context) + ans = ans._fix(context) return ans op1 = _WorkRep(self) @@ -991,7 +991,7 @@ result.exp = op1.exp ans = Decimal(result) if shouldround: - ans = ans._fix(context=context) + ans = ans._fix(context) return ans __radd__ = __add__ @@ -1052,7 +1052,7 @@ if context is None: context = getcontext() if round and context._rounding_decision == ALWAYS_ROUND: - ans = ans._fix(context=context) + ans = ans._fix(context) return ans def __mul__(self, other, context=None): @@ -1090,19 +1090,19 @@ ans = Decimal((resultsign, (0,), resultexp)) if shouldround: #Fixing in case the exponent is out of bounds - ans = ans._fix(context=context) + ans = ans._fix(context) return ans # Special case for multiplying by power of 10 if self._int == (1,): ans = Decimal((resultsign, other._int, resultexp)) if shouldround: - ans = ans._fix(context=context) + ans = ans._fix(context) return ans if other._int == (1,): ans = Decimal((resultsign, self._int, resultexp)) if shouldround: - ans = ans._fix(context=context) + ans = ans._fix(context) return ans op1 = _WorkRep(self) @@ -1110,7 +1110,7 @@ ans = Decimal( (resultsign, map(int, str(op1.int * op2.int)), resultexp)) if shouldround: - ans = ans._fix(context=context) + ans = ans._fix(context) return ans __rmul__ = __mul__ @@ -1209,7 +1209,7 @@ exp = min(self._exp, other._exp) ans2 = self._rescale(exp, context=context, watchexp=0) if shouldround: - ans2 = ans2._fix(context=context) + ans2 = ans2._fix(context) return (Decimal( (sign, (0,), 0) ), ans2) @@ -1246,7 +1246,7 @@ watchexp=0) context._regard_flags(*frozen) if shouldround: - otherside = otherside._fix(context=context) + otherside = otherside._fix(context) return (Decimal(res), otherside) if op1.int == 0 and adjust >= 0 and not divmod: @@ -1286,7 +1286,7 @@ ans = Decimal(res) if shouldround: - ans = ans._fix(context=context) + ans = ans._fix(context) return ans def __rdiv__(self, other, context=None): @@ -1371,7 +1371,7 @@ r._sign, comparison._sign = s1, s2 #Get flags now self.__divmod__(other, context=context) - return r._fix(context=context) + return r._fix(context) r._sign, comparison._sign = s1, s2 rounding = context._set_rounding_decision(NEVER_ROUND) @@ -1402,7 +1402,7 @@ else: r._sign, comparison._sign = s1, s2 - return r._fix(context=context) + return r._fix(context) def __floordiv__(self, other, context=None): """self // other""" @@ -1441,44 +1441,31 @@ """ return long(self.__int__()) - def _fix(self, prec=None, rounding=None, folddown=None, context=None): + def _fix(self, context): """Round if it is necessary to keep self within prec precision. Rounds and fixes the exponent. Does not raise on a sNaN. Arguments: self - Decimal instance - prec - precision to which to round. By default, the context decides. - rounding - Rounding method. By default, the context decides. - folddown - Fold down high elements, by default context._clamp context - context used. """ if self._is_special: return self if context is None: context = getcontext() - if prec is None: - prec = context.prec - ans = Decimal(self) - ans = ans._fixexponents(prec, rounding, folddown=folddown, - context=context) + prec = context.prec + ans = self._fixexponents(prec, context) if len(ans._int) > prec: - ans = ans._round(prec, rounding, context=context) - ans = ans._fixexponents(prec, rounding, folddown=folddown, - context=context) + ans = ans._round(prec, context=context) + ans = ans._fixexponents(prec, context) return ans - def _fixexponents(self, prec=None, rounding=None, folddown=None, - context=None): - """Fix the exponents and return a copy with the exponent in bounds.""" - if self._is_special: - return self - if context is None: - context = getcontext() - if prec is None: - prec = context.prec - if folddown is None: - folddown = context._clamp + def _fixexponents(self, prec, context): + """Fix the exponents and return a copy with the exponent in bounds. + Only call if known to not be a special value. + """ + folddown = context._clamp Emin = context.Emin ans = Decimal(self) ans_adjusted = ans.adjusted() @@ -1756,7 +1743,7 @@ context.prec = firstprec if shouldround: - return val._fix(context=context) + return val._fix(context) return val def __rpow__(self, other, context=None): @@ -1772,7 +1759,7 @@ if ans: return ans - dup = self._fix(context=context) + dup = self._fix(context) if dup._isinfinity(): return dup @@ -1786,7 +1773,7 @@ return Decimal( (dup._sign, dup._int[:end], exp) ) - def quantize(self, exp, rounding = None, context=None, watchexp = 1): + def quantize(self, exp, rounding=None, context=None, watchexp=1): """Quantize self so its exponent is the same as that of exp. Similar to self._rescale(exp._exp) but with error checking. @@ -1817,7 +1804,7 @@ return self._isinfinity() and other._isinfinity() and True return self._exp == other._exp - def _rescale(self, exp, rounding = None, context=None, watchexp = 1): + def _rescale(self, exp, rounding=None, context=None, watchexp=1): """Rescales so that the exponent is exp. exp = exp to scale to (an integer) @@ -1848,13 +1835,13 @@ return ans diff = self._exp - exp - digits = len(self._int)+diff + digits = len(self._int) + diff if watchexp and digits > context.prec: return context._raise_error(InvalidOperation, 'Rescale > prec') tmp = Decimal(self) - tmp._int = (0,)+tmp._int + tmp._int = (0,) + tmp._int digits += 1 prevexact = context.flags[Inexact] @@ -1875,7 +1862,7 @@ return context._raise_error(InvalidOperation, 'rescale(a, INF)') return tmp - def to_integral(self, rounding = None, context=None): + def to_integral(self, rounding=None, context=None): """Rounds to the nearest integer, without raising inexact, rounded.""" if self._is_special: ans = self._check_nans(context=context) @@ -1991,7 +1978,7 @@ context.prec = firstprec context.rounding = rounding - ans = ans._fix(context=context) + ans = ans._fix(context) rounding = context._set_rounding_decision(NEVER_ROUND) if not ans.__mul__(ans, context=context) == self: @@ -2011,7 +1998,7 @@ context._regard_flags(flags) context.Emax, context.Emin = Emax, Emin - return ans._fix(context=context) + return ans._fix(context) def max(self, other, context=None): """Returns the larger value. @@ -2057,7 +2044,7 @@ if context is None: context = getcontext() context._rounding_decision == ALWAYS_ROUND - return ans._fix(context=context) + return ans._fix(context) def min(self, other, context=None): """Returns the smaller value. @@ -2103,7 +2090,7 @@ if context is None: context = getcontext() context._rounding_decision == ALWAYS_ROUND - return ans._fix(context=context) + return ans._fix(context) def _isinteger(self): """Returns whether self is an integer""" @@ -2316,7 +2303,7 @@ def create_decimal(self, num='0'): """Creates a new Decimal instance but using self as context.""" d = Decimal(num, context=self) - return d._fix(context=self) + return d._fix(self) #Methods def abs(self, a): @@ -2348,7 +2335,7 @@ return a.__add__(b, context=self) def _apply(self, a): - return str(a._fix(context=self)) + return str(a._fix(self)) def compare(self, a, b): """Compares values numerically. From jlgijsbers at users.sourceforge.net Sat Oct 9 17:52:07 2004 From: jlgijsbers at users.sourceforge.net (jlgijsbers@users.sourceforge.net) Date: Sat Oct 9 17:52:11 2004 Subject: [Python-checkins] python/dist/src/Doc/ref ref5.tex,1.83,1.84 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28806 Modified Files: ref5.tex Log Message: Patch #1042969: add closing brace for \token {generator_expression}. Thanks George Yoshida! Index: ref5.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref5.tex,v retrieving revision 1.83 retrieving revision 1.84 diff -u -d -r1.83 -r1.84 --- ref5.tex 15 Aug 2004 23:28:10 -0000 1.83 +++ ref5.tex 9 Oct 2004 15:52:04 -0000 1.84 @@ -55,7 +55,7 @@ {\token{identifier} | \token{literal} | \token{enclosure}} \production{enclosure} {\token{parenth_form} | \token{list_display}} - \productioncont{| \token{generator_expression | \token{dict_display}}} + \productioncont{| \token{generator_expression} | \token{dict_display}} \productioncont{| \token{string_conversion}} \end{productionlist} From rhettinger at users.sourceforge.net Sat Oct 9 18:02:21 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat Oct 9 18:02:23 2004 Subject: [Python-checkins] python/dist/src/Modules collectionsmodule.c, 1.33, 1.34 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30794 Modified Files: collectionsmodule.c Log Message: Simplify delitem() code by calling rotate() directly instead of using arguments passed through tuples. Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.33 retrieving revision 1.34 diff -u -d -r1.33 -r1.34 --- collectionsmodule.c 6 Oct 2004 17:51:54 -0000 1.33 +++ collectionsmodule.c 9 Oct 2004 16:02:18 -0000 1.34 @@ -310,17 +310,14 @@ PyDoc_STRVAR(extendleft_doc, "Extend the left side of the deque with elements from the iterable"); -static PyObject * -deque_rotate(dequeobject *deque, PyObject *args) +static int +_deque_rotate(dequeobject *deque, int n) { - int i, n=1, len=deque->len, halflen=(len+1)>>1; + int i, len=deque->len, halflen=(len+1)>>1; PyObject *item, *rv; - if (!PyArg_ParseTuple(args, "|i:rotate", &n)) - return NULL; - if (len == 0) - Py_RETURN_NONE; + return 0; if (n > halflen || n < -halflen) { n %= len; if (n > halflen) @@ -335,7 +332,7 @@ rv = deque_appendleft(deque, item); Py_DECREF(item); if (rv == NULL) - return NULL; + return -1; Py_DECREF(rv); } for (i=0 ; i>n ; i--) { @@ -344,10 +341,22 @@ rv = deque_append(deque, item); Py_DECREF(item); if (rv == NULL) - return NULL; + return -1; Py_DECREF(rv); } - Py_RETURN_NONE; + return 0; +} + +static PyObject * +deque_rotate(dequeobject *deque, PyObject *args) +{ + int n=1; + + if (!PyArg_ParseTuple(args, "|i:rotate", &n)) + return NULL; + if (_deque_rotate(deque, n) == 0) + Py_RETURN_NONE; + return NULL; } PyDoc_STRVAR(rotate_doc, @@ -424,38 +433,17 @@ static int deque_del_item(dequeobject *deque, int i) { - PyObject *item=NULL, *minus_i=NULL, *plus_i=NULL; - int rv = -1; + PyObject *item; assert (i >= 0 && i < deque->len); - - minus_i = Py_BuildValue("(i)", -i); - if (minus_i == NULL) - goto fail; - - plus_i = Py_BuildValue("(i)", i); - if (plus_i == NULL) - goto fail; - - item = deque_rotate(deque, minus_i); - if (item == NULL) - goto fail; - Py_DECREF(item); + if (_deque_rotate(deque, -i) == -1) + return -1; item = deque_popleft(deque, NULL); assert (item != NULL); Py_DECREF(item); - item = deque_rotate(deque, plus_i); - if (item == NULL) - goto fail; - - rv = 0; -fail: - Py_XDECREF(item); - Py_XDECREF(minus_i); - Py_XDECREF(plus_i); - return rv; + return _deque_rotate(deque, i); } static int From tim_one at users.sourceforge.net Sat Oct 9 19:25:07 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sat Oct 9 19:25:11 2004 Subject: [Python-checkins] python/dist/src/Python pystate.c,2.31,2.32 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15822/Python Modified Files: pystate.c Log Message: Trim trailing whitespace. Index: pystate.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pystate.c,v retrieving revision 2.31 retrieving revision 2.32 diff -u -d -r2.31 -r2.32 --- pystate.c 8 Jun 2004 08:17:44 -0000 2.31 +++ pystate.c 9 Oct 2004 17:25:05 -0000 2.32 @@ -271,7 +271,7 @@ _PyThreadState_Current = new; /* It should not be possible for more than one thread state - to be used for a thread. Check this the best we can in debug + to be used for a thread. Check this the best we can in debug builds. */ #if defined(Py_DEBUG) && defined(WITH_THREAD) @@ -385,8 +385,8 @@ static PyInterpreterState *autoInterpreterState = NULL; static int autoTLSkey = 0; -/* Internal initialization/finalization functions called by - Py_Initialize/Py_Finalize +/* Internal initialization/finalization functions called by + Py_Initialize/Py_Finalize */ void _PyGILState_Init(PyInterpreterState *i, PyThreadState *t) { @@ -418,8 +418,8 @@ { int current; PyThreadState *tcur; - /* Note that we do not auto-init Python here - apart from - potential races with 2 threads auto-initializing, pep-311 + /* Note that we do not auto-init Python here - apart from + potential races with 2 threads auto-initializing, pep-311 spells out other issues. Embedders are expected to have called Py_Initialize() and usually PyEval_InitThreads(). */ @@ -438,7 +438,7 @@ PyEval_RestoreThread(tcur); /* Update our counter in the thread-state - no need for locks: - tcur will remain valid as we hold the GIL. - - the counter is safe as we are the only thread "allowed" + - the counter is safe as we are the only thread "allowed" to modify this value */ tcur->gilstate_counter++; @@ -453,7 +453,7 @@ "but no thread-state for this thread"); /* We must hold the GIL and have our thread state current */ /* XXX - remove the check - the assert should be fine, - but while this is very new (April 2003), the extra check + but while this is very new (April 2003), the extra check by release-only users can't hurt. */ if (!PyThreadState_IsCurrent(tcur)) @@ -462,7 +462,7 @@ tcur->gilstate_counter -= 1; assert (tcur->gilstate_counter >= 0); /* illegal counter value */ - /* If we are about to destroy this thread-state, we must + /* If we are about to destroy this thread-state, we must clear it while the lock is held, as destructors may run */ if (tcur->gilstate_counter==0) { From tim_one at users.sourceforge.net Sat Oct 9 19:38:31 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sat Oct 9 19:38:34 2004 Subject: [Python-checkins] python/dist/src/Python pystate.c, 2.32, 2.33 thread.c, 2.51, 2.52 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18441/Python Modified Files: pystate.c thread.c Log Message: Style guide & consistency changes. No semantic changes. Index: pystate.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pystate.c,v retrieving revision 2.32 retrieving revision 2.33 diff -u -d -r2.32 -r2.33 --- pystate.c 9 Oct 2004 17:25:05 -0000 2.32 +++ pystate.c 9 Oct 2004 17:38:29 -0000 2.33 @@ -388,18 +388,20 @@ /* Internal initialization/finalization functions called by Py_Initialize/Py_Finalize */ -void _PyGILState_Init(PyInterpreterState *i, PyThreadState *t) +void +_PyGILState_Init(PyInterpreterState *i, PyThreadState *t) { - assert(i && t); /* must init with a valid states */ + assert(i && t); /* must init with valid states */ autoTLSkey = PyThread_create_key(); autoInterpreterState = i; /* Now stash the thread state for this thread in TLS */ PyThread_set_key_value(autoTLSkey, (void *)t); - assert(t->gilstate_counter==0); /* must be a new thread state */ + assert(t->gilstate_counter == 0); /* must be a new thread state */ t->gilstate_counter = 1; } -void _PyGILState_Fini(void) +void +_PyGILState_Fini(void) { PyThread_delete_key(autoTLSkey); autoTLSkey = 0; @@ -407,14 +409,16 @@ } /* The public functions */ -PyThreadState *PyGILState_GetThisThreadState(void) +PyThreadState * +PyGILState_GetThisThreadState(void) { - if (autoInterpreterState==NULL || autoTLSkey==0) + if (autoInterpreterState == NULL || autoTLSkey == 0) return NULL; - return (PyThreadState *) PyThread_get_key_value(autoTLSkey); + return (PyThreadState *)PyThread_get_key_value(autoTLSkey); } -PyGILState_STATE PyGILState_Ensure(void) +PyGILState_STATE +PyGILState_Ensure(void) { int current; PyThreadState *tcur; @@ -425,30 +429,32 @@ */ assert(autoInterpreterState); /* Py_Initialize() hasn't been called! */ tcur = PyThread_get_key_value(autoTLSkey); - if (tcur==NULL) { + if (tcur == NULL) { /* Create a new thread state for this thread */ tcur = PyThreadState_New(autoInterpreterState); - if (tcur==NULL) + if (tcur == NULL) Py_FatalError("Couldn't create thread-state for new thread"); PyThread_set_key_value(autoTLSkey, (void *)tcur); current = 0; /* new thread state is never current */ - } else + } + else current = PyThreadState_IsCurrent(tcur); - if (!current) + if (current == 0) PyEval_RestoreThread(tcur); /* Update our counter in the thread-state - no need for locks: - tcur will remain valid as we hold the GIL. - the counter is safe as we are the only thread "allowed" to modify this value */ - tcur->gilstate_counter++; + ++tcur->gilstate_counter; return current ? PyGILState_LOCKED : PyGILState_UNLOCKED; } -void PyGILState_Release(PyGILState_STATE oldstate) +void +PyGILState_Release(PyGILState_STATE oldstate) { PyThreadState *tcur = PyThread_get_key_value(autoTLSkey); - if (tcur==NULL) + if (tcur == NULL) Py_FatalError("auto-releasing thread-state, " "but no thread-state for this thread"); /* We must hold the GIL and have our thread state current */ @@ -456,27 +462,27 @@ but while this is very new (April 2003), the extra check by release-only users can't hurt. */ - if (!PyThreadState_IsCurrent(tcur)) + if (! PyThreadState_IsCurrent(tcur)) Py_FatalError("This thread state must be current when releasing"); - assert (PyThreadState_IsCurrent(tcur)); - tcur->gilstate_counter -= 1; - assert (tcur->gilstate_counter >= 0); /* illegal counter value */ + assert(PyThreadState_IsCurrent(tcur)); + --tcur->gilstate_counter; + assert(tcur->gilstate_counter >= 0); /* illegal counter value */ /* If we are about to destroy this thread-state, we must clear it while the lock is held, as destructors may run */ - if (tcur->gilstate_counter==0) { + if (tcur->gilstate_counter == 0) { /* can't have been locked when we created it */ - assert(oldstate==PyGILState_UNLOCKED); + assert(oldstate == PyGILState_UNLOCKED); PyThreadState_Clear(tcur); } /* Release the lock if necessary */ - if (oldstate==PyGILState_UNLOCKED) + if (oldstate == PyGILState_UNLOCKED) PyEval_ReleaseThread(tcur); /* Now complete destruction of the thread if necessary */ - if (tcur->gilstate_counter==0) { + if (tcur->gilstate_counter == 0) { /* Delete this thread from our TLS */ PyThread_delete_key_value(autoTLSkey); /* Delete the thread-state */ Index: thread.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/thread.c,v retrieving revision 2.51 retrieving revision 2.52 diff -u -d -r2.51 -r2.52 --- thread.c 16 Aug 2004 11:35:51 -0000 2.51 +++ thread.c 9 Oct 2004 17:38:29 -0000 2.52 @@ -157,7 +157,8 @@ static int nkeys = 0; static PyThread_type_lock keymutex = NULL; -static struct key *find_key(int key, void *value) +static struct key * +find_key(int key, void *value) { struct key *p; long id = PyThread_get_thread_ident(); @@ -180,14 +181,16 @@ return p; } -int PyThread_create_key(void) +int +PyThread_create_key(void) { if (keymutex == NULL) keymutex = PyThread_allocate_lock(); return ++nkeys; } -void PyThread_delete_key(int key) +void +PyThread_delete_key(int key) { struct key *p, **q; PyThread_acquire_lock(keymutex, 1); @@ -204,7 +207,8 @@ PyThread_release_lock(keymutex); } -int PyThread_set_key_value(int key, void *value) +int +PyThread_set_key_value(int key, void *value) { struct key *p = find_key(key, value); if (p == NULL) @@ -213,7 +217,8 @@ return 0; } -void *PyThread_get_key_value(int key) +void * +PyThread_get_key_value(int key) { struct key *p = find_key(key, NULL); if (p == NULL) @@ -222,7 +227,8 @@ return p->value; } -void PyThread_delete_key_value(int key) +void +PyThread_delete_key_value(int key) { long id = PyThread_get_thread_ident(); struct key *p, **q; From gvanrossum at users.sourceforge.net Sat Oct 9 19:43:07 2004 From: gvanrossum at users.sourceforge.net (gvanrossum@users.sourceforge.net) Date: Sat Oct 9 19:43:10 2004 Subject: [Python-checkins] python/dist/src/Modules readline.c, 2.64.6.3, 2.64.6.4 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19389 Modified Files: Tag: release23-maint readline.c Log Message: Make it ANSI C again. Index: readline.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/readline.c,v retrieving revision 2.64.6.3 retrieving revision 2.64.6.4 diff -u -d -r2.64.6.3 -r2.64.6.4 --- readline.c 20 Aug 2004 06:29:14 -0000 2.64.6.3 +++ readline.c 9 Oct 2004 17:43:03 -0000 2.64.6.4 @@ -655,15 +655,15 @@ static char * call_readline(FILE *sys_stdin, FILE *sys_stdout, char *prompt) { + size_t n; + char *p, *q; + PyOS_sighandler_t old_inthandler; #ifdef SAVE_LOCALE char *saved_locale = strdup(setlocale(LC_CTYPE, NULL)); if (!saved_locale) Py_FatalError("not enough memory to save locale"); setlocale(LC_CTYPE, ""); #endif - size_t n; - char *p, *q; - PyOS_sighandler_t old_inthandler; old_inthandler = PyOS_setsig(SIGINT, onintr); if (setjmp(jbuf)) { From bwarsaw at users.sourceforge.net Sat Oct 9 23:08:33 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sat Oct 9 23:08:37 2004 Subject: [Python-checkins] python/dist/src/Lib/email Charset.py,1.16,1.17 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29677 Modified Files: Charset.py Log Message: __init__(): Coerce the input_charset to unicode (with ascii encoding) before calling .lower() on it. This fixes the problem described in SF patch # 866982 where in the tr_TR.ISO-8859-9 locale, 'I'.lower() isn't 'i'. unicodes are locale insensitive. Index: Charset.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Charset.py,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- Charset.py 3 Oct 2004 03:16:18 -0000 1.16 +++ Charset.py 9 Oct 2004 21:08:30 -0000 1.17 @@ -185,8 +185,9 @@ this attribute will have the same value as the input_codec. """ def __init__(self, input_charset=DEFAULT_CHARSET): - # RFC 2046, $4.1.2 says charsets are not case sensitive - input_charset = input_charset.lower() + # RFC 2046, $4.1.2 says charsets are not case sensitive. We coerce to + # unicode because its .lower() is locale insensitive. + input_charset = unicode(input_charset, 'ascii').lower() # Set the input charset after filtering through the aliases self.input_charset = ALIASES.get(input_charset, input_charset) # We can try to guess which encoding and conversion to use by the From bwarsaw at users.sourceforge.net Sat Oct 9 23:33:27 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sat Oct 9 23:33:29 2004 Subject: [Python-checkins] python/dist/src/Doc/lib emailparser.tex, 1.8.16.1, 1.8.16.2 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2492 Modified Files: Tag: release23-maint emailparser.tex Log Message: Fix for SF bug # 1032960. Index: emailparser.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailparser.tex,v retrieving revision 1.8.16.1 retrieving revision 1.8.16.2 diff -u -d -r1.8.16.1 -r1.8.16.2 --- emailparser.tex 24 Feb 2004 20:57:30 -0000 1.8.16.1 +++ emailparser.tex 9 Oct 2004 21:33:24 -0000 1.8.16.2 @@ -50,12 +50,13 @@ arguments. The optional \var{strict} flag specifies whether strict or lax parsing -should be performed. Normally, when things like MIME terminating +should be performed. When things like MIME terminating boundaries are missing, or when messages contain other formatting problems, the \class{Parser} will raise a -\exception{MessageParseError}. However, when lax parsing is enabled, -the \class{Parser} will attempt to work around such broken formatting -to produce a usable message structure (this doesn't mean +\exception{MessageParseError}, if the \var{strict} flag is \code{True}. +However, when lax parsing is enabled (i.e. \var{strict} is \code{False}), +the \class{Parser} will attempt to work around such broken formatting to +produce a usable message structure (this doesn't mean \exception{MessageParseError}s are never raised; some ill-formatted messages just can't be parsed). The \var{strict} flag defaults to \code{False} since lax parsing usually provides the most convenient From bwarsaw at users.sourceforge.net Sat Oct 9 23:43:49 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sat Oct 9 23:43:53 2004 Subject: [Python-checkins] python/dist/src/Lib smtpd.py,1.13.16.1,1.13.16.2 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4324 Modified Files: Tag: release23-maint smtpd.py Log Message: Fix for SF bug # 1010102. The default is PureProxy not SMTPProxy. Index: smtpd.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/smtpd.py,v retrieving revision 1.13.16.1 retrieving revision 1.13.16.2 diff -u -d -r1.13.16.1 -r1.13.16.2 --- smtpd.py 12 Jul 2004 23:10:42 -0000 1.13.16.1 +++ smtpd.py 9 Oct 2004 21:43:47 -0000 1.13.16.2 @@ -17,7 +17,7 @@ --class classname -c classname - Use `classname' as the concrete SMTP proxy class. Uses `SMTPProxy' by + Use `classname' as the concrete SMTP proxy class. Uses `PureProxy' by default. --debug @@ -346,6 +346,7 @@ refused = self._deliver(mailfrom, rcpttos, data) # TBD: what to do with refused addresses? print >> DEBUGSTREAM, 'we got some refusals:', refused + return refused def _deliver(self, mailfrom, rcpttos, data): import smtplib From bwarsaw at users.sourceforge.net Sat Oct 9 23:44:15 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sat Oct 9 23:44:18 2004 Subject: [Python-checkins] python/dist/src/Lib smtpd.py,1.16,1.17 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4442 Modified Files: smtpd.py Log Message: Fix for SF bug # 1010102. The default is PureProxy not SMTPProxy. Index: smtpd.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/smtpd.py,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- smtpd.py 12 Jul 2004 23:10:08 -0000 1.16 +++ smtpd.py 9 Oct 2004 21:44:13 -0000 1.17 @@ -17,7 +17,7 @@ --class classname -c classname - Use `classname' as the concrete SMTP proxy class. Uses `SMTPProxy' by + Use `classname' as the concrete SMTP proxy class. Uses `PureProxy' by default. --debug From tim_one at users.sourceforge.net Sun Oct 10 00:33:12 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 10 00:33:14 2004 Subject: [Python-checkins] python/dist/src/Python thread.c,2.52,2.53 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14448/Python Modified Files: thread.c Log Message: Document the results of painful reverse-engineering of the "portable TLS" code. PyThread_set_key_value(): It's clear that this code assumes the passed-in value isn't NULL, so document that it must not be, and assert that it isn't. It remains unclear whether existing callers want the odd semantics actually implemented by this function. Index: thread.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/thread.c,v retrieving revision 2.52 retrieving revision 2.53 diff -u -d -r2.52 -r2.53 --- thread.c 9 Oct 2004 17:38:29 -0000 2.52 +++ thread.c 9 Oct 2004 22:33:09 -0000 2.53 @@ -142,26 +142,80 @@ This code stolen from "thread_sgi.h", where it was the only implementation of an existing Python TLS API. */ -/* - * Per-thread data ("key") support. - */ +/* ------------------------------------------------------------------------ +Per-thread data ("key") support. + +Use PyThread_create_key() to create a new key. This is typically shared +across threads. + +Use PyThread_set_key_value(thekey, value) to associate void* value with +thekey in the current thread. Each thread has a distinct mapping of thekey +to a void* value. Caution: if the current thread already has a mapping +for thekey, value is ignored. + +Use PyThread_get_key_value(thekey) to retrieve the void* value associated +with thekey in the current thread. This returns NULL if no value is +associated with thekey in the current thread. + +Use PyThread_delete_key_value(thekey) to forget the current thread's associated +value for thekey. PyThread_delete_key(thekey) forgets the values associated +with thekey across *all* threads. + +While some of these functions have error-return values, none set any +Python exception. + +None of the functions does memory management on behalf of the void* values. +You need to allocate and deallocate them yourself. If the void* values +happen to be PyObject*, these functions don't do refcount operations on +them either. + +The GIL does not need to be held when calling these functions; they supply +their own locking. This isn't true of PyThread_create_key(), though (see +next paragraph). +There's a hidden assumption that PyThread_create_key() will be called before +any of the other functions are called. There's also a hidden assumption +that calls to PyThread_create_key() are serialized externally. +------------------------------------------------------------------------ */ + +/* A singly-linked list of struct key objects remembers all the key->value + * associations. File static keyhead heads the list. keymutex is used + * to enforce exclusion internally. + */ struct key { + /* Next record in the list, or NULL if this is the last record. */ struct key *next; + + /* The thread id, according to PyThread_get_thread_ident(). */ long id; + + /* The key and its associated value. */ int key; void *value; }; static struct key *keyhead = NULL; -static int nkeys = 0; static PyThread_type_lock keymutex = NULL; +static int nkeys = 0; /* PyThread_create_key() hands out nkeys+1 next */ +/* Internal helper. + * If the current thread has a mapping for key, the appropriate struct key* + * is returned. NB: value is ignored in this case! + * If there is no mapping for key in the current thread, then: + * If value is NULL, NULL is returned. + * Else a mapping of key to value is created for the current thread, + * and a pointer to a new struct key* is returned; except that if + * malloc() can't find room for a new struct key*, NULL is returned. + * So when value==NULL, this acts like a pure lookup routine, and when + * value!=NULL, this acts like dict.setdefault(), returning an existing + * mapping if one exists, else creating a new mapping. + */ static struct key * find_key(int key, void *value) { struct key *p; long id = PyThread_get_thread_ident(); + for (p = keyhead; p != NULL; p = p->next) { if (p->id == id && p->key == key) return p; @@ -181,18 +235,27 @@ return p; } +/* Return a new key. This must be called before any other functions in + * this family, and callers must arrange to serialize calls to this + * function. No violations are detected. + */ int PyThread_create_key(void) { + /* All parts of this function are wrong if it's called by multiple + * threads simultaneously. + */ if (keymutex == NULL) keymutex = PyThread_allocate_lock(); return ++nkeys; } +/* Forget the associations for key across *all* threads. */ void PyThread_delete_key(int key) { struct key *p, **q; + PyThread_acquire_lock(keymutex, 1); q = &keyhead; while ((p = *q) != NULL) { @@ -207,31 +270,46 @@ PyThread_release_lock(keymutex); } +/* Confusing: If the current thread has an association for key, + * value is ignored, and 0 is returned. Else an attempt is made to create + * an association of key to value for the current thread. 0 is returned + * if that succeeds, but -1 is returned if there's not enough memory + * to create the association. value must not be NULL. + */ int PyThread_set_key_value(int key, void *value) { - struct key *p = find_key(key, value); + struct key *p; + + assert(value != NULL); + p = find_key(key, value); if (p == NULL) return -1; else return 0; } +/* Retrieve the value associated with key in the current thread, or NULL + * if the current thread doesn't have an association for key. + */ void * PyThread_get_key_value(int key) { struct key *p = find_key(key, NULL); + if (p == NULL) return NULL; else return p->value; } +/* Forget the current thread's association for key, if any. */ void PyThread_delete_key_value(int key) { long id = PyThread_get_thread_ident(); struct key *p, **q; + PyThread_acquire_lock(keymutex, 1); q = &keyhead; while ((p = *q) != NULL) { From tim_one at users.sourceforge.net Sun Oct 10 00:47:16 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 10 00:47:18 2004 Subject: [Python-checkins] python/dist/src/Python pystate.c,2.33,2.34 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17819/Python Modified Files: pystate.c Log Message: _PyGILState_Init(), PyGILState_Ensure(): Since PyThread_set_key_value() can fail, check its return value, and die if it does fail. _PyGILState_Init(): Assert that the thread doesn't already have an association for autoTLSkey. If it does, PyThread_set_key_value() will ignore the attempt to (re)set the association, which the code clearly doesn't want. Index: pystate.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pystate.c,v retrieving revision 2.33 retrieving revision 2.34 diff -u -d -r2.33 -r2.34 --- pystate.c 9 Oct 2004 17:38:29 -0000 2.33 +++ pystate.c 9 Oct 2004 22:47:13 -0000 2.34 @@ -395,7 +395,9 @@ autoTLSkey = PyThread_create_key(); autoInterpreterState = i; /* Now stash the thread state for this thread in TLS */ - PyThread_set_key_value(autoTLSkey, (void *)t); + assert(PyThread_get_key_value(autoTLSkey) == NULL); + if (PyThread_set_key_value(autoTLSkey, (void *)t) < 0) + Py_FatalError("Couldn't create autoTLSkey mapping"); assert(t->gilstate_counter == 0); /* must be a new thread state */ t->gilstate_counter = 1; } @@ -434,7 +436,8 @@ tcur = PyThreadState_New(autoInterpreterState); if (tcur == NULL) Py_FatalError("Couldn't create thread-state for new thread"); - PyThread_set_key_value(autoTLSkey, (void *)tcur); + if (PyThread_set_key_value(autoTLSkey, (void *)tcur) < 0) + Py_FatalError("Couldn't create autoTLSkey mapping"); current = 0; /* new thread state is never current */ } else From bwarsaw at users.sourceforge.net Sun Oct 10 00:57:36 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 10 00:57:39 2004 Subject: [Python-checkins] python/dist/src/Lib/email/test test_email.py, 1.62, 1.63 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20203 Modified Files: test_email.py Log Message: test_missing_start_boundary(): A test for SF bug # 1030941. Index: test_email.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/test/test_email.py,v retrieving revision 1.62 retrieving revision 1.63 diff -u -d -r1.62 -r1.63 --- test_email.py 3 Oct 2004 03:16:18 -0000 1.62 +++ test_email.py 9 Oct 2004 22:57:33 -0000 1.63 @@ -1420,6 +1420,21 @@ unless(isinstance(msg.defects[1], Errors.MultipartInvariantViolationDefect)) + def test_missing_start_boundary(self): + outer = self._msgobj('msg_42.txt') + # The message structure is: + # + # multipart/mixed + # text/plain + # message/rfc822 + # multipart/mixed [*] + # + # [*] This message is missing its start boundary + bad = outer.get_payload(1).get_payload(0) + self.assertEqual(len(bad.defects), 1) + self.failUnless(isinstance(bad.defects[0], + Errors.StartBoundaryNotFoundDefect)) + # Test RFC 2047 header encoding and decoding From bwarsaw at users.sourceforge.net Sun Oct 10 00:57:59 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 10 00:58:02 2004 Subject: [Python-checkins] python/dist/src/Lib/email/test/data msg_42.txt, NONE, 1.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email/test/data In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20325 Added Files: msg_42.txt Log Message: An example message for SF bug # 1030941. --- NEW FILE: msg_42.txt --- Content-Type: multipart/mixed; boundary="AAA" From: Mail Delivery Subsystem To: yyy@example.com This is a MIME-encapsulated message --AAA Stuff --AAA Content-Type: message/rfc822 From: webmaster@python.org To: zzz@example.com Content-Type: multipart/mixed; boundary="BBB" --BBB-- --AAA-- From tim_one at users.sourceforge.net Sun Oct 10 00:58:26 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 10 00:58:29 2004 Subject: [Python-checkins] python/nondist/peps pep-0311.txt,1.5,1.6 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20332 Modified Files: pep-0311.txt Log Message: Some function renamings were overlooked in the PEP; repair them. Index: pep-0311.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0311.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- pep-0311.txt 21 Apr 2003 15:20:13 -0000 1.5 +++ pep-0311.txt 9 Oct 2004 22:58:24 -0000 1.6 @@ -184,14 +184,14 @@ - remember the current state of the lock (owned/not owned) - If the current state does not own the GIL, acquire it. - Increment a counter for how many calls to - PyAutoThreadState_Ensure have been made on the current thread. + PyGILState_Ensure have been made on the current thread. - return - The general operation of PyAutoThreadState_Release() will be: + The general operation of PyGILState_Release() will be: - assert our thread currently holds the lock. - If old state indicates lock was previously unlocked, release GIL. - - Decrement the PyAutoThreadState_Ensure counter for the thread. + - Decrement the PyGILState_Ensure counter for the thread. - If counter == 0: - release and delete the PyThreadState. - forget the ThreadState as being owned by the thread. From bwarsaw at users.sourceforge.net Sun Oct 10 01:00:14 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 10 01:00:19 2004 Subject: [Python-checkins] python/dist/src/Lib/email FeedParser.py, 1.10, 1.11 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20785 Modified Files: FeedParser.py Log Message: Fix SF bug # 1030941. In _parsegen(), in the clause where we're capturing_preamble but we found a StartBoundaryNotFoundDefect, we need to consume all lines from the current position to the EOF, which we'll set as the epilogue of the current message. If we're not at EOF when we return from here, the outer message's capturing_preamble assertion will fail. Index: FeedParser.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/FeedParser.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- FeedParser.py 3 Oct 2004 03:16:18 -0000 1.10 +++ FeedParser.py 9 Oct 2004 23:00:11 -0000 1.11 @@ -309,8 +309,6 @@ if eolmo: preamble[-1] = lastline[:-len(eolmo.group(0))] self._cur.preamble = EMPTYSTRING.join(preamble) - #import pdb ; pdb.set_trace() - # See SF bug #1030941 capturing_preamble = False self._input.unreadline(line) continue @@ -367,10 +365,16 @@ # We've seen either the EOF or the end boundary. If we're still # capturing the preamble, we never saw the start boundary. Note # that as a defect and store the captured text as the payload. - # Otherwise everything from here to the EOF is epilogue. + # Everything from here to the EOF is epilogue. if capturing_preamble: self._cur.defects.append(Errors.StartBoundaryNotFoundDefect()) self._cur.set_payload(EMPTYSTRING.join(preamble)) + epilogue = [] + for line in self._input: + if line is NeedMoreData: + yield NeedMoreData + continue + self._cur.epilogue = EMPTYSTRING.join(epilogue) return # If the end boundary ended in a newline, we'll need to make sure # the epilogue isn't None From bwarsaw at users.sourceforge.net Sun Oct 10 01:01:14 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun Oct 10 01:01:16 2004 Subject: [Python-checkins] python/dist/src/Lib/email __init__.py,1.33,1.34 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21076 Modified Files: __init__.py Log Message: All known bugs are closed, and Python 2.4b1 is coming out soon, so bump email's version number to 3.0b1. Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/__init__.py,v retrieving revision 1.33 retrieving revision 1.34 diff -u -d -r1.33 -r1.34 --- __init__.py 3 Oct 2004 03:16:18 -0000 1.33 +++ __init__.py 9 Oct 2004 23:01:11 -0000 1.34 @@ -4,7 +4,7 @@ """A package for parsing, handling, and generating email messages.""" -__version__ = '3.0a0' +__version__ = '3.0b1' __all__ = [ 'base64MIME', From tim_one at users.sourceforge.net Sun Oct 10 01:55:39 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 10 01:55:42 2004 Subject: [Python-checkins] python/dist/src/Python pystate.c,2.34,2.35 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv337/Python Modified Files: pystate.c Log Message: PyGILState_Release(): If we need to delete the TLS entry for this thread, that must be done under protection of the GIL, for reasons explained in new comments. Index: pystate.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pystate.c,v retrieving revision 2.34 retrieving revision 2.35 diff -u -d -r2.34 -r2.35 --- pystate.c 9 Oct 2004 22:47:13 -0000 2.34 +++ pystate.c 9 Oct 2004 23:55:36 -0000 2.35 @@ -472,24 +472,31 @@ assert(tcur->gilstate_counter >= 0); /* illegal counter value */ /* If we are about to destroy this thread-state, we must - clear it while the lock is held, as destructors may run - */ + * clear it while the lock is held, as destructors may run. + * In addition, we have to delete out TLS entry, which is keyed + * by thread id, while the GIL is held: the thread calling us may + * go away, and a new thread may be created with the same thread + * id. If we don't delete our TLS until after the GIL is released, + * that new thread may manage to insert a TLS value with the same + * thread id as ours, and then we'd erroneously delete it. + */ if (tcur->gilstate_counter == 0) { /* can't have been locked when we created it */ assert(oldstate == PyGILState_UNLOCKED); PyThreadState_Clear(tcur); + /* Delete this thread from our TLS */ + PyThread_delete_key_value(autoTLSkey); } /* Release the lock if necessary */ if (oldstate == PyGILState_UNLOCKED) PyEval_ReleaseThread(tcur); - /* Now complete destruction of the thread if necessary */ - if (tcur->gilstate_counter == 0) { - /* Delete this thread from our TLS */ - PyThread_delete_key_value(autoTLSkey); - /* Delete the thread-state */ + /* Now complete destruction of the thread if necessary. This + * couldn't be done before PyEval_ReleaseThread() because + * PyThreadState_Delete doesn't allow deleting the current thread. + */ + if (tcur->gilstate_counter == 0) PyThreadState_Delete(tcur); - } } #endif /* WITH_THREAD */ From tim_one at users.sourceforge.net Sun Oct 10 03:58:49 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 10 03:58:52 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1154,1.1155 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22438/Misc Modified Files: NEWS Log Message: find_key(): This routine wasn't thread-correct, and accounts for the release-build failures noted in bug 1041645. This is a critical bugfix. I'm not going to backport it, though (no time). Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1154 retrieving revision 1.1155 diff -u -d -r1.1154 -r1.1155 --- NEWS 7 Oct 2004 06:46:24 -0000 1.1154 +++ NEWS 10 Oct 2004 01:58:39 -0000 1.1155 @@ -12,6 +12,11 @@ Core and builtins ----------------- +- The internal portable implementation of thread-local storage (TLS), used + by the ``PyGILState_Ensure()``/``PyGILState_Release()`` API, was not + thread-correct. This could lead to a variety of problems, up to and + including segfaults. See bug 1041645 for an example. + - Added a command line option, -m module, which searches sys.path for the module and then runs it. (Contributed by Nick Coghlan.) From tim_one at users.sourceforge.net Sun Oct 10 03:58:49 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 10 03:58:53 2004 Subject: [Python-checkins] python/dist/src/Python thread.c,2.53,2.54 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22438/Python Modified Files: thread.c Log Message: find_key(): This routine wasn't thread-correct, and accounts for the release-build failures noted in bug 1041645. This is a critical bugfix. I'm not going to backport it, though (no time). Index: thread.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/thread.c,v retrieving revision 2.53 retrieving revision 2.54 diff -u -d -r2.53 -r2.54 --- thread.c 9 Oct 2004 22:33:09 -0000 2.53 +++ thread.c 10 Oct 2004 01:58:44 -0000 2.54 @@ -209,6 +209,15 @@ * So when value==NULL, this acts like a pure lookup routine, and when * value!=NULL, this acts like dict.setdefault(), returning an existing * mapping if one exists, else creating a new mapping. + * + * Caution: this used to be too clever, trying to hold keymutex only + * around the "p->next = keyhead; keyhead = p" pair. That allowed + * another thread to mutate the list, via key deletion, concurrent with + * find_key() crawling over the list. Hilarity ensued. For example, when + * the for-loop here does "p = p->next", p could end up pointing at a + * record that PyThread_delete_key_value() was concurrently free()'ing. + * That could lead to anything, from failing to find a key that exists, to + * segfaults. Now we lock the whole routine. */ static struct key * find_key(int key, void *value) @@ -216,22 +225,25 @@ struct key *p; long id = PyThread_get_thread_ident(); + PyThread_acquire_lock(keymutex, 1); for (p = keyhead; p != NULL; p = p->next) { if (p->id == id && p->key == key) - return p; + goto Done; + } + if (value == NULL) { + assert(p == NULL); + goto Done; } - if (value == NULL) - return NULL; p = (struct key *)malloc(sizeof(struct key)); if (p != NULL) { p->id = id; p->key = key; p->value = value; - PyThread_acquire_lock(keymutex, 1); p->next = keyhead; keyhead = p; - PyThread_release_lock(keymutex); } + Done: + PyThread_release_lock(keymutex); return p; } From tim_one at users.sourceforge.net Sun Oct 10 04:47:36 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 10 04:47:38 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1155,1.1156 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30086/Misc Modified Files: NEWS Log Message: PyInterpreterState_New(), PyThreadState_New(): use malloc/free directly. This appears to finish repairs for SF bug 1041645. This is a critical bugfix. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1155 retrieving revision 1.1156 diff -u -d -r1.1155 -r1.1156 --- NEWS 10 Oct 2004 01:58:39 -0000 1.1155 +++ NEWS 10 Oct 2004 02:47:33 -0000 1.1156 @@ -136,6 +136,16 @@ C API ----- +- The C API calls ``PyInterpreterState_New()`` and ``PyThreadState_New()`` + are two of the very few advertised as being safe to call without holding + the GIL. However, this wasn't true in a debug build, as bug 1041645 + demonstrated. In a debug build, Python redirects the ``PyMem`` family + of calls to Python's small-object allocator, to get the benefit of + its extra debugging capabilities. But Python's small-object allocator + isn't threadsafe, relying on the GIL to avoid the expense of doing its + own locking. ``PyInterpreterState_New()`` and ``PyThreadState_New()`` + call the platform ``malloc()`` directly now, regardless of build type. + - PyLong_AsUnsignedLong[Mask] now support int objects as well. - SF patch #998993: ``PyUnicode_DecodeUTF8Stateful`` and From tim_one at users.sourceforge.net Sun Oct 10 04:47:36 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 10 04:47:39 2004 Subject: [Python-checkins] python/dist/src/Python pystate.c,2.35,2.36 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30086/Python Modified Files: pystate.c Log Message: PyInterpreterState_New(), PyThreadState_New(): use malloc/free directly. This appears to finish repairs for SF bug 1041645. This is a critical bugfix. Index: pystate.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pystate.c,v retrieving revision 2.35 retrieving revision 2.36 diff -u -d -r2.35 -r2.36 --- pystate.c 9 Oct 2004 23:55:36 -0000 2.35 +++ pystate.c 10 Oct 2004 02:47:33 -0000 2.36 @@ -3,6 +3,16 @@ #include "Python.h" +/* -------------------------------------------------------------------------- +CAUTION + +Always use malloc() and free() directly in this file. A number of these +functions are advertised as safe to call when the GIL isn't held, and in +a debug build Python redirects (e.g.) PyMem_NEW (etc) to Python's debugging +obmalloc functions. Those aren't thread-safe (they rely on the GIL to avoid +the expense of doing their own locking). +-------------------------------------------------------------------------- */ + #ifdef HAVE_DLOPEN #ifdef HAVE_DLFCN_H #include @@ -41,7 +51,8 @@ PyInterpreterState * PyInterpreterState_New(void) { - PyInterpreterState *interp = PyMem_NEW(PyInterpreterState, 1); + PyInterpreterState *interp = (PyInterpreterState *) + malloc(sizeof(PyInterpreterState)); if (interp != NULL) { HEAD_INIT(); @@ -119,7 +130,7 @@ Py_FatalError("PyInterpreterState_Delete: remaining threads"); *p = interp->next; HEAD_UNLOCK(); - PyMem_DEL(interp); + free(interp); } @@ -133,7 +144,8 @@ PyThreadState * PyThreadState_New(PyInterpreterState *interp) { - PyThreadState *tstate = PyMem_NEW(PyThreadState, 1); + PyThreadState *tstate = (PyThreadState *)malloc(sizeof(PyThreadState)); + if (_PyThreadState_GetFrame == NULL) _PyThreadState_GetFrame = threadstate_getframe; @@ -226,7 +238,7 @@ } *p = tstate->next; HEAD_UNLOCK(); - PyMem_DEL(tstate); + free(tstate); } From tim_one at users.sourceforge.net Sun Oct 10 07:30:43 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 10 07:30:45 2004 Subject: [Python-checkins] python/dist/src/Python pystate.c,2.36,2.37 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24384/Python Modified Files: pystate.c Log Message: Revert rev 2.35. It was based on erroneous reasoning -- the current thread's id can't get duplicated, because (of course!) the current thread is still running. The code should work either way, but reverting the gratuitous change should make backporting easier, and gets the bad reasoning out of 2.35's new comments. Index: pystate.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pystate.c,v retrieving revision 2.36 retrieving revision 2.37 diff -u -d -r2.36 -r2.37 --- pystate.c 10 Oct 2004 02:47:33 -0000 2.36 +++ pystate.c 10 Oct 2004 05:30:40 -0000 2.37 @@ -484,31 +484,24 @@ assert(tcur->gilstate_counter >= 0); /* illegal counter value */ /* If we are about to destroy this thread-state, we must - * clear it while the lock is held, as destructors may run. - * In addition, we have to delete out TLS entry, which is keyed - * by thread id, while the GIL is held: the thread calling us may - * go away, and a new thread may be created with the same thread - * id. If we don't delete our TLS until after the GIL is released, - * that new thread may manage to insert a TLS value with the same - * thread id as ours, and then we'd erroneously delete it. - */ + clear it while the lock is held, as destructors may run + */ if (tcur->gilstate_counter == 0) { /* can't have been locked when we created it */ assert(oldstate == PyGILState_UNLOCKED); PyThreadState_Clear(tcur); - /* Delete this thread from our TLS */ - PyThread_delete_key_value(autoTLSkey); } /* Release the lock if necessary */ if (oldstate == PyGILState_UNLOCKED) PyEval_ReleaseThread(tcur); - /* Now complete destruction of the thread if necessary. This - * couldn't be done before PyEval_ReleaseThread() because - * PyThreadState_Delete doesn't allow deleting the current thread. - */ - if (tcur->gilstate_counter == 0) + /* Now complete destruction of the thread if necessary */ + if (tcur->gilstate_counter == 0) { + /* Delete this thread from our TLS */ + PyThread_delete_key_value(autoTLSkey); + /* Delete the thread-state */ PyThreadState_Delete(tcur); + } } #endif /* WITH_THREAD */ From tim_one at users.sourceforge.net Mon Oct 11 04:40:52 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Mon Oct 11 04:40:55 2004 Subject: [Python-checkins] python/dist/src/PC/os2emx python24.def,1.1,1.2 Message-ID: Update of /cvsroot/python/python/dist/src/PC/os2emx In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23529/PC/os2emx Modified Files: python24.def Log Message: SF patch 1044089: New C API function PyEval_ThreadsInitialized(), by Nick Coghlan, for determining whether PyEval_InitThreads() has been called. Also purged the undocumented+unused _PyThread_Started int. Index: python24.def =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/os2emx/python24.def,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- python24.def 3 Oct 2004 08:11:30 -0000 1.1 +++ python24.def 11 Oct 2004 02:40:50 -0000 1.2 @@ -980,7 +980,6 @@ "Py_UseClassExceptionsFlag" "Py_UnicodeFlag" "_Py_QnewFlag" - "_PyThread_Started" ; From python24_s.lib(structmember) "PyMember_Get" From tim_one at users.sourceforge.net Mon Oct 11 04:40:52 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Mon Oct 11 04:40:56 2004 Subject: [Python-checkins] python/dist/src/PC/os2vacpp python.def,1.5,1.6 Message-ID: Update of /cvsroot/python/python/dist/src/PC/os2vacpp In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23529/PC/os2vacpp Modified Files: python.def Log Message: SF patch 1044089: New C API function PyEval_ThreadsInitialized(), by Nick Coghlan, for determining whether PyEval_InitThreads() has been called. Also purged the undocumented+unused _PyThread_Started int. Index: python.def =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/os2vacpp/python.def,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- python.def 29 Mar 2004 11:49:24 -0000 1.5 +++ python.def 11 Oct 2004 02:40:50 -0000 1.6 @@ -69,7 +69,6 @@ _PyImport_Inittab _PyParser_Grammar _PyParser_TokenNames - _PyThread_Started _Py_EllipsisObject _Py_NoneStruct _Py_PackageContext From tim_one at users.sourceforge.net Mon Oct 11 04:40:52 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Mon Oct 11 04:40:57 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1156,1.1157 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23529/Misc Modified Files: NEWS Log Message: SF patch 1044089: New C API function PyEval_ThreadsInitialized(), by Nick Coghlan, for determining whether PyEval_InitThreads() has been called. Also purged the undocumented+unused _PyThread_Started int. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1156 retrieving revision 1.1157 diff -u -d -r1.1156 -r1.1157 --- NEWS 10 Oct 2004 02:47:33 -0000 1.1156 +++ NEWS 11 Oct 2004 02:40:48 -0000 1.1157 @@ -136,6 +136,11 @@ C API ----- +- SF patch 1044089: New function ``PyEval_ThreadsInitialized()`` returns + non-zero if PyEval_InitThreads() has been called. + +- The undocumented and unused extern int ``_PyThread_Started`` was removed. + - The C API calls ``PyInterpreterState_New()`` and ``PyThreadState_New()`` are two of the very few advertised as being safe to call without holding the GIL. However, this wasn't true in a debug build, as bug 1041645 From tim_one at users.sourceforge.net Mon Oct 11 04:40:54 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Mon Oct 11 04:40:58 2004 Subject: [Python-checkins] python/dist/src/Python ceval.c, 2.417, 2.418 pythonrun.c, 2.209, 2.210 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23529/Python Modified Files: ceval.c pythonrun.c Log Message: SF patch 1044089: New C API function PyEval_ThreadsInitialized(), by Nick Coghlan, for determining whether PyEval_InitThreads() has been called. Also purged the undocumented+unused _PyThread_Started int. Index: ceval.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v retrieving revision 2.417 retrieving revision 2.418 diff -u -d -r2.417 -r2.418 --- ceval.c 16 Sep 2004 16:41:57 -0000 2.417 +++ ceval.c 11 Oct 2004 02:40:50 -0000 2.418 @@ -203,17 +203,20 @@ #endif #include "pythread.h" -extern int _PyThread_Started; /* Flag for Py_Exit */ - static PyThread_type_lock interpreter_lock = 0; /* This is the GIL */ static long main_thread = 0; +int +PyEval_ThreadsInitialized(void) +{ + return interpreter_lock != 0; +} + void PyEval_InitThreads(void) { if (interpreter_lock) return; - _PyThread_Started = 1; interpreter_lock = PyThread_allocate_lock(); PyThread_acquire_lock(interpreter_lock, 1); main_thread = PyThread_get_thread_ident(); Index: pythonrun.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pythonrun.c,v retrieving revision 2.209 retrieving revision 2.210 diff -u -d -r2.209 -r2.210 --- pythonrun.c 7 Oct 2004 03:58:07 -0000 2.209 +++ pythonrun.c 11 Oct 2004 02:40:51 -0000 2.210 @@ -1517,7 +1517,6 @@ #ifdef WITH_THREAD #include "pythread.h" -int _PyThread_Started = 0; /* Set by threadmodule.c and maybe others */ #endif #define NEXITFUNCS 32 From tim_one at users.sourceforge.net Mon Oct 11 04:41:08 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Mon Oct 11 04:41:10 2004 Subject: [Python-checkins] python/dist/src/Doc/api init.tex,1.20,1.21 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/api In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23529/Doc/api Modified Files: init.tex Log Message: SF patch 1044089: New C API function PyEval_ThreadsInitialized(), by Nick Coghlan, for determining whether PyEval_InitThreads() has been called. Also purged the undocumented+unused _PyThread_Started int. Index: init.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/api/init.tex,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- init.tex 19 Aug 2004 11:31:55 -0000 1.20 +++ init.tex 11 Oct 2004 02:40:35 -0000 1.21 @@ -24,7 +24,7 @@ \end{cfuncdesc} \begin{cfuncdesc}{void}{Py_InitializeEx}{int initsigs} - This function works like \cfunction{Py_Initialize} if + This function works like \cfunction{Py_Initialize()} if \var{initsigs} is 1. If \var{initsigs} is 0, it skips initialization registration of signal handlers, which might be useful when Python is embedded. \versionadded{2.4} @@ -517,14 +517,14 @@ This is a common situation (most Python programs do not use threads), and the lock operations slow the interpreter down a bit. Therefore, the lock is not created initially. This situation is - equivalent to having acquired the lock: when there is only a single + equivalent to having acquired the lock: when there is only a single thread, all object accesses are safe. Therefore, when this function initializes the lock, it also acquires it. Before the Python \module{thread}\refbimodindex{thread} module creates a new thread, knowing that either it has the lock or the lock hasn't been created yet, it calls \cfunction{PyEval_InitThreads()}. When this call - returns, it is guaranteed that the lock has been created and that it - has acquired it. + returns, it is guaranteed that the lock has been created and that the + calling thread has acquired it. It is \strong{not} safe to call this function when it is unknown which thread (if any) currently has the global interpreter lock. @@ -533,6 +533,14 @@ compile time. \end{cfuncdesc} +\begin{cfuncdesc}{int}{PyEval_ThreadsInitialized}{} + Returns a non-zero value if \cfunction{PyEval_InitThreads()} has been + called. This function can be called without holding the lock, and + therefore can be used to avoid calls to the locking API when running + single-threaded. This function is not available when thread support + is disabled at compile time. \versionadded{2.4} +\end{cfuncdesc} + \begin{cfuncdesc}{void}{PyEval_AcquireLock}{} Acquire the global interpreter lock. The lock must have been created earlier. If this thread already has the lock, a deadlock From tim_one at users.sourceforge.net Mon Oct 11 04:41:21 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Mon Oct 11 04:41:24 2004 Subject: [Python-checkins] python/dist/src/Include ceval.h,2.52,2.53 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23529/Include Modified Files: ceval.h Log Message: SF patch 1044089: New C API function PyEval_ThreadsInitialized(), by Nick Coghlan, for determining whether PyEval_InitThreads() has been called. Also purged the undocumented+unused _PyThread_Started int. Index: ceval.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/ceval.h,v retrieving revision 2.52 retrieving revision 2.53 diff -u -d -r2.52 -r2.53 --- ceval.h 27 Jun 2004 15:43:12 -0000 2.52 +++ ceval.h 11 Oct 2004 02:40:35 -0000 2.53 @@ -120,6 +120,7 @@ #ifdef WITH_THREAD +PyAPI_FUNC(int) PyEval_ThreadsInitialized(void); PyAPI_FUNC(void) PyEval_InitThreads(void); PyAPI_FUNC(void) PyEval_AcquireLock(void); PyAPI_FUNC(void) PyEval_ReleaseLock(void); From anthonybaxter at users.sourceforge.net Mon Oct 11 15:53:09 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Mon Oct 11 15:53:17 2004 Subject: [Python-checkins] python/dist/src/Doc/lib emailutil.tex,1.9,1.10 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26235/Doc/lib Modified Files: emailutil.tex Log Message: Added a usegmt flag to email.Utils.formatdate - this allows it to be used to replace rfc822.formatdate for protocols like HTTP (where 'GMT' must be the timezone string). Index: emailutil.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/emailutil.tex,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- emailutil.tex 3 Oct 2004 03:16:17 -0000 1.9 +++ emailutil.tex 11 Oct 2004 13:53:07 -0000 1.10 @@ -84,7 +84,7 @@ common use. \end{funcdesc} -\begin{funcdesc}{formatdate}{\optional{timeval\optional{, localtime}}} +\begin{funcdesc}{formatdate}{\optional{timeval\optional{, localtime}\optional{, usegmt}}} Returns a date string as per \rfc{2822}, e.g.: \begin{verbatim} @@ -99,6 +99,11 @@ \var{timeval}, and returns a date relative to the local timezone instead of UTC, properly taking daylight savings time into account. The default is \code{False} meaning UTC is used. + +Optional \var{usegmt} is a flag that when \code{True}, outputs a +date string with the timezone as an ascii string \code{GMT}, rather +than a numeric \code{-0000}. This is needed for some protocols (such +as HTTP). This only applies when \var{localtime} is \code{False} \end{funcdesc} \begin{funcdesc}{make_msgid}{\optional{idstring}} From anthonybaxter at users.sourceforge.net Mon Oct 11 15:53:10 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Mon Oct 11 15:53:20 2004 Subject: [Python-checkins] python/dist/src/Lib/email Utils.py,1.27,1.28 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26235/Lib/email Modified Files: Utils.py Log Message: Added a usegmt flag to email.Utils.formatdate - this allows it to be used to replace rfc822.formatdate for protocols like HTTP (where 'GMT' must be the timezone string). Index: Utils.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Utils.py,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- Utils.py 3 Oct 2004 03:16:18 -0000 1.27 +++ Utils.py 11 Oct 2004 13:53:07 -0000 1.28 @@ -103,7 +103,7 @@ -def formatdate(timeval=None, localtime=False): +def formatdate(timeval=None, localtime=False, usegmt=False): """Returns a date string as specified by RFC 2822, e.g.: Fri, 09 Nov 2001 01:08:47 -0000 @@ -114,6 +114,10 @@ Optional localtime is a flag that when True, interprets timeval, and returns a date relative to the local timezone instead of UTC, properly taking daylight savings time into account. + + Optional argument usegmt means that the timezone is written out as + an ascii string, not numeric one (so "GMT" instead of "+0000"). This + is needed for HTTP, and is only used when localtime==False. """ # Note: we cannot use strftime() because that honors the locale and RFC # 2822 requires that day and month names be the English abbreviations. @@ -138,7 +142,10 @@ else: now = time.gmtime(timeval) # Timezone offset is always -0000 - zone = '-0000' + if usegmt: + zone = 'GMT' + else: + zone = '-0000' return '%s, %02d %s %04d %02d:%02d:%02d %s' % ( ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][now[6]], now[2], From anthonybaxter at users.sourceforge.net Mon Oct 11 15:53:16 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Mon Oct 11 15:53:21 2004 Subject: [Python-checkins] python/dist/src/Lib/email/test test_email.py, 1.63, 1.64 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26235/Lib/email/test Modified Files: test_email.py Log Message: Added a usegmt flag to email.Utils.formatdate - this allows it to be used to replace rfc822.formatdate for protocols like HTTP (where 'GMT' must be the timezone string). Index: test_email.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/test/test_email.py,v retrieving revision 1.63 retrieving revision 1.64 diff -u -d -r1.63 -r1.64 --- test_email.py 9 Oct 2004 22:57:33 -0000 1.63 +++ test_email.py 11 Oct 2004 13:53:08 -0000 1.64 @@ -2037,6 +2037,15 @@ Utils.parsedate(Utils.formatdate(now, localtime=True))[:6], time.localtime(now)[:6]) + def test_formatdate_usegmt(self): + now = time.time() + self.assertEqual( + Utils.formatdate(now, localtime=False), + time.strftime('%a, %d %b %Y %H:%M:%S -0000', time.gmtime(now))) + self.assertEqual( + Utils.formatdate(now, localtime=False, usegmt=True), + time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime(now))) + def test_parsedate_none(self): self.assertEqual(Utils.parsedate(''), None) From anthonybaxter at users.sourceforge.net Mon Oct 11 15:53:16 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Mon Oct 11 15:53:22 2004 Subject: [Python-checkins] python/dist/src/Lib urllib.py, 1.164, 1.165 urllib2.py, 1.76, 1.77 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26235/Lib Modified Files: urllib.py urllib2.py Log Message: Added a usegmt flag to email.Utils.formatdate - this allows it to be used to replace rfc822.formatdate for protocols like HTTP (where 'GMT' must be the timezone string). Index: urllib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib.py,v retrieving revision 1.164 retrieving revision 1.165 diff -u -d -r1.164 -r1.165 --- urllib.py 18 Jul 2004 06:14:41 -0000 1.164 +++ urllib.py 11 Oct 2004 13:53:07 -0000 1.165 @@ -410,7 +410,7 @@ def open_local_file(self, url): """Use local file.""" - import mimetypes, mimetools, rfc822, StringIO + import mimetypes, mimetools, email.Utils, StringIO host, file = splithost(url) localname = url2pathname(file) try: @@ -418,7 +418,7 @@ except OSError, e: raise IOError(e.errno, e.strerror, e.filename) size = stats.st_size - modified = rfc822.formatdate(stats.st_mtime) + modified = email.Utils.formatdate(stats.st_mtime, usegmt=True) mtype = mimetypes.guess_type(url)[0] headers = mimetools.Message(StringIO.StringIO( 'Content-Type: %s\nContent-Length: %d\nLast-modified: %s\n' % Index: urllib2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib2.py,v retrieving revision 1.76 retrieving revision 1.77 diff -u -d -r1.76 -r1.77 --- urllib2.py 31 Aug 2004 11:38:12 -0000 1.76 +++ urllib2.py 11 Oct 2004 13:53:07 -0000 1.77 @@ -99,7 +99,6 @@ import posixpath import random import re -import rfc822 import sha import socket import sys @@ -1129,12 +1128,13 @@ # not entirely sure what the rules are here def open_local_file(self, req): + import email.Utils host = req.get_host() file = req.get_selector() localfile = url2pathname(file) stats = os.stat(localfile) size = stats.st_size - modified = rfc822.formatdate(stats.st_mtime) + modified = email.Utils.formatdate(stats.st_mtime, usegmt=True) mtype = mimetypes.guess_type(file)[0] headers = mimetools.Message(StringIO( 'Content-type: %s\nContent-length: %d\nLast-modified: %s\n' % From bwarsaw at users.sourceforge.net Mon Oct 11 16:32:51 2004 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Mon Oct 11 16:32:53 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1157,1.1158 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4365 Modified Files: NEWS Log Message: Added note about the new usegmt argument to email.Utils.formatdate(). Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1157 retrieving revision 1.1158 diff -u -d -r1.1157 -r1.1158 --- NEWS 11 Oct 2004 02:40:48 -0000 1.1157 +++ NEWS 11 Oct 2004 14:32:47 -0000 1.1158 @@ -50,6 +50,7 @@ Closes bug #1039270. - Updates for the email package: + + email.Utils.formatdate() grew a 'usegmt' argument for HTTP support. + All deprecated APIs that in email 2.x issued warnings have been removed: _encoder argument to the MIMEText constructor, Message.add_payload(), Utils.dump_address_pair(), Utils.decode(), Utils.encode() From mwh at users.sourceforge.net Mon Oct 11 17:34:34 2004 From: mwh at users.sourceforge.net (mwh@users.sourceforge.net) Date: Mon Oct 11 17:34:37 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_compiler.py, 1.8, 1.9 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17678 Modified Files: test_compiler.py Log Message: Open source files in universal newlines mode. Index: test_compiler.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_compiler.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- test_compiler.py 12 Sep 2004 03:49:31 -0000 1.8 +++ test_compiler.py 11 Oct 2004 15:34:31 -0000 1.9 @@ -24,7 +24,7 @@ path = os.path.join(dir, basename) if test.test_support.verbose: print "compiling", path - f = open(path) + f = open(path, "U") buf = f.read() f.close() if "badsyntax" in basename: From mwh at users.sourceforge.net Mon Oct 11 17:35:55 2004 From: mwh at users.sourceforge.net (mwh@users.sourceforge.net) Date: Mon Oct 11 17:35:59 2004 Subject: [Python-checkins] python/dist/src/Lib/compiler transformer.py, 1.47, 1.48 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/compiler In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17868 Modified Files: transformer.py Log Message: This is jiwon's patch to fix: [ 1042238 ] Lib/compiler chokes on certain genexps Index: transformer.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/compiler/transformer.py,v retrieving revision 1.47 retrieving revision 1.48 diff -u -d -r1.47 -r1.48 --- transformer.py 12 Sep 2004 03:49:30 -0000 1.47 +++ transformer.py 11 Oct 2004 15:35:53 -0000 1.48 @@ -1165,8 +1165,13 @@ if node[0] == token.STAR or node[0] == token.DOUBLESTAR: break kw, result = self.com_argument(node, kw) - if len_nodelist != 2 and isinstance(result, GenExpr): + + if len_nodelist != 2 and isinstance(result, GenExpr) \ + and len(node) == 3 and node[2][0] == symbol.gen_for: + # allow f(x for x in y), but reject f(x for x in y, 1) + # should use f((x for x in y), 1) instead of f(x for x in y, 1) raise SyntaxError, 'generator expression needs parenthesis' + args.append(result) else: # No broken by star arg, so skip the last one we processed. From jlgijsbers at users.sourceforge.net Mon Oct 11 20:12:24 2004 From: jlgijsbers at users.sourceforge.net (jlgijsbers@users.sourceforge.net) Date: Mon Oct 11 20:12:27 2004 Subject: [Python-checkins] python/dist/src/Lib os.py, 1.82, 1.83 popen2.py, 1.29, 1.30 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22303/Lib Modified Files: os.py popen2.py Log Message: Document that on Unix, the 'cmd' argument to the os.popen2/3/4 and popen2.popen2/3/4 functions can be a sequence. All texts are a variation on the following: On \UNIX, \var{cmd} may be a sequence, in which case arguments will be passed directly to the program without shell intervention (as with \function{os.spawnv()}). If \var{cmd} is a string it will be passed to the shell (as with \function{os.system()}). Index: os.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/os.py,v retrieving revision 1.82 retrieving revision 1.83 diff -u -d -r1.82 -r1.83 --- os.py 18 Sep 2004 16:07:58 -0000 1.82 +++ os.py 11 Oct 2004 18:12:15 -0000 1.83 @@ -611,6 +611,12 @@ if _exists("fork"): if not _exists("popen2"): def popen2(cmd, mode="t", bufsize=-1): + """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' + may be a sequence, in which case arguments will be passed directly to + the program without shell intervention (as with os.spawnv()). If 'cmd' + is a string it will be passed to the shell (as with os.system()). If + 'bufsize' is specified, it sets the buffer size for the I/O pipes. The + file objects (child_stdin, child_stdout) are returned.""" import popen2 stdout, stdin = popen2.popen2(cmd, bufsize) return stdin, stdout @@ -618,6 +624,12 @@ if not _exists("popen3"): def popen3(cmd, mode="t", bufsize=-1): + """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' + may be a sequence, in which case arguments will be passed directly to + the program without shell intervention (as with os.spawnv()). If 'cmd' + is a string it will be passed to the shell (as with os.system()). If + 'bufsize' is specified, it sets the buffer size for the I/O pipes. The + file objects (child_stdin, child_stdout, child_stderr) are returned.""" import popen2 stdout, stdin, stderr = popen2.popen3(cmd, bufsize) return stdin, stdout, stderr @@ -625,6 +637,12 @@ if not _exists("popen4"): def popen4(cmd, mode="t", bufsize=-1): + """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' + may be a sequence, in which case arguments will be passed directly to + the program without shell intervention (as with os.spawnv()). If 'cmd' + is a string it will be passed to the shell (as with os.system()). If + 'bufsize' is specified, it sets the buffer size for the I/O pipes. The + file objects (child_stdin, child_stdout_stderr) are returned.""" import popen2 stdout, stdin = popen2.popen4(cmd, bufsize) return stdin, stdout Index: popen2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/popen2.py,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- popen2.py 12 Feb 2004 17:35:06 -0000 1.29 +++ popen2.py 11 Oct 2004 18:12:20 -0000 1.30 @@ -30,10 +30,14 @@ def __init__(self, cmd, capturestderr=False, bufsize=-1): """The parameter 'cmd' is the shell command to execute in a - sub-process. The 'capturestderr' flag, if true, specifies that - the object should capture standard error output of the child process. - The default is false. If the 'bufsize' parameter is specified, it - specifies the size of the I/O buffers to/from the child process.""" + sub-process. On UNIX, 'cmd' may be a sequence, in which case arguments + will be passed directly to the program without shell intervention (as + with os.spawnv()). If 'cmd' is a string it will be passed to the shell + (as with os.system()). The 'capturestderr' flag, if true, specifies + that the object should capture standard error output of the child + process. The default is false. If the 'bufsize' parameter is + specified, it specifies the size of the I/O buffers to/from the child + process.""" _cleanup() p2cread, p2cwrite = os.pipe() c2pread, c2pwrite = os.pipe() @@ -120,44 +124,62 @@ del Popen3, Popen4 def popen2(cmd, bufsize=-1, mode='t'): - """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is - specified, it sets the buffer size for the I/O pipes. The file objects - (child_stdout, child_stdin) are returned.""" + """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may + be a sequence, in which case arguments will be passed directly to the + program without shell intervention (as with os.spawnv()). If 'cmd' is a + string it will be passed to the shell (as with os.system()). If + 'bufsize' is specified, it sets the buffer size for the I/O pipes. The + file objects (child_stdout, child_stdin) are returned.""" w, r = os.popen2(cmd, mode, bufsize) return r, w def popen3(cmd, bufsize=-1, mode='t'): - """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is - specified, it sets the buffer size for the I/O pipes. The file objects - (child_stdout, child_stdin, child_stderr) are returned.""" + """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may + be a sequence, in which case arguments will be passed directly to the + program without shell intervention (as with os.spawnv()). If 'cmd' is a + string it will be passed to the shell (as with os.system()). If + 'bufsize' is specified, it sets the buffer size for the I/O pipes. The + file objects (child_stdout, child_stdin, child_stderr) are returned.""" w, r, e = os.popen3(cmd, mode, bufsize) return r, w, e def popen4(cmd, bufsize=-1, mode='t'): - """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is - specified, it sets the buffer size for the I/O pipes. The file objects - (child_stdout_stderr, child_stdin) are returned.""" + """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may + be a sequence, in which case arguments will be passed directly to the + program without shell intervention (as with os.spawnv()). If 'cmd' is a + string it will be passed to the shell (as with os.system()). If + 'bufsize' is specified, it sets the buffer size for the I/O pipes. The + file objects (child_stdout_stderr, child_stdin) are returned.""" w, r = os.popen4(cmd, mode, bufsize) return r, w else: def popen2(cmd, bufsize=-1, mode='t'): - """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is - specified, it sets the buffer size for the I/O pipes. The file objects - (child_stdout, child_stdin) are returned.""" + """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may + be a sequence, in which case arguments will be passed directly to the + program without shell intervention (as with os.spawnv()). If 'cmd' is a + string it will be passed to the shell (as with os.system()). If + 'bufsize' is specified, it sets the buffer size for the I/O pipes. The + file objects (child_stdout, child_stdin) are returned.""" inst = Popen3(cmd, False, bufsize) return inst.fromchild, inst.tochild def popen3(cmd, bufsize=-1, mode='t'): - """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is - specified, it sets the buffer size for the I/O pipes. The file objects - (child_stdout, child_stdin, child_stderr) are returned.""" + """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may + be a sequence, in which case arguments will be passed directly to the + program without shell intervention (as with os.spawnv()). If 'cmd' is a + string it will be passed to the shell (as with os.system()). If + 'bufsize' is specified, it sets the buffer size for the I/O pipes. The + file objects (child_stdout, child_stdin, child_stderr) are returned.""" inst = Popen3(cmd, True, bufsize) return inst.fromchild, inst.tochild, inst.childerr def popen4(cmd, bufsize=-1, mode='t'): - """Execute the shell command 'cmd' in a sub-process. If 'bufsize' is - specified, it sets the buffer size for the I/O pipes. The file objects - (child_stdout_stderr, child_stdin) are returned.""" + """Execute the shell command 'cmd' in a sub-process. On UNIX, 'cmd' may + be a sequence, in which case arguments will be passed directly to the + program without shell intervention (as with os.spawnv()). If 'cmd' is a + string it will be passed to the shell (as with os.system()). If + 'bufsize' is specified, it sets the buffer size for the I/O pipes. The + file objects (child_stdout_stderr, child_stdin) are returned.""" inst = Popen4(cmd, bufsize) return inst.fromchild, inst.tochild From jlgijsbers at users.sourceforge.net Mon Oct 11 20:12:47 2004 From: jlgijsbers at users.sourceforge.net (jlgijsbers@users.sourceforge.net) Date: Mon Oct 11 20:12:50 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libos.tex, 1.142, 1.143 libpopen2.tex, 1.22, 1.23 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22303/Doc/lib Modified Files: libos.tex libpopen2.tex Log Message: Document that on Unix, the 'cmd' argument to the os.popen2/3/4 and popen2.popen2/3/4 functions can be a sequence. All texts are a variation on the following: On \UNIX, \var{cmd} may be a sequence, in which case arguments will be passed directly to the program without shell intervention (as with \function{os.spawnv()}). If \var{cmd} is a string it will be passed to the shell (as with \function{os.system()}). Index: libos.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libos.tex,v retrieving revision 1.142 retrieving revision 1.143 diff -u -d -r1.142 -r1.143 --- libos.tex 27 Sep 2004 19:54:32 -0000 1.142 +++ libos.tex 11 Oct 2004 18:12:13 -0000 1.143 @@ -361,6 +361,11 @@ objects should be opened in binary or text mode. The default value for \var{mode} is \code{'t'}. +Also, for each of these variants, on \UNIX, \var{cmd} may be a sequence, in +which case arguments will be passed directly to the program without shell +intervention (as with \function{os.spawnv()}). If \var{cmd} is a string it will +be passed to the shell (as with \function{os.system()}). + These methods do not make it possible to retrieve the return code from the child processes. The only way to control the input and output streams and also retrieve the return codes is to use the @@ -389,15 +394,14 @@ \begin{funcdesc}{popen4}{cmd\optional{, mode\optional{, bufsize}}} Executes \var{cmd} as a sub-process. Returns the file objects \code{(\var{child_stdin}, \var{child_stdout_and_stderr})}. +Availability: \UNIX, Windows. +\versionadded{2.0} +\end{funcdesc} (Note that \code{\var{child_stdin}, \var{child_stdout}, and \var{child_stderr}} are named from the point of view of the child process, i.e. \var{child_stdin} is the child's standard input.) -Availability: \UNIX, Windows. -\versionadded{2.0} -\end{funcdesc} - This functionality is also available in the \refmodule{popen2} module using functions of the same names, but the return values of those functions have a different order. Index: libpopen2.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libpopen2.tex,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- libpopen2.tex 9 Aug 2004 14:12:05 -0000 1.22 +++ libpopen2.tex 11 Oct 2004 18:12:14 -0000 1.23 @@ -24,6 +24,11 @@ in binary or text mode. The default value for \var{mode} is \code{'t'}. +On \UNIX, \var{cmd} may be a sequence, in which case arguments will be passed +directly to the program without shell intervention (as with +\function{os.spawnv()}). If \var{cmd} is a string it will be passed to the +shell (as with \function{os.system()}). + The only way to retrieve the return codes for the child processes is by using the \method{poll()} or \method{wait()} methods on the \class{Popen3} and \class{Popen4} classes; these are only available on @@ -75,7 +80,6 @@ \versionadded{2.0} \end{classdesc} - \subsection{Popen3 and Popen4 Objects \label{popen3-objects}} Instances of the \class{Popen3} and \class{Popen4} classes have the From akuchling at users.sourceforge.net Mon Oct 11 21:20:13 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Mon Oct 11 21:20:16 2004 Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew24.tex, 1.107, 1.108 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7907 Modified Files: whatsnew24.tex Log Message: Add two items Index: whatsnew24.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew24.tex,v retrieving revision 1.107 retrieving revision 1.108 diff -u -d -r1.107 -r1.108 --- whatsnew24.tex 8 Oct 2004 18:29:29 -0000 1.107 +++ whatsnew24.tex 11 Oct 2004 19:20:06 -0000 1.108 @@ -1230,6 +1230,14 @@ for options can now include the string \code{'\%default'}, which will be replaced by the option's default value. +\item The long-term plan is to deprecate the \module{rfc822} module +in some future Python release in favor of the \module{email} package. +To this end, the \function{email.Utils.formatdate()} function has been +changed to make it usable as a replacement for +\function{rfc822.formatdate()}. You may want to write new e-mail +processing code with this in mind. (Change implemented by Anthony +Baxter.) + \item A new \function{urandom(\var{n})} function was added to the \module{os} module, providing access to platform-specific sources of randomness such as @@ -1384,6 +1392,12 @@ its float or double argument \var{X} is a NaN. (Contributed by Tim Peters.) + \item C code can avoid unnecessary locking by using the new + \cfunction{PyEval_ThreadsInitialized()} function to tell + if any thread operations have been performed. If this function + returns false, no lock operations are needed. + (Contributed by Nick Coghlan.) + \item A new function, \cfunction{PyArg_VaParseTupleAndKeywords()}, is the same as \cfunction{PyArg_ParseTupleAndKeywords()} but takes a \ctype{va_list} instead of a number of arguments. From rhettinger at users.sourceforge.net Tue Oct 12 11:12:19 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue Oct 12 11:12:22 2004 Subject: [Python-checkins] python/dist/src/Lib decimal.py,1.26,1.27 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10275 Modified Files: decimal.py Log Message: Don't use mutable values for method defaults. Index: decimal.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/decimal.py,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- decimal.py 9 Oct 2004 07:10:44 -0000 1.26 +++ decimal.py 12 Oct 2004 09:12:16 -0000 1.27 @@ -2161,11 +2161,15 @@ """ def __init__(self, prec=None, rounding=None, - traps=None, flags=[], + traps=None, flags=None, _rounding_decision=None, Emin=None, Emax=None, capitals=None, _clamp=0, - _ignored_flags=[]): + _ignored_flags=None): + if flags is None: + flags = [] + if _ignored_flags is None: + _ignored_flags = [] if not isinstance(flags, dict): flags = dict([(s,s in flags) for s in _signals]) del s From effbot at users.sourceforge.net Tue Oct 12 17:26:29 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Tue Oct 12 17:26:32 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1158,1.1159 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24287/Misc Modified Files: NEWS Log Message: Added Peter Astrand's subprocess module. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1158 retrieving revision 1.1159 diff -u -d -r1.1158 -r1.1159 --- NEWS 11 Oct 2004 14:32:47 -0000 1.1158 +++ NEWS 12 Oct 2004 15:26:26 -0000 1.1159 @@ -44,6 +44,8 @@ Library ------- +- Added Peter Astrand's subprocess.py module. See PEP 327 for details. + - time.strptime() now properly escapes timezones and all other locale-specific strings for regex-specific symbols. Was breaking under Japanese Windows when the timezone was specified as "Tokyo (standard time)". From effbot at users.sourceforge.net Tue Oct 12 17:26:29 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Tue Oct 12 17:26:33 2004 Subject: [Python-checkins] python/dist/src/Lib subprocess.py,NONE,1.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24287/Lib Added Files: subprocess.py Log Message: Added Peter Astrand's subprocess module. --- NEW FILE: subprocess.py --- # subprocess - Subprocesses with accessible I/O streams # # For more information about this module, see PEP 324. # # Copyright (c) 2003-2004 by Peter Astrand # # By obtaining, using, and/or copying this software and/or its # associated documentation, you agree that you have read, understood, # and will comply with the following terms and conditions: # # Permission to use, copy, modify, and distribute this software and # its associated documentation for any purpose and without fee is # hereby granted, provided that the above copyright notice appears in # all copies, and that both that copyright notice and this permission # notice appear in supporting documentation, and that the name of the # author not be used in advertising or publicity pertaining to # distribution of the software without specific, written prior # permission. # [...1102 lines suppressed...] print "Looking for 'PROMPT' in set output..." p1 = Popen("set", stdout=PIPE, shell=True) p2 = Popen('find "PROMPT"', stdin=p1.stdout, stdout=PIPE) print repr(p2.communicate()[0]) # # Example 2: Simple execution of program # print "Executing calc..." p = Popen("calc") p.wait() if __name__ == "__main__": if mswindows: _demo_windows() else: _demo_posix() From effbot at users.sourceforge.net Tue Oct 12 17:26:30 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Tue Oct 12 17:26:36 2004 Subject: [Python-checkins] python/dist/src/Lib/test/output test_subprocess, NONE, 1.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test/output In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24287/Lib/test/output Added Files: test_subprocess Log Message: Added Peter Astrand's subprocess module. --- NEW FILE: test_subprocess --- test_subprocess ......... From effbot at users.sourceforge.net Tue Oct 12 17:26:31 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Tue Oct 12 17:26:36 2004 Subject: [Python-checkins] python/dist/src/PC _subprocess.c,NONE,1.1 Message-ID: Update of /cvsroot/python/python/dist/src/PC In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24287/PC Added Files: _subprocess.c Log Message: Added Peter Astrand's subprocess module. --- NEW FILE: _subprocess.c --- /* * support routines for subprocess module * * Currently, this extension module is only required when using the * subprocess module on Windows, but in the future, stubs for other * platforms might be added here as well. * * Copyright (c) 2004 by Fredrik Lundh * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com * Copyright (c) 2004 by Peter Astrand * * By obtaining, using, and/or copying this software and/or its * associated documentation, you agree that you have read, understood, * and will comply with the following terms and conditions: * * Permission to use, copy, modify, and distribute this software and * its associated documentation for any purpose and without fee is * hereby granted, provided that the above copyright notice appears in * all copies, and that both that copyright notice and this permission * notice appear in supporting documentation, and that the name of the * authors not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. * * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* TODO: handle unicode command lines? */ /* TODO: handle unicode environment? */ #include "Python.h" #define WINDOWS_LEAN_AND_MEAN #include "windows.h" /* -------------------------------------------------------------------- */ /* handle wrapper. note that this library uses integers when passing handles to a function, and handle wrappers when returning handles. the wrapper is used to provide Detach and Close methods */ typedef struct { PyObject_HEAD HANDLE handle; } sp_handle_object; staticforward PyTypeObject sp_handle_type; static PyObject* sp_handle_new(HANDLE handle) { sp_handle_object* self; self = PyObject_NEW(sp_handle_object, &sp_handle_type); if (self == NULL) return NULL; self->handle = handle; return (PyObject*) self; } static PyObject* sp_handle_detach(sp_handle_object* self, PyObject* args) { HANDLE handle; if (!PyArg_ParseTuple(args, ":Detach")) return NULL; handle = self->handle; self->handle = NULL; /* note: return the current handle, as an integer */ return PyInt_FromLong((long) handle); } static PyObject* sp_handle_close(sp_handle_object* self, PyObject* args) { if (!PyArg_ParseTuple(args, ":Close")) return NULL; if (self->handle != INVALID_HANDLE_VALUE) { CloseHandle(self->handle); self->handle = INVALID_HANDLE_VALUE; } Py_INCREF(Py_None); return Py_None; } static void sp_handle_dealloc(sp_handle_object* self) { if (self->handle != INVALID_HANDLE_VALUE) CloseHandle(self->handle); PyMem_DEL(self); } static PyMethodDef sp_handle_methods[] = { {"Detach", (PyCFunction) sp_handle_detach, 1}, {"Close", (PyCFunction) sp_handle_close, 1}, {NULL, NULL} }; static PyObject* sp_handle_getattr(sp_handle_object* self, char* name) { return Py_FindMethod(sp_handle_methods, (PyObject*) self, name); } static PyObject* sp_handle_as_int(sp_handle_object* self) { return PyInt_FromLong((long) self->handle); } static PyNumberMethods sp_handle_as_number; statichere PyTypeObject sp_handle_type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "_subprocess_handle", sizeof(sp_handle_object), 0, (destructor) sp_handle_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ (getattrfunc) sp_handle_getattr, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ &sp_handle_as_number, /*tp_as_number */ 0, /*tp_as_sequence */ 0, /*tp_as_mapping */ 0 /*tp_hash*/ }; /* -------------------------------------------------------------------- */ /* windows API functions */ static PyObject * sp_GetStdHandle(PyObject* self, PyObject* args) { HANDLE handle; int std_handle; if (!PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle)) return NULL; Py_BEGIN_ALLOW_THREADS handle = GetStdHandle((DWORD) std_handle); Py_END_ALLOW_THREADS if (handle == INVALID_HANDLE_VALUE) return PyErr_SetFromWindowsErr(GetLastError()); if (!handle) { Py_INCREF(Py_None); return Py_None; } /* note: returns integer, not handle object */ return PyInt_FromLong((long) handle); } static PyObject * sp_GetCurrentProcess(PyObject* self, PyObject* args) { if (!PyArg_ParseTuple(args, ":GetCurrentProcess")) return NULL; return sp_handle_new(GetCurrentProcess()); } static PyObject * sp_DuplicateHandle(PyObject* self, PyObject* args) { HANDLE target_handle; BOOL result; long source_process_handle; long source_handle; long target_process_handle; int desired_access; int inherit_handle; int options = 0; if (!PyArg_ParseTuple(args, "lllii|i:DuplicateHandle", &source_process_handle, &source_handle, &target_process_handle, &desired_access, &inherit_handle, &options)) return NULL; Py_BEGIN_ALLOW_THREADS result = DuplicateHandle( (HANDLE) source_process_handle, (HANDLE) source_handle, (HANDLE) target_process_handle, &target_handle, desired_access, inherit_handle, options ); Py_END_ALLOW_THREADS if (!result) return PyErr_SetFromWindowsErr(GetLastError()); return sp_handle_new(target_handle); } static PyObject * sp_CreatePipe(PyObject* self, PyObject* args) { HANDLE read_pipe; HANDLE write_pipe; BOOL result; PyObject* pipe_attributes; /* ignored */ int size; if (!PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size)) return NULL; Py_BEGIN_ALLOW_THREADS result = CreatePipe(&read_pipe, &write_pipe, NULL, size); Py_END_ALLOW_THREADS if (!result) return PyErr_SetFromWindowsErr(GetLastError()); return Py_BuildValue( "NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe) ); } /* helpers for createprocess */ static int getint(PyObject* obj, char* name) { PyObject* value; value = PyObject_GetAttrString(obj, name); if (!value) { PyErr_Clear(); /* FIXME: propagate error? */ return 0; } return (int) PyInt_AsLong(value); } static HANDLE gethandle(PyObject* obj, char* name) { sp_handle_object* value; value = (sp_handle_object*) PyObject_GetAttrString(obj, name); if (!value) { PyErr_Clear(); /* FIXME: propagate error? */ return NULL; } if (value->ob_type != &sp_handle_type) return NULL; return value->handle; } static PyObject* getenvironment(PyObject* environment) { int i, envsize; PyObject* out = NULL; PyObject* keys; PyObject* values; char* p; /* convert environment dictionary to windows enviroment string */ if (!PyMapping_Check(environment)) { PyErr_SetString( PyExc_TypeError, "environment must be dictionary or None" ); return NULL; } envsize = PyMapping_Length(environment); keys = PyMapping_Keys(environment); values = PyMapping_Values(environment); if (!keys || !values) goto error; out = PyString_FromStringAndSize(NULL, 2048); if (!out) goto error; p = PyString_AS_STRING(out); for (i = 0; i < envsize; i++) { int ksize, vsize, totalsize; PyObject* key = PyList_GET_ITEM(keys, i); PyObject* value = PyList_GET_ITEM(values, i); if (!PyString_Check(key) || !PyString_Check(value)) { PyErr_SetString( PyExc_TypeError, "environment can only contain strings" ); goto error; } ksize = PyString_GET_SIZE(key); vsize = PyString_GET_SIZE(value); totalsize = (p - PyString_AS_STRING(out)) + ksize + 1 + vsize + 1 + 1; if (totalsize > PyString_GET_SIZE(out)) { int offset = p - PyString_AS_STRING(out); _PyString_Resize(&out, totalsize + 1024); p = PyString_AS_STRING(out) + offset; } memcpy(p, PyString_AS_STRING(key), ksize); p += ksize; *p++ = '='; memcpy(p, PyString_AS_STRING(value), vsize); p += vsize; *p++ = '\0'; } /* add trailing null byte */ *p++ = '\0'; _PyString_Resize(&out, p - PyString_AS_STRING(out)); /* PyObject_Print(out, stdout, 0); */ return out; error: Py_XDECREF(out); Py_XDECREF(keys); Py_XDECREF(values); return NULL; } static PyObject * sp_CreateProcess(PyObject* self, PyObject* args) { BOOL result; PROCESS_INFORMATION pi; STARTUPINFO si; PyObject* environment; char* application_name; char* command_line; PyObject* process_attributes; /* ignored */ PyObject* thread_attributes; /* ignored */ int inherit_handles; int creation_flags; PyObject* env_mapping; char* current_directory; PyObject* startup_info; if (!PyArg_ParseTuple(args, "zzOOiiOzO:CreateProcess", &application_name, &command_line, &process_attributes, &thread_attributes, &inherit_handles, &creation_flags, &env_mapping, ¤t_directory, &startup_info)) return NULL; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); /* note: we only support a small subset of all SI attributes */ si.dwFlags = getint(startup_info, "dwFlags"); si.hStdInput = gethandle(startup_info, "hStdInput"); si.hStdOutput = gethandle(startup_info, "hStdOutput"); si.hStdError = gethandle(startup_info, "hStdError"); if (env_mapping == Py_None) environment = NULL; else { environment = getenvironment(env_mapping); if (!environment) return NULL; } Py_BEGIN_ALLOW_THREADS result = CreateProcess( application_name, command_line, NULL, NULL, inherit_handles, creation_flags, environment ? PyString_AS_STRING(environment) : NULL, current_directory, &si, &pi ); Py_END_ALLOW_THREADS Py_XDECREF(environment); if (!result) return PyErr_SetFromWindowsErr(GetLastError()); return Py_BuildValue( "NNii", sp_handle_new(pi.hProcess), sp_handle_new(pi.hThread), pi.dwProcessId, pi.dwThreadId ); } static PyObject * sp_GetExitCodeProcess(PyObject* self, PyObject* args) { DWORD exit_code; BOOL result; long process; if (!PyArg_ParseTuple(args, "l:GetExitCodeProcess", &process)) return NULL; result = GetExitCodeProcess((HANDLE) process, &exit_code); if (!result) return PyErr_SetFromWindowsErr(GetLastError()); return PyInt_FromLong(exit_code); } static PyObject * sp_WaitForSingleObject(PyObject* self, PyObject* args) { DWORD result; long handle; int milliseconds; if (!PyArg_ParseTuple(args, "li:WaitForSingleObject", &handle, &milliseconds)) return NULL; Py_BEGIN_ALLOW_THREADS result = WaitForSingleObject((HANDLE) handle, (DWORD) milliseconds); Py_END_ALLOW_THREADS if (result == WAIT_FAILED) return PyErr_SetFromWindowsErr(GetLastError()); return PyInt_FromLong((int) result); } static PyObject * sp_GetVersion(PyObject* self, PyObject* args) { if (!PyArg_ParseTuple(args, ":GetVersion")) return NULL; return PyInt_FromLong((int) GetVersion()); } static PyObject * sp_GetModuleFileName(PyObject* self, PyObject* args) { BOOL result; long module; TCHAR filename[MAX_PATH]; if (!PyArg_ParseTuple(args, "l:GetModuleFileName", &module)) return NULL; result = GetModuleFileName((HMODULE)module, filename, MAX_PATH); filename[MAX_PATH-1] = '\0'; if (!result) return PyErr_SetFromWindowsErr(GetLastError()); return PyString_FromString(filename); } static PyMethodDef sp_functions[] = { {"GetStdHandle", sp_GetStdHandle, METH_VARARGS}, {"GetCurrentProcess", sp_GetCurrentProcess, METH_VARARGS}, {"DuplicateHandle", sp_DuplicateHandle, METH_VARARGS}, {"CreatePipe", sp_CreatePipe, METH_VARARGS}, {"CreateProcess", sp_CreateProcess, METH_VARARGS}, {"GetExitCodeProcess", sp_GetExitCodeProcess, METH_VARARGS}, {"WaitForSingleObject", sp_WaitForSingleObject, METH_VARARGS}, {"GetVersion", sp_GetVersion, METH_VARARGS}, {"GetModuleFileName", sp_GetModuleFileName, METH_VARARGS}, {NULL, NULL} }; /* -------------------------------------------------------------------- */ static void defint(PyObject* d, const char* name, int value) { PyObject* v = PyInt_FromLong((long) value); if (v) { PyDict_SetItemString(d, (char*) name, v); Py_DECREF(v); } } #if PY_VERSION_HEX >= 0x02030000 PyMODINIT_FUNC #else DL_EXPORT(void) #endif init_subprocess() { PyObject *d; PyObject *m; /* patch up object descriptors */ sp_handle_type.ob_type = &PyType_Type; sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int; m = Py_InitModule("_subprocess", sp_functions); d = PyModule_GetDict(m); /* constants */ defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE); defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE); defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE); defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS); defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES); defint(d, "INFINITE", INFINITE); defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0); defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE); } From effbot at users.sourceforge.net Tue Oct 12 17:26:30 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Tue Oct 12 17:26:37 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, NONE, 1.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24287/Lib/test Added Files: test_subprocess.py Log Message: Added Peter Astrand's subprocess module. --- NEW FILE: test_subprocess.py --- import unittest from test import test_support import subprocess import sys import signal import os import tempfile import time mswindows = (sys.platform == "win32") # # Depends on the following external programs: Python # if mswindows: SETBINARY = 'import msvcrt; msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY);' else: SETBINARY = '' class ProcessTestCase(unittest.TestCase): def mkstemp(self): """wrapper for mkstemp, calling mktemp if mkstemp is not available""" if hasattr(tempfile, "mkstemp"): return tempfile.mkstemp() else: fname = tempfile.mktemp() return os.open(fname, os.O_RDWR|os.O_CREAT), fname # # Generic tests # def test_call_seq(self): """call() function with sequence argument""" rc = subprocess.call([sys.executable, "-c", "import sys; sys.exit(47)"]) self.assertEqual(rc, 47) def test_call_kwargs(self): """call() function with keyword args""" newenv = os.environ.copy() newenv["FRUIT"] = "banana" rc = subprocess.call([sys.executable, "-c", 'import sys, os;' \ 'sys.exit(os.getenv("FRUIT")=="banana")'], env=newenv) self.assertEqual(rc, 1) def test_stdin_none(self): """.stdin is None when not redirected""" p = subprocess.Popen([sys.executable, "-c", 'print "banana"'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.wait() self.assertEqual(p.stdin, None) def test_stdout_none(self): """.stdout is None when not redirected""" p = subprocess.Popen([sys.executable, "-c", 'print "banana"'], stdin=subprocess.PIPE, stderr=subprocess.PIPE) p.wait() self.assertEqual(p.stdout, None) def test_stderr_none(self): """.stderr is None when not redirected""" p = subprocess.Popen([sys.executable, "-c", 'print "banana"'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) p.wait() self.assertEqual(p.stderr, None) def test_executable(self): """executable""" p = subprocess.Popen(["somethingyoudonthave", "-c", "import sys; sys.exit(47)"], executable=sys.executable) p.wait() self.assertEqual(p.returncode, 47) def test_stdin_pipe(self): """stdin redirection""" p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.exit(sys.stdin.read() == "pear")'], stdin=subprocess.PIPE) p.stdin.write("pear") p.stdin.close() p.wait() self.assertEqual(p.returncode, 1) def test_stdin_filedes(self): """stdin is set to open file descriptor""" tf = tempfile.TemporaryFile() d = tf.fileno() os.write(d, "pear") os.lseek(d, 0, 0) p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.exit(sys.stdin.read() == "pear")'], stdin=d) p.wait() self.assertEqual(p.returncode, 1) def test_stdin_fileobj(self): """stdin is set to open file object""" tf = tempfile.TemporaryFile() tf.write("pear") tf.seek(0) p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.exit(sys.stdin.read() == "pear")'], stdin=tf) p.wait() self.assertEqual(p.returncode, 1) def test_stdout_pipe(self): """stdout redirection""" p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stdout.write("orange")'], stdout=subprocess.PIPE) self.assertEqual(p.stdout.read(), "orange") def test_stdout_filedes(self): """stdout is set to open file descriptor""" tf = tempfile.TemporaryFile() d = tf.fileno() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stdout.write("orange")'], stdout=d) p.wait() os.lseek(d, 0, 0) self.assertEqual(os.read(d, 1024), "orange") def test_stdout_fileobj(self): """stdout is set to open file object""" tf = tempfile.TemporaryFile() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stdout.write("orange")'], stdout=tf) p.wait() tf.seek(0) self.assertEqual(tf.read(), "orange") def test_stderr_pipe(self): """stderr redirection""" p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stderr.write("strawberry")'], stderr=subprocess.PIPE) self.assertEqual(p.stderr.read(), "strawberry") def test_stderr_filedes(self): """stderr is set to open file descriptor""" tf = tempfile.TemporaryFile() d = tf.fileno() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stderr.write("strawberry")'], stderr=d) p.wait() os.lseek(d, 0, 0) self.assertEqual(os.read(d, 1024), "strawberry") def test_stderr_fileobj(self): """stderr is set to open file object""" tf = tempfile.TemporaryFile() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stderr.write("strawberry")'], stderr=tf) p.wait() tf.seek(0) self.assertEqual(tf.read(), "strawberry") def test_stdout_stderr_pipe(self): """capture stdout and stderr to the same pipe""" p = subprocess.Popen([sys.executable, "-c", 'import sys;' \ 'sys.stdout.write("apple");' \ 'sys.stdout.flush();' \ 'sys.stderr.write("orange")'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) self.assertEqual(p.stdout.read(), "appleorange") def test_stdout_stderr_file(self): """capture stdout and stderr to the same open file""" tf = tempfile.TemporaryFile() p = subprocess.Popen([sys.executable, "-c", 'import sys;' \ 'sys.stdout.write("apple");' \ 'sys.stdout.flush();' \ 'sys.stderr.write("orange")'], stdout=tf, stderr=tf) p.wait() tf.seek(0) self.assertEqual(tf.read(), "appleorange") def test_cwd(self): """cwd""" tmpdir = os.getenv("TEMP", "/tmp") tmpdir = os.path.realpath(tmpdir) p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stdout.write(os.getcwd())'], stdout=subprocess.PIPE, cwd=tmpdir) self.assertEqual(p.stdout.read(), tmpdir) def test_env(self): """env""" newenv = os.environ.copy() newenv["FRUIT"] = "orange" p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stdout.write(os.getenv("FRUIT"))'], stdout=subprocess.PIPE, env=newenv) self.assertEqual(p.stdout.read(), "orange") def test_communicate(self): """communicate()""" p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stderr.write("pineapple");' \ 'sys.stdout.write(sys.stdin.read())'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) (stdout, stderr) = p.communicate("banana") self.assertEqual(stdout, "banana") self.assertEqual(stderr, "pineapple") def test_communicate_returns(self): """communicate() should return None if no redirection is active""" p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(47)"]) (stdout, stderr) = p.communicate() self.assertEqual(stdout, None) self.assertEqual(stderr, None) def test_communicate_pipe_buf(self): """communicate() with writes larger than pipe_buf""" # This test will probably deadlock rather than fail, if # communicate() does not work properly. x, y = os.pipe() if mswindows: pipe_buf = 512 else: pipe_buf = os.fpathconf(x, "PC_PIPE_BUF") os.close(x) os.close(y) p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' 'sys.stdout.write(sys.stdin.read(47));' \ 'sys.stderr.write("xyz"*%d);' \ 'sys.stdout.write(sys.stdin.read())' % pipe_buf], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) string_to_write = "abc"*pipe_buf (stdout, stderr) = p.communicate(string_to_write) self.assertEqual(stdout, string_to_write) def test_writes_before_communicate(self): """stdin.write before communicate()""" p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stdout.write(sys.stdin.read())'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.stdin.write("banana") (stdout, stderr) = p.communicate("split") self.assertEqual(stdout, "bananasplit") self.assertEqual(stderr, "") def test_universal_newlines(self): """universal newlines""" p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' + SETBINARY + \ 'sys.stdout.write("line1\\n");' \ 'sys.stdout.flush();' \ 'sys.stdout.write("line2\\r");' \ 'sys.stdout.flush();' \ 'sys.stdout.write("line3\\r\\n");' \ 'sys.stdout.flush();' \ 'sys.stdout.write("line4\\r");' \ 'sys.stdout.flush();' \ 'sys.stdout.write("\\nline5");' 'sys.stdout.flush();' \ 'sys.stdout.write("\\nline6");'], stdout=subprocess.PIPE, universal_newlines=1) stdout = p.stdout.read() if hasattr(open, 'newlines'): # Interpreter with universal newline support self.assertEqual(stdout, "line1\nline2\nline3\nline4\nline5\nline6") else: # Interpreter without universal newline support self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6") def test_universal_newlines_communicate(self): """universal newlines through communicate()""" p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' + SETBINARY + \ 'sys.stdout.write("line1\\n");' \ 'sys.stdout.flush();' \ 'sys.stdout.write("line2\\r");' \ 'sys.stdout.flush();' \ 'sys.stdout.write("line3\\r\\n");' \ 'sys.stdout.flush();' \ 'sys.stdout.write("line4\\r");' \ 'sys.stdout.flush();' \ 'sys.stdout.write("\\nline5");' 'sys.stdout.flush();' \ 'sys.stdout.write("\\nline6");'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=1) (stdout, stderr) = p.communicate() if hasattr(open, 'newlines'): # Interpreter with universal newline support self.assertEqual(stdout, "line1\nline2\nline3\nline4\nline5\nline6") else: # Interpreter without universal newline support self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6") def test_no_leaking(self): """Make sure we leak no resources""" for i in range(1026): p = subprocess.Popen([sys.executable, "-c", "import sys;sys.stdout.write(sys.stdin.read())"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) data = p.communicate("lime")[0] self.assertEqual(data, "lime") def test_list2cmdline(self): """list2cmdline""" self.assertEqual(subprocess.list2cmdline(['a b c', 'd', 'e']), '"a b c" d e') self.assertEqual(subprocess.list2cmdline(['ab"c', '\\', 'd']), 'ab\\"c \\ d') self.assertEqual(subprocess.list2cmdline(['a\\\\\\b', 'de fg', 'h']), 'a\\\\\\b "de fg" h') self.assertEqual(subprocess.list2cmdline(['a\\"b', 'c', 'd']), 'a\\\\\\"b c d') self.assertEqual(subprocess.list2cmdline(['a\\\\b c', 'd', 'e']), '"a\\\\b c" d e') self.assertEqual(subprocess.list2cmdline(['a\\\\b\\ c', 'd', 'e']), '"a\\\\b\\ c" d e') def test_poll(self): """poll""" p = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(4)"]) while p.poll() == None: sys.stdout.write(".") sys.stdout.flush() time.sleep(0.5) # Subsequent invocations should just return the returncode self.assertEqual(p.poll(), 0) def test_wait(self): """wait""" p = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(2)"]) self.assertEqual(p.wait(), 0) # Subsequent invocations should just return the returncode self.assertEqual(p.wait(), 0) # # POSIX tests # if not mswindows: def test_exceptions(self): """catched & re-raised exceptions""" try: p = subprocess.Popen([sys.executable, "-c", ""], cwd="/this/path/does/not/exist") except OSError, e: # The attribute child_traceback should contain "os.chdir" # somewhere. self.assertNotEqual(e.child_traceback.find("os.chdir"), -1) else: self.fail("Expected OSError") def test_run_abort(self): """returncode handles signal termination""" p = subprocess.Popen([sys.executable, "-c", "import os; os.abort()"]) p.wait() self.assertEqual(-p.returncode, signal.SIGABRT) def test_preexec(self): """preexec function""" p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stdout.write(os.getenv("FRUIT"))'], stdout=subprocess.PIPE, preexec_fn=lambda: os.putenv("FRUIT", "apple")) self.assertEqual(p.stdout.read(), "apple") def test_close_fds(self): """close_fds""" # Make sure we have some fds open os.pipe() p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stdout.write(str(os.dup(0)))'], stdout=subprocess.PIPE, close_fds=1) # When all fds are closed, the next free fd should be 3. self.assertEqual(p.stdout.read(), "3") def test_args_string(self): """args is a string""" f, fname = self.mkstemp() os.write(f, "#!/bin/sh\n") os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % sys.executable) os.close(f) os.chmod(fname, 0700) p = subprocess.Popen(fname) p.wait() self.assertEqual(p.returncode, 47) os.remove(fname) def test_invalid_args(self): """invalid arguments should raise ValueError""" self.assertRaises(ValueError, subprocess.call, [sys.executable, "-c", "import sys; sys.exit(47)"], startupinfo=47) self.assertRaises(ValueError, subprocess.call, [sys.executable, "-c", "import sys; sys.exit(47)"], creationflags=47) def test_shell_sequence(self): """Run command through the shell (sequence)""" newenv = os.environ.copy() newenv["FRUIT"] = "apple" p = subprocess.Popen(["echo $FRUIT"], shell=1, stdout=subprocess.PIPE, env=newenv) self.assertEqual(p.stdout.read().strip(), "apple") def test_shell_string(self): """Run command through the shell (string)""" newenv = os.environ.copy() newenv["FRUIT"] = "apple" p = subprocess.Popen("echo $FRUIT", shell=1, stdout=subprocess.PIPE, env=newenv) self.assertEqual(p.stdout.read().strip(), "apple") def test_call_string(self): """call() function with string argument on UNIX""" f, fname = self.mkstemp() os.write(f, "#!/bin/sh\n") os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % sys.executable) os.close(f) os.chmod(fname, 0700) rc = subprocess.call(fname) self.assertEqual(rc, 47) # # Windows tests # if mswindows: def test_startupinfo(self): """startupinfo argument""" # We uses hardcoded constants, because we do not want to # depend on win32all. STARTF_USESHOWWINDOW = 1 SW_MAXIMIZE = 3 startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags = STARTF_USESHOWWINDOW startupinfo.wShowWindow = SW_MAXIMIZE # Since Python is a console process, it won't be affected # by wShowWindow, but the argument should be silently # ignored subprocess.call([sys.executable, "-c", "import sys; sys.exit(0)"], startupinfo=startupinfo) def test_creationflags(self): """creationflags argument""" CREATE_NEW_CONSOLE = 16 subprocess.call(sys.executable + ' -c "import time; time.sleep(2)"', creationflags=CREATE_NEW_CONSOLE) def test_invalid_args(self): """invalid arguments should raise ValueError""" self.assertRaises(ValueError, subprocess.call, [sys.executable, "-c", "import sys; sys.exit(47)"], preexec_fn=lambda: 1) self.assertRaises(ValueError, subprocess.call, [sys.executable, "-c", "import sys; sys.exit(47)"], close_fds=True) def test_shell_sequence(self): """Run command through the shell (sequence)""" newenv = os.environ.copy() newenv["FRUIT"] = "physalis" p = subprocess.Popen(["set"], shell=1, stdout=subprocess.PIPE, env=newenv) self.assertNotEqual(p.stdout.read().find("physalis"), -1) def test_shell_string(self): """Run command through the shell (string)""" newenv = os.environ.copy() newenv["FRUIT"] = "physalis" p = subprocess.Popen("set", shell=1, stdout=subprocess.PIPE, env=newenv) self.assertNotEqual(p.stdout.read().find("physalis"), -1) def test_call_string(self): """call() function with string argument on Windows""" rc = subprocess.call(sys.executable + ' -c "import sys; sys.exit(47)"') self.assertEqual(rc, 47) def test_main(): test_support.run_unittest(ProcessTestCase) if __name__ == "__main__": test_main() From akuchling at users.sourceforge.net Tue Oct 12 17:32:13 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 12 17:32:15 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1159,1.1160 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26569 Modified Files: NEWS Log Message: Fix PEP number Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1159 retrieving revision 1.1160 diff -u -d -r1.1159 -r1.1160 --- NEWS 12 Oct 2004 15:26:26 -0000 1.1159 +++ NEWS 12 Oct 2004 15:32:10 -0000 1.1160 @@ -44,7 +44,7 @@ Library ------- -- Added Peter Astrand's subprocess.py module. See PEP 327 for details. +- Added Peter Astrand's subprocess.py module. See PEP 324 for details. - time.strptime() now properly escapes timezones and all other locale-specific strings for regex-specific symbols. Was breaking under Japanese Windows when From amk at amk.ca Tue Oct 12 17:36:49 2004 From: amk at amk.ca (A.M. Kuchling) Date: Tue Oct 12 17:38:51 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1159,1.1160 In-Reply-To: References: Message-ID: <20041012153649.GA15674@rogue.amk.ca> On Tue, Oct 12, 2004 at 08:32:13AM -0700, akuchling@users.sourceforge.net wrote: > -- Added Peter Astrand's subprocess.py module. See PEP 327 for details. > +- Added Peter Astrand's subprocess.py module. See PEP 324 for details. By the by, PEP 324 still refers to callv(); I don't know if there were other relevant changes recently. Someone should update the PEP. --amk From effbot at users.sourceforge.net Tue Oct 12 17:43:27 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Tue Oct 12 17:43:29 2004 Subject: [Python-checkins] python/nondist/peps pep-0324.txt,1.3,1.4 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29270 Modified Files: pep-0324.txt Log Message: Updated the subprocess PEP to the latest version. Index: pep-0324.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0324.txt,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- pep-0324.txt 8 Oct 2004 13:03:22 -0000 1.3 +++ pep-0324.txt 12 Oct 2004 15:43:24 -0000 1.4 @@ -92,16 +92,16 @@ For example, many people cannot tell the difference between popen2.popen2 and popen2.popen4 without using the documentation. - - Two small utility functions are provided: subprocess.call() and - subprocess.callv(). These aims to be an enhancement over - os.system(), while still very easy to use: + - One small utility functions is provided: subprocess.call(). It + aims to be an enhancement over os.system(), while still very + easy to use: - It does not use the Standard C function system(), which has limitations. - It does not call the shell implicitly. - - No need for quoting; using a variable argument list. + - No need for quoting; using an argument list. - The return value is easier to work with. @@ -116,17 +116,6 @@ The motivation behind the call() function is simple: Starting a process and wait for it to finish is a common task. - The callv() function is identical to call(), except that each - non-keyword argument is treated as a program argument. This - gives a slightly nicer syntax. The drawback is that callv() - does not allow specifying the program and it's arguments as a - whitespace-separated string: The entire (first) string would be - interpreted as the executable. The implementation of callv() is - also very simple: - - def callv(*args, **kwargs): - return Popen(args, **kwargs).wait() - While Popen supports a wide range of options, many users have simple needs. Many people are using os.system() today, mainly because it provides a simple interface. Consider this example: @@ -137,10 +126,9 @@ subprocess.call(["stty", "sane", "-F", device]) - Some people feel that the list brackets are clumsy. With - callv(), they are not needed: + or, if executing through the shell: - subprocess.callv("stty", "sane", "-F", device) + subprocess.call("stty sane -F " + device, shell=True) - The "preexec" functionality makes it possible to run arbitrary code between fork and exec. One might ask why there are special @@ -177,18 +165,23 @@ Arguments are: - - args should be a sequence of program arguments. The program to - execute is normally the first item in the args sequence, but can - be explicitly set by using the executable argument. - - - On UNIX: the Popen class uses os.execvp() to execute the child - program, which operates on sequences. If args is a string, it - will be converted to a sequence using the cmdline2list method. - Please note that syntax for quoting arguments is different from - a typical UNIX shell. See the documentation of the cmdline2list - method for more information. - - - On Windows: the Popen class uses CreateProcess() to execute the + - args should be a string, or a sequence of program arguments. + The program to execute is normally the first item in the args + sequence or string, but can be explicitly set by using the + executable argument. + + On UNIX, with shell=False (default): In this case, the Popen + class uses os.execvp() to execute the child program. args + should normally be a sequence. A string will be treated as a + sequence with the string as the only item (the program to + execute). + + On UNIX, with shell=True: If args is a string, it specifies the + command string to execute through the shell. If args is a + sequence, the first item specifies the command string, and any + additional items will be treated as additional shell arguments. + + On Windows: the Popen class uses CreateProcess() to execute the child program, which operates on strings. If args is a sequence, it will be converted to a string using the list2cmdline method. Please note that not all MS Windows @@ -221,11 +214,7 @@ will be closed before the child process is executed. - If shell is true, the specified command will be executed through - the shell. Note: When executing through the shell on UNIX - systems and the args argument is a sequence, only the first - element in the sequence will be passed as a command string to - the shell. The remaining arguments can be used to specify - additional shell options. + the shell. - If cwd is not None, the current directory will be changed to cwd before the child is executed. @@ -261,21 +250,6 @@ retcode = call(["ls", "-l"]) - - callv(*args, **kwargs): - Run command with arguments. Wait for command to complete, - then return the returncode attribute. - - This function is identical to call(), except that each - non-keyword argument is treated as a program argument. - Example: - - retcode = callv("ls", "-l") - - This is equivalent to: - - retcode = call(["ls", "-l"]) - - Exceptions ---------- @@ -389,7 +363,7 @@ sts = os.system("mycmd" + " myarg") ==> - p = Popen(["mycmd" + " myarg"], shell=True) + p = Popen("mycmd" + " myarg", shell=True) sts = os.waitpid(p.pid, 0) Note: @@ -402,7 +376,7 @@ A more real-world example would look like this: try: - retcode = callv("mycmd", "myarg") + retcode = call("mycmd" + " myarg", shell=True) if retcode < 0: print >>sys.stderr, "Child was terminated by signal", -retcode else: @@ -425,7 +399,7 @@ retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") ==> - retcode = callv("/bin/mycmd", "myarg") + retcode = call(["/bin/mycmd", "myarg"]) Vector example: @@ -447,16 +421,16 @@ pipe = os.popen(cmd, mode='r', bufsize) ==> - pipe = Popen([cmd], shell=True, bufsize=bufsize, stdout=PIPE).stdout + pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout pipe = os.popen(cmd, mode='w', bufsize) ==> - pipe = Popen([cmd], shell=True, bufsize=bufsize, stdin=PIPE).stdin + pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin (child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) ==> - p = Popen([cmd], shell=True, bufsize=bufsize, + p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdin, child_stdout) = (p.stdin, p.stdout) @@ -465,7 +439,7 @@ child_stdout, child_stderr) = os.popen3(cmd, mode, bufsize) ==> - p = Popen([cmd], shell=True, bufsize=bufsize, + p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) (child_stdin, child_stdout, @@ -474,7 +448,7 @@ (child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) ==> - p = Popen([cmd], shell=True, bufsize=bufsize, + p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) From effbot at users.sourceforge.net Tue Oct 12 17:48:20 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Tue Oct 12 17:48:23 2004 Subject: [Python-checkins] python/nondist/peps pep-0324.txt,1.4,1.5 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30752 Modified Files: pep-0324.txt Log Message: Typo. Index: pep-0324.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0324.txt,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- pep-0324.txt 12 Oct 2004 15:43:24 -0000 1.4 +++ pep-0324.txt 12 Oct 2004 15:48:03 -0000 1.5 @@ -92,7 +92,7 @@ For example, many people cannot tell the difference between popen2.popen2 and popen2.popen4 without using the documentation. - - One small utility functions is provided: subprocess.call(). It + - One small utility function is provided: subprocess.call(). It aims to be an enhancement over os.system(), while still very easy to use: From akuchling at users.sourceforge.net Tue Oct 12 17:58:05 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 12 17:58:07 2004 Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew24.tex, 1.108, 1.109 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv308 Modified Files: whatsnew24.tex Log Message: Start section for PEP 324 Index: whatsnew24.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew24.tex,v retrieving revision 1.108 retrieving revision 1.109 diff -u -d -r1.108 -r1.109 --- whatsnew24.tex 11 Oct 2004 19:20:06 -0000 1.108 +++ whatsnew24.tex 12 Oct 2004 15:58:02 -0000 1.109 @@ -427,6 +427,28 @@ %====================================================================== +\section{PEP 324: New subprocess Module} + +The standard library provides a number of ways to +execute a subprocess, each of which offers different features and +levels of difficulty. \function{os.system(\var{command})} is easy, but +slow -- it runs a shell process which executes the command -- +and dangerous -- you have to be careful about escaping metacharacters. +The \module{popen2} module offers classes that can capture +standard output and standard error from the subprocess, but the naming +is confusing. + +The \module{subprocess} module cleans all this up, providing a unified +interface that offers all the features you might need. + +% XXX finish writing this section by adding some examples + + +\begin{seealso} +\seepep{324}{subprocess - New process module}{Written and implemented by Peter Astrand, with assistance from Fredrik Lundh and others.} +\end{seealso} + +%====================================================================== \section{PEP 327: Decimal Data Type} Python has always supported floating-point (FP) numbers as a data From akuchling at users.sourceforge.net Tue Oct 12 18:37:00 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 12 18:37:03 2004 Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew24.tex, 1.109, 1.110 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9392 Modified Files: whatsnew24.tex Log Message: Finish off PEP 324 section; fix Peter's last name Index: whatsnew24.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew24.tex,v retrieving revision 1.109 retrieving revision 1.110 diff -u -d -r1.109 -r1.110 --- whatsnew24.tex 12 Oct 2004 15:58:02 -0000 1.109 +++ whatsnew24.tex 12 Oct 2004 16:36:57 -0000 1.110 @@ -440,14 +440,79 @@ The \module{subprocess} module cleans all this up, providing a unified interface that offers all the features you might need. +Instead of \module{popen2}'s collection of classes, +\module{subprocess} contains a single class called \class{Popen} +whose constructor supports a number of different keyword arguments. -% XXX finish writing this section by adding some examples +\begin{verbatim} +class Popen(args, bufsize=0, executable=None, + stdin=None, stdout=None, stderr=None, + preexec_fn=None, close_fds=False, shell=False, + cwd=None, env=None, universal_newlines=False, + startupinfo=None, creationflags=0): +\end{verbatim} + +\var{args} is commonly a sequence of strings that will be the arguments to +the program executed as the subprocess. (If the \var{shell} argument is true, +\var{args} can be a string which will then be passed on to the shell for interpretation.) + +\var{stdin}, \var{stdout}, and \var{stderr} specify what the +subprocess's input, output, and error streams will be. You can +provide a file object or a file descriptor, or you can +use \code{subprocess.PIPE} to create a pipe between the subprocess +and the parent. + +The constructor has a number of handy options: + +\begin{itemize} + \item \var{close_fds} requests that all file descriptors be closed before running the subprocess. + \item \var{cwd} specifies the working directory in which the subprocess will be executed (defaulting to whatever the parent's working directory is). + \item \var{env} is a dictionary specifying environment variables. + \item \var{preexec_fn} is a function that gets called before the child is started. + \item \var{universal_newlines} opens the child's input and output using +Python's universal newline feature. +\end{itemize} + +Once you've created the \class{Popen} instance, +you can call \method{wait()} to pause until the subprocess has exited, +\method{poll()} to check if it's exited without pausing, +or \method{communicate(\var{data})} to send the string \var{data} to +the subprocess's standard input. \method{communicate(\var{data})} +then reads any data that the subprocess has sent to its standard output or error, returning a tuple \code{(\var{stdout_data}, \var{stderr_data})}. + +\function{call()} is a shortcut that passes its arguments along to +the \class{Popen} constructor, waits for the command to complete, and +returns the status code of the subprocess. It can serve as an analog +to +\function{os.system()}: + +\begin{verbatim} +sts = subprocess.call(['dpkg', '-i', '/tmp/new-package.deb']) +if sts == 0: + # Success + ... +else: + # dpkg returned an error + ... +\end{verbatim} + +The command is invoked without use of the shell. If you really do want to +use the shell, you can add \code{shell=True} as a keyword argument and provide +a string instead of a sequence: + +\begin{verbatim} +sts = subprocess.call('dpkg -i /tmp/new-package.deb', shell=True) +\end{verbatim} +The PEP takes various examples of shell and Python code and shows how +they'd be translated into Python code that uses \module{subprocess}. +Reading this section of the PEP is highly recommended. \begin{seealso} -\seepep{324}{subprocess - New process module}{Written and implemented by Peter Astrand, with assistance from Fredrik Lundh and others.} +\seepep{324}{subprocess - New process module}{Written and implemented by Peter {\AA}strand, with assistance from Fredrik Lundh and others.} \end{seealso} + %====================================================================== \section{PEP 327: Decimal Data Type} @@ -1491,6 +1556,7 @@ The author would like to thank the following people for offering suggestions, corrections and assistance with various drafts of this -article: Hye-Shik Chang, Michael Dyck, Raymond Hettinger, Hamish Lawson. +article: Hye-Shik Chang, Michael Dyck, Raymond Hettinger, Hamish Lawson, +Fredrik Lundh. \end{document} From akuchling at users.sourceforge.net Tue Oct 12 18:37:50 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 12 18:37:54 2004 Subject: [Python-checkins] python/nondist/peps pep-0324.txt,1.5,1.6 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9582 Modified Files: pep-0324.txt Log Message: Typo fixes Index: pep-0324.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0324.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- pep-0324.txt 12 Oct 2004 15:48:03 -0000 1.5 +++ pep-0324.txt 12 Oct 2004 16:37:47 -0000 1.6 @@ -223,7 +223,7 @@ new process. - If universal_newlines is true, the file objects stdout and - stderr are opened as a text files, but lines may be terminated + stderr are opened as a text file, but lines may be terminated by any of '\n', the Unix end-of-line convention, '\r', the Macintosh convention or '\r\n', the Windows convention. All of these external representations are seen as '\n' by the Python @@ -500,7 +500,7 @@ * expect-like functionality, including pty support. pty support is highly platform-dependent, which is a - problem. Also, there are already other modules that provides this + problem. Also, there are already other modules that provide this kind of functionality[6]. From akuchling at users.sourceforge.net Tue Oct 12 18:38:44 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 12 18:38:46 2004 Subject: [Python-checkins] python/dist/src/Lib subprocess.py,1.1,1.2 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9837 Modified Files: subprocess.py Log Message: Typo fix Index: subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/subprocess.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- subprocess.py 12 Oct 2004 15:26:27 -0000 1.1 +++ subprocess.py 12 Oct 2004 16:38:42 -0000 1.2 @@ -711,7 +711,7 @@ self.pid = pid ht.Close() - # Child is launched. Close the parents copy of those pipe + # Child is launched. Close the parent's copy of those pipe # handles that only the child should have open. You need # to make sure that no handles to the write end of the # output pipe are maintained in this process or else the From jlgijsbers at users.sourceforge.net Tue Oct 12 20:12:13 2004 From: jlgijsbers at users.sourceforge.net (jlgijsbers@users.sourceforge.net) Date: Tue Oct 12 20:12:16 2004 Subject: [Python-checkins] python/dist/src/Lib pdb.py,1.69,1.70 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31804 Modified Files: pdb.py Log Message: Improvements when running pdb as a script. Bug fixes: * Use fresh copy of globals/locals so the script being debugged can't access the pdb namespace (e.g.: p line_prefix will no longer work). * Remove pdb.py's path from sys.path. Having it in there is normally not a problem, but it could prove irritating when messing with PYTHONPATH or invoking pdb via /usr/bin/pdf. * You can now set a breakpoint on the script being debugged, even if the script doesn't end with a '.py' extension. Also, setting breakpoints with absolute paths now works reliably. Enhancements: * Go directly to the first line of the script. * Enter post-mortem debugging if the script being debugged doesn't catch an exception. * Restart the script being debugged and preserve debugger state when the script being debugged exits. Cleanup: * Moved the __main__ method into a main() function. * Kill the (undocumented, not in __all__) mainmodule/mainpyfile globals, add a mainpyfile attribute to pdb. Thanks Ilya Sandler for the patch! Index: pdb.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/pdb.py,v retrieving revision 1.69 retrieving revision 1.70 diff -u -d -r1.69 -r1.70 --- pdb.py 30 Aug 2004 13:29:44 -0000 1.69 +++ pdb.py 12 Oct 2004 18:12:09 -0000 1.70 @@ -12,7 +12,7 @@ import os import re import pprint - +import traceback # Create a custom safe Repr instance and increase its maxstring. # The default of 30 truncates error messages too easily. _repr = Repr() @@ -57,6 +57,8 @@ cmd.Cmd.__init__(self) self.prompt = '(Pdb) ' self.aliases = {} + self.mainpyfile = '' + self._wait_for_mainpyfile = 0 # Try to load readline if it exists try: import readline @@ -117,12 +119,19 @@ def user_call(self, frame, argument_list): """This method is called when there is the remote possibility that we ever need to stop in this function.""" + if self._wait_for_mainpyfile: + return if self.stop_here(frame): print '--Call--' self.interaction(frame, None) def user_line(self, frame): """This function is called when we stop or break at this line.""" + if self._wait_for_mainpyfile: + if (self.mainpyfile != self.canonic(frame.f_code.co_filename) + or frame.f_lineno<= 0): + return + self._wait_for_mainpyfile = 0 self.interaction(frame, None) def user_return(self, frame, return_value): @@ -281,8 +290,8 @@ def defaultFile(self): """Produce a reasonable default.""" filename = self.curframe.f_code.co_filename - if filename == '' and mainpyfile: - filename = mainpyfile + if filename == '' and self.mainpyfile: + filename = self.mainpyfile return filename do_b = do_break @@ -525,13 +534,16 @@ self.lastcmd = p.lastcmd def do_quit(self, arg): + self._user_requested_quit = 1 self.set_quit() return 1 + do_q = do_quit do_exit = do_quit def do_EOF(self, arg): print + self._user_requested_quit = 1 self.set_quit() return 1 @@ -928,7 +940,16 @@ help() def lookupmodule(self, filename): - """Helper function for break/clear parsing -- may be overridden.""" + """Helper function for break/clear parsing -- may be overridden. + + lookupmodule() translates (possibly incomplete) file or module name + into an absolute file name. + """ + if os.path.isabs(filename) and os.path.exists(filename): + return filename + f = os.path.join(sys.path[0], filename) + if os.path.exists(f) and self.canonic(f) == self.mainpyfile: + return f root, ext = os.path.splitext(filename) if ext == '': filename = filename + '.py' @@ -942,6 +963,24 @@ return fullname return None + def _runscript(self, filename): + # Start with fresh empty copy of globals and locals and tell the script + # that it's being run as __main__ to avoid scripts being able to access + # the pdb.py namespace. + globals_ = {"__name__" : "__main__"} + locals_ = globals_ + + # When bdb sets tracing, a number of call and line events happens + # BEFORE debugger even reaches user's code (and the exact sequence of + # events depends on python version). So we take special measures to + # avoid stopping before we reach the main script (see user_line and + # user_call for details). + self._wait_for_mainpyfile = 1 + self.mainpyfile = self.canonic(filename) + self._user_requested_quit = 0 + statement = 'execfile( "%s")' % filename + self.run(statement, globals=globals_, locals=locals_) + # Simplified interface def run(statement, globals=None, locals=None): @@ -992,23 +1031,49 @@ print 'Sorry, can\'t find the help file "pdb.doc"', print 'along the Python search path' -mainmodule = '' -mainpyfile = '' - -# When invoked as main program, invoke the debugger on a script -if __name__=='__main__': +def main(): if not sys.argv[1:]: print "usage: pdb.py scriptfile [arg] ..." sys.exit(2) - mainpyfile = filename = sys.argv[1] # Get script filename - if not os.path.exists(filename): - print 'Error:', repr(filename), 'does not exist' + mainpyfile = sys.argv[1] # Get script filename + if not os.path.exists(mainpyfile): + print 'Error:', mainpyfile, 'does not exist' sys.exit(1) - mainmodule = os.path.basename(filename) + del sys.argv[0] # Hide "pdb.py" from argument list - # Insert script directory in front of module search path - sys.path.insert(0, os.path.dirname(filename)) + # Replace pdb's dir with script's dir in front of module search path. + sys.path[0] = os.path.dirname(mainpyfile) - run('execfile(%r)' % (filename,)) + # Note on saving/restoring sys.argv: it's a good idea when sys.argv was + # modified by the script being debugged. It's a bad idea when it was + # changed by the user from the command line. The best approach would be to + # have a "restart" command which would allow explicit specification of + # command line arguments. + pdb = Pdb() + while 1: + try: + pdb._runscript(mainpyfile) + if pdb._user_requested_quit: + break + print "The program finished and will be restarted" + except SystemExit: + # In most cases SystemExit does not warrant a post-mortem session. + print "The program exited via sys.exit(). Exit status: ", + print sys.exc_info()[1] + except: + traceback.print_exc() + print "Uncaught exception. Entering post mortem debugging" + print "Running 'cont' or 'step' will restart the program" + t = sys.exc_info()[2] + while t.tb_next is not None: + t = t.tb_next + pdb.interaction(t.tb_frame,t) + print "Post mortem debugger finished. The "+mainpyfile+" will be restarted" + + +# When invoked as main program, invoke the debugger on a script +if __name__=='__main__': + main() + From tim_one at users.sourceforge.net Tue Oct 12 23:38:24 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Tue Oct 12 23:38:27 2004 Subject: [Python-checkins] python/dist/src/PC _subprocess.c,1.1,1.2 Message-ID: Update of /cvsroot/python/python/dist/src/PC In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11905/pc Modified Files: _subprocess.c Log Message: Before this turns into an unreadable mess, follow PEP 7 by using hard tab indents in C code. Index: _subprocess.c =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/_subprocess.c,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- _subprocess.c 12 Oct 2004 15:26:28 -0000 1.1 +++ _subprocess.c 12 Oct 2004 21:38:22 -0000 1.2 @@ -3,16 +3,16 @@ * * Currently, this extension module is only required when using the * subprocess module on Windows, but in the future, stubs for other - * platforms might be added here as well. + * platforms might be added here as well. * * Copyright (c) 2004 by Fredrik Lundh * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com * Copyright (c) 2004 by Peter Astrand - * + * * By obtaining, using, and/or copying this software and/or its * associated documentation, you agree that you have read, understood, * and will comply with the following terms and conditions: - * + * * Permission to use, copy, modify, and distribute this software and * its associated documentation for any purpose and without fee is * hereby granted, provided that the above copyright notice appears in @@ -21,7 +21,7 @@ * authors not be used in advertising or publicity pertaining to * distribution of the software without specific, written prior * permission. - * + * * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR @@ -29,7 +29,7 @@ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * + * */ /* TODO: handle unicode command lines? */ @@ -46,8 +46,8 @@ the wrapper is used to provide Detach and Close methods */ typedef struct { - PyObject_HEAD - HANDLE handle; + PyObject_HEAD + HANDLE handle; } sp_handle_object; staticforward PyTypeObject sp_handle_type; @@ -55,89 +55,89 @@ static PyObject* sp_handle_new(HANDLE handle) { - sp_handle_object* self; + sp_handle_object* self; - self = PyObject_NEW(sp_handle_object, &sp_handle_type); - if (self == NULL) - return NULL; + self = PyObject_NEW(sp_handle_object, &sp_handle_type); + if (self == NULL) + return NULL; - self->handle = handle; + self->handle = handle; - return (PyObject*) self; + return (PyObject*) self; } static PyObject* sp_handle_detach(sp_handle_object* self, PyObject* args) { - HANDLE handle; + HANDLE handle; - if (!PyArg_ParseTuple(args, ":Detach")) - return NULL; + if (! PyArg_ParseTuple(args, ":Detach")) + return NULL; - handle = self->handle; + handle = self->handle; - self->handle = NULL; + self->handle = NULL; - /* note: return the current handle, as an integer */ - return PyInt_FromLong((long) handle); + /* note: return the current handle, as an integer */ + return PyInt_FromLong((long) handle); } static PyObject* sp_handle_close(sp_handle_object* self, PyObject* args) { - if (!PyArg_ParseTuple(args, ":Close")) - return NULL; + if (! PyArg_ParseTuple(args, ":Close")) + return NULL; - if (self->handle != INVALID_HANDLE_VALUE) { - CloseHandle(self->handle); - self->handle = INVALID_HANDLE_VALUE; - } - Py_INCREF(Py_None); - return Py_None; + if (self->handle != INVALID_HANDLE_VALUE) { + CloseHandle(self->handle); + self->handle = INVALID_HANDLE_VALUE; + } + Py_INCREF(Py_None); + return Py_None; } static void sp_handle_dealloc(sp_handle_object* self) { - if (self->handle != INVALID_HANDLE_VALUE) - CloseHandle(self->handle); - PyMem_DEL(self); + if (self->handle != INVALID_HANDLE_VALUE) + CloseHandle(self->handle); + PyMem_DEL(self); } static PyMethodDef sp_handle_methods[] = { - {"Detach", (PyCFunction) sp_handle_detach, 1}, - {"Close", (PyCFunction) sp_handle_close, 1}, - {NULL, NULL} + {"Detach", (PyCFunction) sp_handle_detach, 1}, + {"Close", (PyCFunction) sp_handle_close, 1}, + {NULL, NULL} }; -static PyObject* +static PyObject* sp_handle_getattr(sp_handle_object* self, char* name) { - return Py_FindMethod(sp_handle_methods, (PyObject*) self, name); + return Py_FindMethod(sp_handle_methods, (PyObject*) self, name); } static PyObject* sp_handle_as_int(sp_handle_object* self) { - return PyInt_FromLong((long) self->handle); + return PyInt_FromLong((long) self->handle); } static PyNumberMethods sp_handle_as_number; statichere PyTypeObject sp_handle_type = { - PyObject_HEAD_INIT(NULL) - 0, /*ob_size*/ - "_subprocess_handle", sizeof(sp_handle_object), 0, - (destructor) sp_handle_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - (getattrfunc) sp_handle_getattr, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_compare*/ - 0, /*tp_repr*/ - &sp_handle_as_number, /*tp_as_number */ - 0, /*tp_as_sequence */ - 0, /*tp_as_mapping */ - 0 /*tp_hash*/ + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "_subprocess_handle", sizeof(sp_handle_object), 0, + (destructor) sp_handle_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc) sp_handle_getattr,/*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + &sp_handle_as_number, /*tp_as_number */ + 0, /*tp_as_sequence */ + 0, /*tp_as_mapping */ + 0 /*tp_hash*/ }; /* -------------------------------------------------------------------- */ @@ -146,91 +146,99 @@ static PyObject * sp_GetStdHandle(PyObject* self, PyObject* args) { - HANDLE handle; + HANDLE handle; + int std_handle; - int std_handle; - if (!PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle)) - return NULL; + if (! PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle)) + return NULL; - Py_BEGIN_ALLOW_THREADS - handle = GetStdHandle((DWORD) std_handle); - Py_END_ALLOW_THREADS + Py_BEGIN_ALLOW_THREADS + handle = GetStdHandle((DWORD) std_handle); + Py_END_ALLOW_THREADS - if (handle == INVALID_HANDLE_VALUE) - return PyErr_SetFromWindowsErr(GetLastError()); + if (handle == INVALID_HANDLE_VALUE) + return PyErr_SetFromWindowsErr(GetLastError()); - if (!handle) { - Py_INCREF(Py_None); - return Py_None; - } + if (! handle) { + Py_INCREF(Py_None); + return Py_None; + } - /* note: returns integer, not handle object */ - return PyInt_FromLong((long) handle); + /* note: returns integer, not handle object */ + return PyInt_FromLong((long) handle); } static PyObject * sp_GetCurrentProcess(PyObject* self, PyObject* args) { - if (!PyArg_ParseTuple(args, ":GetCurrentProcess")) - return NULL; + if (! PyArg_ParseTuple(args, ":GetCurrentProcess")) + return NULL; - return sp_handle_new(GetCurrentProcess()); + return sp_handle_new(GetCurrentProcess()); } static PyObject * sp_DuplicateHandle(PyObject* self, PyObject* args) { - HANDLE target_handle; - BOOL result; + HANDLE target_handle; + BOOL result; - long source_process_handle; - long source_handle; - long target_process_handle; - int desired_access; - int inherit_handle; - int options = 0; - if (!PyArg_ParseTuple(args, "lllii|i:DuplicateHandle", - &source_process_handle, &source_handle, - &target_process_handle, - &desired_access, &inherit_handle, &options)) - return NULL; + long source_process_handle; + long source_handle; + long target_process_handle; + int desired_access; + int inherit_handle; + int options = 0; - Py_BEGIN_ALLOW_THREADS - result = DuplicateHandle( - (HANDLE) source_process_handle, (HANDLE) source_handle, - (HANDLE) target_process_handle, &target_handle, desired_access, - inherit_handle, options - ); - Py_END_ALLOW_THREADS + if (! PyArg_ParseTuple(args, "lllii|i:DuplicateHandle", + &source_process_handle, + &source_handle, + &target_process_handle, + &desired_access, + &inherit_handle, + &options)) + return NULL; - if (!result) - return PyErr_SetFromWindowsErr(GetLastError()); + Py_BEGIN_ALLOW_THREADS + result = DuplicateHandle( + (HANDLE) source_process_handle, + (HANDLE) source_handle, + (HANDLE) target_process_handle, + &target_handle, + desired_access, + inherit_handle, + options + ); + Py_END_ALLOW_THREADS - return sp_handle_new(target_handle); + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return sp_handle_new(target_handle); } static PyObject * sp_CreatePipe(PyObject* self, PyObject* args) { - HANDLE read_pipe; - HANDLE write_pipe; - BOOL result; + HANDLE read_pipe; + HANDLE write_pipe; + BOOL result; - PyObject* pipe_attributes; /* ignored */ - int size; - if (!PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size)) - return NULL; + PyObject* pipe_attributes; /* ignored */ + int size; - Py_BEGIN_ALLOW_THREADS - result = CreatePipe(&read_pipe, &write_pipe, NULL, size); - Py_END_ALLOW_THREADS + if (! PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size)) + return NULL; - if (!result) - return PyErr_SetFromWindowsErr(GetLastError()); + Py_BEGIN_ALLOW_THREADS + result = CreatePipe(&read_pipe, &write_pipe, NULL, size); + Py_END_ALLOW_THREADS - return Py_BuildValue( - "NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe) - ); + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return Py_BuildValue( + "NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe)); } /* helpers for createprocess */ @@ -238,236 +246,253 @@ static int getint(PyObject* obj, char* name) { - PyObject* value; - value = PyObject_GetAttrString(obj, name); - if (!value) { - PyErr_Clear(); /* FIXME: propagate error? */ - return 0; - } - return (int) PyInt_AsLong(value); + PyObject* value; + + value = PyObject_GetAttrString(obj, name); + if (! value) { + PyErr_Clear(); /* FIXME: propagate error? */ + return 0; + } + return (int) PyInt_AsLong(value); } - + static HANDLE gethandle(PyObject* obj, char* name) { - sp_handle_object* value; - value = (sp_handle_object*) PyObject_GetAttrString(obj, name); - if (!value) { - PyErr_Clear(); /* FIXME: propagate error? */ - return NULL; - } - if (value->ob_type != &sp_handle_type) - return NULL; - return value->handle; + sp_handle_object* value; + + value = (sp_handle_object*) PyObject_GetAttrString(obj, name); + if (! value) { + PyErr_Clear(); /* FIXME: propagate error? */ + return NULL; + } + if (value->ob_type != &sp_handle_type) + return NULL; + return value->handle; } static PyObject* getenvironment(PyObject* environment) { - int i, envsize; - PyObject* out = NULL; - PyObject* keys; - PyObject* values; - char* p; + int i, envsize; + PyObject* out = NULL; + PyObject* keys; + PyObject* values; + char* p; - /* convert environment dictionary to windows enviroment string */ + /* convert environment dictionary to windows enviroment string */ + if (! PyMapping_Check(environment)) { + PyErr_SetString( + PyExc_TypeError, "environment must be dictionary or None"); + return NULL; + } - if (!PyMapping_Check(environment)) { - PyErr_SetString( - PyExc_TypeError, "environment must be dictionary or None" - ); - return NULL; - } - - envsize = PyMapping_Length(environment); + envsize = PyMapping_Length(environment); - keys = PyMapping_Keys(environment); - values = PyMapping_Values(environment); - if (!keys || !values) - goto error; + keys = PyMapping_Keys(environment); + values = PyMapping_Values(environment); + if (!keys || !values) + goto error; - out = PyString_FromStringAndSize(NULL, 2048); - if (!out) - goto error; + out = PyString_FromStringAndSize(NULL, 2048); + if (! out) + goto error; - p = PyString_AS_STRING(out); + p = PyString_AS_STRING(out); - for (i = 0; i < envsize; i++) { - int ksize, vsize, totalsize; - PyObject* key = PyList_GET_ITEM(keys, i); - PyObject* value = PyList_GET_ITEM(values, i); - if (!PyString_Check(key) || !PyString_Check(value)) { - PyErr_SetString( - PyExc_TypeError, "environment can only contain strings" - ); - goto error; - } - ksize = PyString_GET_SIZE(key); - vsize = PyString_GET_SIZE(value); - totalsize = (p - PyString_AS_STRING(out)) + ksize + 1 + vsize + 1 + 1; - if (totalsize > PyString_GET_SIZE(out)) { - int offset = p - PyString_AS_STRING(out); - _PyString_Resize(&out, totalsize + 1024); - p = PyString_AS_STRING(out) + offset; - } - memcpy(p, PyString_AS_STRING(key), ksize); p += ksize; *p++ = '='; - memcpy(p, PyString_AS_STRING(value), vsize); p += vsize; *p++ = '\0'; - } + for (i = 0; i < envsize; i++) { + int ksize, vsize, totalsize; + PyObject* key = PyList_GET_ITEM(keys, i); + PyObject* value = PyList_GET_ITEM(values, i); - /* add trailing null byte */ - *p++ = '\0'; + if (! PyString_Check(key) || ! PyString_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "environment can only contain strings"); + goto error; + } + ksize = PyString_GET_SIZE(key); + vsize = PyString_GET_SIZE(value); + totalsize = (p - PyString_AS_STRING(out)) + ksize + 1 + + vsize + 1 + 1; + if (totalsize > PyString_GET_SIZE(out)) { + int offset = p - PyString_AS_STRING(out); + _PyString_Resize(&out, totalsize + 1024); + p = PyString_AS_STRING(out) + offset; + } + memcpy(p, PyString_AS_STRING(key), ksize); + p += ksize; + *p++ = '='; + memcpy(p, PyString_AS_STRING(value), vsize); + p += vsize; + *p++ = '\0'; + } - _PyString_Resize(&out, p - PyString_AS_STRING(out)); + /* add trailing null byte */ + *p++ = '\0'; + _PyString_Resize(&out, p - PyString_AS_STRING(out)); - /* PyObject_Print(out, stdout, 0); */ + /* PyObject_Print(out, stdout, 0); */ - return out; + return out; -error: - Py_XDECREF(out); - Py_XDECREF(keys); - Py_XDECREF(values); - return NULL; + error: + Py_XDECREF(out); + Py_XDECREF(keys); + Py_XDECREF(values); + return NULL; } static PyObject * sp_CreateProcess(PyObject* self, PyObject* args) { - BOOL result; - PROCESS_INFORMATION pi; - STARTUPINFO si; - PyObject* environment; + BOOL result; + PROCESS_INFORMATION pi; + STARTUPINFO si; + PyObject* environment; - char* application_name; - char* command_line; - PyObject* process_attributes; /* ignored */ - PyObject* thread_attributes; /* ignored */ - int inherit_handles; - int creation_flags; - PyObject* env_mapping; - char* current_directory; - PyObject* startup_info; - if (!PyArg_ParseTuple(args, "zzOOiiOzO:CreateProcess", - &application_name, &command_line, - &process_attributes, &thread_attributes, - &inherit_handles, &creation_flags, - &env_mapping, ¤t_directory, &startup_info)) - return NULL; + char* application_name; + char* command_line; + PyObject* process_attributes; /* ignored */ + PyObject* thread_attributes; /* ignored */ + int inherit_handles; + int creation_flags; + PyObject* env_mapping; + char* current_directory; + PyObject* startup_info; - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); + if (! PyArg_ParseTuple(args, "zzOOiiOzO:CreateProcess", + &application_name, + &command_line, + &process_attributes, + &thread_attributes, + &inherit_handles, + &creation_flags, + &env_mapping, + ¤t_directory, + &startup_info)) + return NULL; - /* note: we only support a small subset of all SI attributes */ - si.dwFlags = getint(startup_info, "dwFlags"); - si.hStdInput = gethandle(startup_info, "hStdInput"); - si.hStdOutput = gethandle(startup_info, "hStdOutput"); - si.hStdError = gethandle(startup_info, "hStdError"); + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); - if (env_mapping == Py_None) - environment = NULL; - else { - environment = getenvironment(env_mapping); - if (!environment) - return NULL; - } + /* note: we only support a small subset of all SI attributes */ + si.dwFlags = getint(startup_info, "dwFlags"); + si.hStdInput = gethandle(startup_info, "hStdInput"); + si.hStdOutput = gethandle(startup_info, "hStdOutput"); + si.hStdError = gethandle(startup_info, "hStdError"); - Py_BEGIN_ALLOW_THREADS - result = CreateProcess( - application_name, command_line, NULL, NULL, inherit_handles, - creation_flags, environment ? PyString_AS_STRING(environment) : NULL, - current_directory, &si, &pi - ); - Py_END_ALLOW_THREADS + if (env_mapping == Py_None) + environment = NULL; + else { + environment = getenvironment(env_mapping); + if (! environment) + return NULL; + } - Py_XDECREF(environment); + Py_BEGIN_ALLOW_THREADS + result = CreateProcess(application_name, + command_line, + NULL, + NULL, + inherit_handles, + creation_flags, + environment ? PyString_AS_STRING(environment) : NULL, + current_directory, + &si, + &pi); + Py_END_ALLOW_THREADS - if (!result) - return PyErr_SetFromWindowsErr(GetLastError()); + Py_XDECREF(environment); - return Py_BuildValue( - "NNii", sp_handle_new(pi.hProcess), sp_handle_new(pi.hThread), - pi.dwProcessId, pi.dwThreadId - ); + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); + + return Py_BuildValue("NNii", + sp_handle_new(pi.hProcess), + sp_handle_new(pi.hThread), + pi.dwProcessId, + pi.dwThreadId); } static PyObject * sp_GetExitCodeProcess(PyObject* self, PyObject* args) { - DWORD exit_code; - BOOL result; + DWORD exit_code; + BOOL result; - long process; - if (!PyArg_ParseTuple(args, "l:GetExitCodeProcess", &process)) - return NULL; + long process; + if (! PyArg_ParseTuple(args, "l:GetExitCodeProcess", &process)) + return NULL; - result = GetExitCodeProcess((HANDLE) process, &exit_code); + result = GetExitCodeProcess((HANDLE) process, &exit_code); - if (!result) - return PyErr_SetFromWindowsErr(GetLastError()); + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); - return PyInt_FromLong(exit_code); + return PyInt_FromLong(exit_code); } static PyObject * sp_WaitForSingleObject(PyObject* self, PyObject* args) { - DWORD result; + DWORD result; - long handle; - int milliseconds; - if (!PyArg_ParseTuple(args, "li:WaitForSingleObject", - &handle, &milliseconds)) - return NULL; + long handle; + int milliseconds; + if (! PyArg_ParseTuple(args, "li:WaitForSingleObject", + &handle, + &milliseconds)) + return NULL; - Py_BEGIN_ALLOW_THREADS - result = WaitForSingleObject((HANDLE) handle, (DWORD) milliseconds); - Py_END_ALLOW_THREADS + Py_BEGIN_ALLOW_THREADS + result = WaitForSingleObject((HANDLE) handle, (DWORD) milliseconds); + Py_END_ALLOW_THREADS - if (result == WAIT_FAILED) - return PyErr_SetFromWindowsErr(GetLastError()); + if (result == WAIT_FAILED) + return PyErr_SetFromWindowsErr(GetLastError()); - return PyInt_FromLong((int) result); + return PyInt_FromLong((int) result); } static PyObject * sp_GetVersion(PyObject* self, PyObject* args) { - if (!PyArg_ParseTuple(args, ":GetVersion")) - return NULL; + if (! PyArg_ParseTuple(args, ":GetVersion")) + return NULL; - return PyInt_FromLong((int) GetVersion()); + return PyInt_FromLong((int) GetVersion()); } static PyObject * sp_GetModuleFileName(PyObject* self, PyObject* args) { - BOOL result; - long module; - TCHAR filename[MAX_PATH]; + BOOL result; + long module; + TCHAR filename[MAX_PATH]; - if (!PyArg_ParseTuple(args, "l:GetModuleFileName", &module)) - return NULL; + if (! PyArg_ParseTuple(args, "l:GetModuleFileName", &module)) + return NULL; - result = GetModuleFileName((HMODULE)module, filename, MAX_PATH); - filename[MAX_PATH-1] = '\0'; + result = GetModuleFileName((HMODULE)module, filename, MAX_PATH); + filename[MAX_PATH-1] = '\0'; - if (!result) - return PyErr_SetFromWindowsErr(GetLastError()); + if (! result) + return PyErr_SetFromWindowsErr(GetLastError()); - return PyString_FromString(filename); + return PyString_FromString(filename); } static PyMethodDef sp_functions[] = { - {"GetStdHandle", sp_GetStdHandle, METH_VARARGS}, - {"GetCurrentProcess", sp_GetCurrentProcess, METH_VARARGS}, - {"DuplicateHandle", sp_DuplicateHandle, METH_VARARGS}, - {"CreatePipe", sp_CreatePipe, METH_VARARGS}, - {"CreateProcess", sp_CreateProcess, METH_VARARGS}, - {"GetExitCodeProcess", sp_GetExitCodeProcess, METH_VARARGS}, - {"WaitForSingleObject", sp_WaitForSingleObject, METH_VARARGS}, - {"GetVersion", sp_GetVersion, METH_VARARGS}, - {"GetModuleFileName", sp_GetModuleFileName, METH_VARARGS}, - {NULL, NULL} + {"GetStdHandle", sp_GetStdHandle, METH_VARARGS}, + {"GetCurrentProcess", sp_GetCurrentProcess, METH_VARARGS}, + {"DuplicateHandle", sp_DuplicateHandle, METH_VARARGS}, + {"CreatePipe", sp_CreatePipe, METH_VARARGS}, + {"CreateProcess", sp_CreateProcess, METH_VARARGS}, + {"GetExitCodeProcess", sp_GetExitCodeProcess, METH_VARARGS}, + {"WaitForSingleObject", sp_WaitForSingleObject, METH_VARARGS}, + {"GetVersion", sp_GetVersion, METH_VARARGS}, + {"GetModuleFileName", sp_GetModuleFileName, METH_VARARGS}, + {NULL, NULL} }; /* -------------------------------------------------------------------- */ @@ -475,11 +500,11 @@ static void defint(PyObject* d, const char* name, int value) { - PyObject* v = PyInt_FromLong((long) value); - if (v) { - PyDict_SetItemString(d, (char*) name, v); - Py_DECREF(v); - } + PyObject* v = PyInt_FromLong((long) value); + if (v) { + PyDict_SetItemString(d, (char*) name, v); + Py_DECREF(v); + } } #if PY_VERSION_HEX >= 0x02030000 @@ -489,23 +514,23 @@ #endif init_subprocess() { - PyObject *d; - PyObject *m; + PyObject *d; + PyObject *m; - /* patch up object descriptors */ - sp_handle_type.ob_type = &PyType_Type; - sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int; + /* patch up object descriptors */ + sp_handle_type.ob_type = &PyType_Type; + sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int; - m = Py_InitModule("_subprocess", sp_functions); - d = PyModule_GetDict(m); + m = Py_InitModule("_subprocess", sp_functions); + d = PyModule_GetDict(m); - /* constants */ - defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE); - defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE); - defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE); - defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS); - defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES); - defint(d, "INFINITE", INFINITE); - defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0); - defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE); + /* constants */ + defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE); + defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE); + defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE); + defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS); + defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES); + defint(d, "INFINITE", INFINITE); + defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0); + defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE); } From tim_one at users.sourceforge.net Tue Oct 12 23:48:59 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Tue Oct 12 23:49:02 2004 Subject: [Python-checkins] python/dist/src/PC config.c,1.50,1.51 Message-ID: Update of /cvsroot/python/python/dist/src/PC In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15106/PC Modified Files: config.c Log Message: Supply the _subprocess module under 7.1. I'm not sure what the status of this should be on non-WIN32 Windows variants. Index: config.c =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/config.c,v retrieving revision 1.50 retrieving revision 1.51 diff -u -d -r1.50 -r1.51 --- config.c 31 Aug 2004 14:29:12 -0000 1.50 +++ config.c 12 Oct 2004 21:48:56 -0000 1.51 @@ -61,6 +61,7 @@ extern void init_codecs_jp(void); extern void init_codecs_kr(void); extern void init_codecs_tw(void); +extern void init_subprocess(void); /* tools/freeze/makeconfig.py marker for additional "extern" */ /* -- ADDMODULE MARKER 1 -- */ @@ -105,6 +106,8 @@ {"msvcrt", initmsvcrt}, {"_locale", init_locale}, #endif + /* XXX Should _subprocess go in a WIN32 block? not WIN64? */ + {"_subprocess", init_subprocess}, {"_codecs", init_codecs}, {"_weakref", init_weakref}, From tim_one at users.sourceforge.net Tue Oct 12 23:49:01 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Tue Oct 12 23:49:04 2004 Subject: [Python-checkins] python/dist/src/PCbuild pythoncore.vcproj, 1.20, 1.21 Message-ID: Update of /cvsroot/python/python/dist/src/PCbuild In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15106/PCbuild Modified Files: pythoncore.vcproj Log Message: Supply the _subprocess module under 7.1. I'm not sure what the status of this should be on non-WIN32 Windows variants. Index: pythoncore.vcproj =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/pythoncore.vcproj,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- pythoncore.vcproj 1 Sep 2004 18:29:25 -0000 1.20 +++ pythoncore.vcproj 12 Oct 2004 21:48:57 -0000 1.21 @@ -364,6 +364,9 @@ RelativePath="..\Modules\_sre.c"> + + From tim_one at users.sourceforge.net Tue Oct 12 23:51:35 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Tue Oct 12 23:51:39 2004 Subject: [Python-checkins] python/dist/src/Lib/email Utils.py,1.28,1.29 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/email In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15813/Lib/email Modified Files: Utils.py Log Message: Whitespace normalization. Index: Utils.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/email/Utils.py,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- Utils.py 11 Oct 2004 13:53:07 -0000 1.28 +++ Utils.py 12 Oct 2004 21:51:32 -0000 1.29 @@ -115,7 +115,7 @@ returns a date relative to the local timezone instead of UTC, properly taking daylight savings time into account. - Optional argument usegmt means that the timezone is written out as + Optional argument usegmt means that the timezone is written out as an ascii string, not numeric one (so "GMT" instead of "+0000"). This is needed for HTTP, and is only used when localtime==False. """ From tim_one at users.sourceforge.net Tue Oct 12 23:51:35 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Tue Oct 12 23:51:40 2004 Subject: [Python-checkins] python/dist/src/Lib pdb.py, 1.70, 1.71 subprocess.py, 1.2, 1.3 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15813/Lib Modified Files: pdb.py subprocess.py Log Message: Whitespace normalization. Index: pdb.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/pdb.py,v retrieving revision 1.70 retrieving revision 1.71 diff -u -d -r1.70 -r1.71 --- pdb.py 12 Oct 2004 18:12:09 -0000 1.70 +++ pdb.py 12 Oct 2004 21:51:32 -0000 1.71 @@ -946,7 +946,7 @@ into an absolute file name. """ if os.path.isabs(filename) and os.path.exists(filename): - return filename + return filename f = os.path.join(sys.path[0], filename) if os.path.exists(f) and self.canonic(f) == self.mainpyfile: return f @@ -967,8 +967,8 @@ # Start with fresh empty copy of globals and locals and tell the script # that it's being run as __main__ to avoid scripts being able to access # the pdb.py namespace. - globals_ = {"__name__" : "__main__"} - locals_ = globals_ + globals_ = {"__name__" : "__main__"} + locals_ = globals_ # When bdb sets tracing, a number of call and line events happens # BEFORE debugger even reaches user's code (and the exact sequence of @@ -1057,7 +1057,7 @@ pdb._runscript(mainpyfile) if pdb._user_requested_quit: break - print "The program finished and will be restarted" + print "The program finished and will be restarted" except SystemExit: # In most cases SystemExit does not warrant a post-mortem session. print "The program exited via sys.exit(). Exit status: ", @@ -1076,4 +1076,3 @@ # When invoked as main program, invoke the debugger on a script if __name__=='__main__': main() - Index: subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/subprocess.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- subprocess.py 12 Oct 2004 16:38:42 -0000 1.2 +++ subprocess.py 12 Oct 2004 21:51:32 -0000 1.3 @@ -1,6 +1,6 @@ # subprocess - Subprocesses with accessible I/O streams # -# For more information about this module, see PEP 324. +# For more information about this module, see PEP 324. # # Copyright (c) 2003-2004 by Peter Astrand # @@ -174,7 +174,7 @@ terminate. The optional stdin argument should be a string to be sent to the child process, or None, if no data should be sent to the child. - + communicate() returns a tuple (stdout, stderr). Note: The data read is buffered in memory, so do not use this @@ -262,7 +262,7 @@ Replacing os.spawn* ------------------- -P_NOWAIT example: +P_NOWAIT example: pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") ==> @@ -276,21 +276,21 @@ retcode = call(["/bin/mycmd", "myarg"]) -Vector example: +Vector example: os.spawnvp(os.P_NOWAIT, path, args) ==> Popen([path] + args[1:]) -Environment example: +Environment example: os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) ==> Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) -Replacing os.popen* +Replacing os.popen* ------------------- pipe = os.popen(cmd, mode='r', bufsize) ==> @@ -352,7 +352,7 @@ * the capturestderr argument is replaced with the stderr argument. * stdin=PIPE and stdout=PIPE must be specified. * popen2 closes all filedescriptors by default, but you have to specify - close_fds=True with subprocess.Popen. + close_fds=True with subprocess.Popen. """ @@ -468,10 +468,10 @@ for c in arg: if c == '\\': - # Don't know if we need to double yet. + # Don't know if we need to double yet. bs_buf.append(c) elif c == '"': - # Double backspaces. + # Double backspaces. result.append('\\' * len(bs_buf)*2) bs_buf = [] result.append('\\"') @@ -482,7 +482,7 @@ bs_buf = [] result.append(c) - # Add remaining backspaces, if any. + # Add remaining backspaces, if any. if bs_buf: result.extend(bs_buf) @@ -513,7 +513,7 @@ if creationflags != 0: raise ValueError("creationflags is only supported on Windows platforms") - self.stdin = None + self.stdin = None self.stdout = None self.stderr = None self.pid = None @@ -534,7 +534,7 @@ # are file descriptors on both platforms. The parent objects # are None when not using PIPEs. The child objects are None # when not redirecting. - + (p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite) = self._get_handles(stdin, stdout, stderr) @@ -558,7 +558,7 @@ self.stderr = os.fdopen(errread, 'rU', bufsize) else: self.stderr = os.fdopen(errread, 'rb', bufsize) - + _active.append(self) @@ -578,7 +578,7 @@ """ if stdin == None and stdout == None and stderr == None: return (None, None, None, None, None, None) - + p2cread, p2cwrite = None, None c2pread, c2pwrite = None, None errread, errwrite = None, None @@ -651,7 +651,7 @@ "for Popen to work with your shell or platform.") return w9xpopen - + def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, @@ -685,7 +685,7 @@ if startupinfo == None: startupinfo = STARTUPINFO() if not None in (p2cread, c2pwrite, errwrite): - startupinfo.dwFlags |= STARTF_USESTDHANDLES + startupinfo.dwFlags |= STARTF_USESTDHANDLES startupinfo.hStdInput = p2cread startupinfo.hStdOutput = c2pwrite startupinfo.hStdError = errwrite @@ -724,7 +724,7 @@ if errwrite != None: errwrite.Close() - + def poll(self): """Check if child process has terminated. Returns returncode attribute.""" @@ -830,7 +830,7 @@ c2pwrite = stdout else: # Assuming file-like object - c2pwrite = stdout.fileno() + c2pwrite = stdout.fileno() if stderr == None: pass @@ -867,8 +867,8 @@ os.close(i) except: pass - - + + def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, @@ -976,7 +976,7 @@ _active.remove(self) - + def poll(self): """Check if child process has terminated. Returns returncode attribute.""" @@ -1022,7 +1022,7 @@ self.stdin.close() if self.stdout: read_set.append(self.stdout) - stdout = [] + stdout = [] if self.stderr: read_set.append(self.stderr) stderr = [] @@ -1137,5 +1137,3 @@ _demo_windows() else: _demo_posix() - - From tim_one at users.sourceforge.net Tue Oct 12 23:51:35 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Tue Oct 12 23:51:41 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.1, 1.2 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15813/Lib/test Modified Files: test_subprocess.py Log Message: Whitespace normalization. Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- test_subprocess.py 12 Oct 2004 15:26:28 -0000 1.1 +++ test_subprocess.py 12 Oct 2004 21:51:32 -0000 1.2 @@ -26,7 +26,7 @@ else: fname = tempfile.mktemp() return os.open(fname, os.O_RDWR|os.O_CREAT), fname - + # # Generic tests # @@ -85,7 +85,7 @@ def test_stdin_filedes(self): """stdin is set to open file descriptor""" - tf = tempfile.TemporaryFile() + tf = tempfile.TemporaryFile() d = tf.fileno() os.write(d, "pear") os.lseek(d, 0, 0) @@ -115,7 +115,7 @@ def test_stdout_filedes(self): """stdout is set to open file descriptor""" - tf = tempfile.TemporaryFile() + tf = tempfile.TemporaryFile() d = tf.fileno() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stdout.write("orange")'], @@ -126,7 +126,7 @@ def test_stdout_fileobj(self): """stdout is set to open file object""" - tf = tempfile.TemporaryFile() + tf = tempfile.TemporaryFile() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stdout.write("orange")'], stdout=tf) @@ -143,7 +143,7 @@ def test_stderr_filedes(self): """stderr is set to open file descriptor""" - tf = tempfile.TemporaryFile() + tf = tempfile.TemporaryFile() d = tf.fileno() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stderr.write("strawberry")'], @@ -154,7 +154,7 @@ def test_stderr_fileobj(self): """stderr is set to open file object""" - tf = tempfile.TemporaryFile() + tf = tempfile.TemporaryFile() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stderr.write("strawberry")'], stderr=tf) @@ -230,7 +230,7 @@ def test_communicate_pipe_buf(self): """communicate() with writes larger than pipe_buf""" # This test will probably deadlock rather than fail, if - # communicate() does not work properly. + # communicate() does not work properly. x, y = os.pipe() if mswindows: pipe_buf = 512 @@ -239,7 +239,7 @@ os.close(x) os.close(y) p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' + 'import sys,os;' 'sys.stdout.write(sys.stdin.read(47));' \ 'sys.stderr.write("xyz"*%d);' \ 'sys.stdout.write(sys.stdin.read())' % pipe_buf], @@ -258,7 +258,7 @@ (stdout, stderr) = p.communicate("split") self.assertEqual(stdout, "bananasplit") self.assertEqual(stderr, "") - + def test_universal_newlines(self): """universal newlines""" p = subprocess.Popen([sys.executable, "-c", @@ -354,7 +354,7 @@ self.assertEqual(p.wait(), 0) # Subsequent invocations should just return the returncode self.assertEqual(p.wait(), 0) - + # # POSIX tests # @@ -370,7 +370,7 @@ self.assertNotEqual(e.child_traceback.find("os.chdir"), -1) else: self.fail("Expected OSError") - + def test_run_abort(self): """returncode handles signal termination""" p = subprocess.Popen([sys.executable, "-c", "import os; os.abort()"]) @@ -394,7 +394,7 @@ 'import sys,os;' \ 'sys.stdout.write(str(os.dup(0)))'], stdout=subprocess.PIPE, close_fds=1) - # When all fds are closed, the next free fd should be 3. + # When all fds are closed, the next free fd should be 3. self.assertEqual(p.stdout.read(), "3") def test_args_string(self): @@ -446,7 +446,7 @@ rc = subprocess.call(fname) self.assertEqual(rc, 47) - + # # Windows tests # @@ -454,7 +454,7 @@ def test_startupinfo(self): """startupinfo argument""" # We uses hardcoded constants, because we do not want to - # depend on win32all. + # depend on win32all. STARTF_USESHOWWINDOW = 1 SW_MAXIMIZE = 3 startupinfo = subprocess.STARTUPINFO() @@ -486,7 +486,7 @@ newenv = os.environ.copy() newenv["FRUIT"] = "physalis" p = subprocess.Popen(["set"], shell=1, - stdout=subprocess.PIPE, + stdout=subprocess.PIPE, env=newenv) self.assertNotEqual(p.stdout.read().find("physalis"), -1) @@ -495,7 +495,7 @@ newenv = os.environ.copy() newenv["FRUIT"] = "physalis" p = subprocess.Popen("set", shell=1, - stdout=subprocess.PIPE, + stdout=subprocess.PIPE, env=newenv) self.assertNotEqual(p.stdout.read().find("physalis"), -1) @@ -511,4 +511,3 @@ if __name__ == "__main__": test_main() - From tim_one at users.sourceforge.net Wed Oct 13 00:19:50 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 13 00:19:54 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.2, 1.3 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21294/Lib/test Modified Files: test_subprocess.py Log Message: Wrap long lines. Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- test_subprocess.py 12 Oct 2004 21:51:32 -0000 1.2 +++ test_subprocess.py 12 Oct 2004 22:19:32 -0000 1.3 @@ -14,7 +14,8 @@ # if mswindows: - SETBINARY = 'import msvcrt; msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY);' + SETBINARY = ('import msvcrt; msvcrt.setmode(sys.stdout.fileno(), ' + 'os.O_BINARY);') else: SETBINARY = '' @@ -32,7 +33,8 @@ # def test_call_seq(self): """call() function with sequence argument""" - rc = subprocess.call([sys.executable, "-c", "import sys; sys.exit(47)"]) + rc = subprocess.call([sys.executable, "-c", + "import sys; sys.exit(47)"]) self.assertEqual(rc, 47) def test_call_kwargs(self): @@ -68,8 +70,9 @@ def test_executable(self): """executable""" - p = subprocess.Popen(["somethingyoudonthave", "-c", "import sys; sys.exit(47)"], - executable=sys.executable) + p = subprocess.Popen(["somethingyoudonthave", + "-c", "import sys; sys.exit(47)"], + executable=sys.executable) p.wait() self.assertEqual(p.returncode, 47) @@ -215,14 +218,17 @@ 'import sys,os;' \ 'sys.stderr.write("pineapple");' \ 'sys.stdout.write(sys.stdin.read())'], - stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) (stdout, stderr) = p.communicate("banana") self.assertEqual(stdout, "banana") self.assertEqual(stderr, "pineapple") def test_communicate_returns(self): """communicate() should return None if no redirection is active""" - p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(47)"]) + p = subprocess.Popen([sys.executable, "-c", + "import sys; sys.exit(47)"]) (stdout, stderr) = p.communicate() self.assertEqual(stdout, None) self.assertEqual(stderr, None) @@ -243,7 +249,9 @@ 'sys.stdout.write(sys.stdin.read(47));' \ 'sys.stderr.write("xyz"*%d);' \ 'sys.stdout.write(sys.stdin.read())' % pipe_buf], - stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) string_to_write = "abc"*pipe_buf (stdout, stderr) = p.communicate(string_to_write) self.assertEqual(stdout, string_to_write) @@ -253,7 +261,9 @@ p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stdout.write(sys.stdin.read())'], - stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) p.stdin.write("banana") (stdout, stderr) = p.communicate("split") self.assertEqual(stdout, "bananasplit") @@ -262,49 +272,52 @@ def test_universal_newlines(self): """universal newlines""" p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' + SETBINARY + \ - 'sys.stdout.write("line1\\n");' \ - 'sys.stdout.flush();' \ - 'sys.stdout.write("line2\\r");' \ - 'sys.stdout.flush();' \ - 'sys.stdout.write("line3\\r\\n");' \ - 'sys.stdout.flush();' \ - 'sys.stdout.write("line4\\r");' \ - 'sys.stdout.flush();' \ + 'import sys,os;' + SETBINARY + + 'sys.stdout.write("line1\\n");' + 'sys.stdout.flush();' + 'sys.stdout.write("line2\\r");' + 'sys.stdout.flush();' + 'sys.stdout.write("line3\\r\\n");' + 'sys.stdout.flush();' + 'sys.stdout.write("line4\\r");' + 'sys.stdout.flush();' 'sys.stdout.write("\\nline5");' - 'sys.stdout.flush();' \ + 'sys.stdout.flush();' 'sys.stdout.write("\\nline6");'], stdout=subprocess.PIPE, universal_newlines=1) stdout = p.stdout.read() if hasattr(open, 'newlines'): # Interpreter with universal newline support - self.assertEqual(stdout, "line1\nline2\nline3\nline4\nline5\nline6") + self.assertEqual(stdout, + "line1\nline2\nline3\nline4\nline5\nline6") else: # Interpreter without universal newline support - self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6") + self.assertEqual(stdout, + "line1\nline2\rline3\r\nline4\r\nline5\nline6") def test_universal_newlines_communicate(self): """universal newlines through communicate()""" p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' + SETBINARY + \ - 'sys.stdout.write("line1\\n");' \ - 'sys.stdout.flush();' \ - 'sys.stdout.write("line2\\r");' \ - 'sys.stdout.flush();' \ - 'sys.stdout.write("line3\\r\\n");' \ - 'sys.stdout.flush();' \ - 'sys.stdout.write("line4\\r");' \ - 'sys.stdout.flush();' \ + 'import sys,os;' + SETBINARY + + 'sys.stdout.write("line1\\n");' + 'sys.stdout.flush();' + 'sys.stdout.write("line2\\r");' + 'sys.stdout.flush();' + 'sys.stdout.write("line3\\r\\n");' + 'sys.stdout.flush();' + 'sys.stdout.write("line4\\r");' + 'sys.stdout.flush();' 'sys.stdout.write("\\nline5");' - 'sys.stdout.flush();' \ + 'sys.stdout.flush();' 'sys.stdout.write("\\nline6");'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=1) (stdout, stderr) = p.communicate() if hasattr(open, 'newlines'): # Interpreter with universal newline support - self.assertEqual(stdout, "line1\nline2\nline3\nline4\nline5\nline6") + self.assertEqual(stdout, + "line1\nline2\nline3\nline4\nline5\nline6") else: # Interpreter without universal newline support self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6") @@ -312,8 +325,11 @@ def test_no_leaking(self): """Make sure we leak no resources""" for i in range(1026): - p = subprocess.Popen([sys.executable, "-c", "import sys;sys.stdout.write(sys.stdin.read())"], - stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + p = subprocess.Popen([sys.executable, "-c", + "import sys;sys.stdout.write(sys.stdin.read())"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) data = p.communicate("lime")[0] self.assertEqual(data, "lime") @@ -373,7 +389,8 @@ def test_run_abort(self): """returncode handles signal termination""" - p = subprocess.Popen([sys.executable, "-c", "import os; os.abort()"]) + p = subprocess.Popen([sys.executable, + "-c", "import os; os.abort()"]) p.wait() self.assertEqual(-p.returncode, signal.SIGABRT) @@ -401,7 +418,8 @@ """args is a string""" f, fname = self.mkstemp() os.write(f, "#!/bin/sh\n") - os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % sys.executable) + os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % + sys.executable) os.close(f) os.chmod(fname, 0700) p = subprocess.Popen(fname) @@ -412,10 +430,12 @@ def test_invalid_args(self): """invalid arguments should raise ValueError""" self.assertRaises(ValueError, subprocess.call, - [sys.executable, "-c", "import sys; sys.exit(47)"], + [sys.executable, + "-c", "import sys; sys.exit(47)"], startupinfo=47) self.assertRaises(ValueError, subprocess.call, - [sys.executable, "-c", "import sys; sys.exit(47)"], + [sys.executable, + "-c", "import sys; sys.exit(47)"], creationflags=47) def test_shell_sequence(self): @@ -440,7 +460,8 @@ """call() function with string argument on UNIX""" f, fname = self.mkstemp() os.write(f, "#!/bin/sh\n") - os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % sys.executable) + os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % + sys.executable) os.close(f) os.chmod(fname, 0700) rc = subprocess.call(fname) @@ -469,16 +490,19 @@ def test_creationflags(self): """creationflags argument""" CREATE_NEW_CONSOLE = 16 - subprocess.call(sys.executable + ' -c "import time; time.sleep(2)"', + subprocess.call(sys.executable + + ' -c "import time; time.sleep(2)"', creationflags=CREATE_NEW_CONSOLE) def test_invalid_args(self): """invalid arguments should raise ValueError""" self.assertRaises(ValueError, subprocess.call, - [sys.executable, "-c", "import sys; sys.exit(47)"], + [sys.executable, + "-c", "import sys; sys.exit(47)"], preexec_fn=lambda: 1) self.assertRaises(ValueError, subprocess.call, - [sys.executable, "-c", "import sys; sys.exit(47)"], + [sys.executable, + "-c", "import sys; sys.exit(47)"], close_fds=True) def test_shell_sequence(self): @@ -501,11 +525,11 @@ def test_call_string(self): """call() function with string argument on Windows""" - rc = subprocess.call(sys.executable + ' -c "import sys; sys.exit(47)"') + rc = subprocess.call(sys.executable + + ' -c "import sys; sys.exit(47)"') self.assertEqual(rc, 47) - def test_main(): test_support.run_unittest(ProcessTestCase) From tim_one at users.sourceforge.net Wed Oct 13 00:29:57 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 13 00:29:59 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.3, 1.4 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22755/Lib/test Modified Files: test_subprocess.py Log Message: Experience with Zope2's tests showed it's a Bad Idea to make unittest display a test's docstring as "the name" of the test. So changed most test docstrings to comments, and removed the clearly useless ones. Now unittest reports the actual names of the test methods. Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- test_subprocess.py 12 Oct 2004 22:19:32 -0000 1.3 +++ test_subprocess.py 12 Oct 2004 22:29:54 -0000 1.4 @@ -32,13 +32,13 @@ # Generic tests # def test_call_seq(self): - """call() function with sequence argument""" + # call() function with sequence argument rc = subprocess.call([sys.executable, "-c", "import sys; sys.exit(47)"]) self.assertEqual(rc, 47) def test_call_kwargs(self): - """call() function with keyword args""" + # call() function with keyword args newenv = os.environ.copy() newenv["FRUIT"] = "banana" rc = subprocess.call([sys.executable, "-c", @@ -48,28 +48,27 @@ self.assertEqual(rc, 1) def test_stdin_none(self): - """.stdin is None when not redirected""" + # .stdin is None when not redirected p = subprocess.Popen([sys.executable, "-c", 'print "banana"'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) p.wait() self.assertEqual(p.stdin, None) def test_stdout_none(self): - """.stdout is None when not redirected""" + # .stdout is None when not redirected p = subprocess.Popen([sys.executable, "-c", 'print "banana"'], stdin=subprocess.PIPE, stderr=subprocess.PIPE) p.wait() self.assertEqual(p.stdout, None) def test_stderr_none(self): - """.stderr is None when not redirected""" + # .stderr is None when not redirected p = subprocess.Popen([sys.executable, "-c", 'print "banana"'], stdin=subprocess.PIPE, stdout=subprocess.PIPE) p.wait() self.assertEqual(p.stderr, None) def test_executable(self): - """executable""" p = subprocess.Popen(["somethingyoudonthave", "-c", "import sys; sys.exit(47)"], executable=sys.executable) @@ -77,7 +76,7 @@ self.assertEqual(p.returncode, 47) def test_stdin_pipe(self): - """stdin redirection""" + # stdin redirection p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.exit(sys.stdin.read() == "pear")'], stdin=subprocess.PIPE) @@ -87,7 +86,7 @@ self.assertEqual(p.returncode, 1) def test_stdin_filedes(self): - """stdin is set to open file descriptor""" + # stdin is set to open file descriptor tf = tempfile.TemporaryFile() d = tf.fileno() os.write(d, "pear") @@ -99,7 +98,7 @@ self.assertEqual(p.returncode, 1) def test_stdin_fileobj(self): - """stdin is set to open file object""" + # stdin is set to open file object tf = tempfile.TemporaryFile() tf.write("pear") tf.seek(0) @@ -110,14 +109,14 @@ self.assertEqual(p.returncode, 1) def test_stdout_pipe(self): - """stdout redirection""" + # stdout redirection p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stdout.write("orange")'], stdout=subprocess.PIPE) self.assertEqual(p.stdout.read(), "orange") def test_stdout_filedes(self): - """stdout is set to open file descriptor""" + # stdout is set to open file descriptor tf = tempfile.TemporaryFile() d = tf.fileno() p = subprocess.Popen([sys.executable, "-c", @@ -128,7 +127,7 @@ self.assertEqual(os.read(d, 1024), "orange") def test_stdout_fileobj(self): - """stdout is set to open file object""" + # stdout is set to open file object tf = tempfile.TemporaryFile() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stdout.write("orange")'], @@ -138,14 +137,14 @@ self.assertEqual(tf.read(), "orange") def test_stderr_pipe(self): - """stderr redirection""" + # stderr redirection p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stderr.write("strawberry")'], stderr=subprocess.PIPE) self.assertEqual(p.stderr.read(), "strawberry") def test_stderr_filedes(self): - """stderr is set to open file descriptor""" + # stderr is set to open file descriptor tf = tempfile.TemporaryFile() d = tf.fileno() p = subprocess.Popen([sys.executable, "-c", @@ -156,7 +155,7 @@ self.assertEqual(os.read(d, 1024), "strawberry") def test_stderr_fileobj(self): - """stderr is set to open file object""" + # stderr is set to open file object tf = tempfile.TemporaryFile() p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stderr.write("strawberry")'], @@ -166,7 +165,7 @@ self.assertEqual(tf.read(), "strawberry") def test_stdout_stderr_pipe(self): - """capture stdout and stderr to the same pipe""" + # capture stdout and stderr to the same pipe p = subprocess.Popen([sys.executable, "-c", 'import sys;' \ 'sys.stdout.write("apple");' \ @@ -177,7 +176,7 @@ self.assertEqual(p.stdout.read(), "appleorange") def test_stdout_stderr_file(self): - """capture stdout and stderr to the same open file""" + # capture stdout and stderr to the same open file tf = tempfile.TemporaryFile() p = subprocess.Popen([sys.executable, "-c", 'import sys;' \ @@ -191,7 +190,6 @@ self.assertEqual(tf.read(), "appleorange") def test_cwd(self): - """cwd""" tmpdir = os.getenv("TEMP", "/tmp") tmpdir = os.path.realpath(tmpdir) p = subprocess.Popen([sys.executable, "-c", @@ -202,7 +200,6 @@ self.assertEqual(p.stdout.read(), tmpdir) def test_env(self): - """env""" newenv = os.environ.copy() newenv["FRUIT"] = "orange" p = subprocess.Popen([sys.executable, "-c", @@ -213,7 +210,6 @@ self.assertEqual(p.stdout.read(), "orange") def test_communicate(self): - """communicate()""" p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stderr.write("pineapple");' \ @@ -226,7 +222,7 @@ self.assertEqual(stderr, "pineapple") def test_communicate_returns(self): - """communicate() should return None if no redirection is active""" + # communicate() should return None if no redirection is active p = subprocess.Popen([sys.executable, "-c", "import sys; sys.exit(47)"]) (stdout, stderr) = p.communicate() @@ -234,7 +230,7 @@ self.assertEqual(stderr, None) def test_communicate_pipe_buf(self): - """communicate() with writes larger than pipe_buf""" + # communicate() with writes larger than pipe_buf # This test will probably deadlock rather than fail, if # communicate() does not work properly. x, y = os.pipe() @@ -257,7 +253,7 @@ self.assertEqual(stdout, string_to_write) def test_writes_before_communicate(self): - """stdin.write before communicate()""" + # stdin.write before communicate() p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stdout.write(sys.stdin.read())'], @@ -270,7 +266,6 @@ self.assertEqual(stderr, "") def test_universal_newlines(self): - """universal newlines""" p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' + SETBINARY + 'sys.stdout.write("line1\\n");' @@ -297,7 +292,7 @@ "line1\nline2\rline3\r\nline4\r\nline5\nline6") def test_universal_newlines_communicate(self): - """universal newlines through communicate()""" + # universal newlines through communicate() p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' + SETBINARY + 'sys.stdout.write("line1\\n");' @@ -323,7 +318,7 @@ self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6") def test_no_leaking(self): - """Make sure we leak no resources""" + # Make sure we leak no resources for i in range(1026): p = subprocess.Popen([sys.executable, "-c", "import sys;sys.stdout.write(sys.stdin.read())"], @@ -335,8 +330,6 @@ def test_list2cmdline(self): - """list2cmdline""" - self.assertEqual(subprocess.list2cmdline(['a b c', 'd', 'e']), '"a b c" d e') self.assertEqual(subprocess.list2cmdline(['ab"c', '\\', 'd']), @@ -352,7 +345,6 @@ def test_poll(self): - """poll""" p = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(4)"]) while p.poll() == None: @@ -364,7 +356,6 @@ def test_wait(self): - """wait""" p = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(2)"]) self.assertEqual(p.wait(), 0) @@ -376,7 +367,7 @@ # if not mswindows: def test_exceptions(self): - """catched & re-raised exceptions""" + # catched & re-raised exceptions try: p = subprocess.Popen([sys.executable, "-c", ""], cwd="/this/path/does/not/exist") @@ -388,14 +379,14 @@ self.fail("Expected OSError") def test_run_abort(self): - """returncode handles signal termination""" + # returncode handles signal termination p = subprocess.Popen([sys.executable, "-c", "import os; os.abort()"]) p.wait() self.assertEqual(-p.returncode, signal.SIGABRT) def test_preexec(self): - """preexec function""" + # preexec function p = subprocess.Popen([sys.executable, "-c", 'import sys,os;' \ 'sys.stdout.write(os.getenv("FRUIT"))'], @@ -404,7 +395,6 @@ self.assertEqual(p.stdout.read(), "apple") def test_close_fds(self): - """close_fds""" # Make sure we have some fds open os.pipe() p = subprocess.Popen([sys.executable, "-c", @@ -415,7 +405,7 @@ self.assertEqual(p.stdout.read(), "3") def test_args_string(self): - """args is a string""" + # args is a string f, fname = self.mkstemp() os.write(f, "#!/bin/sh\n") os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % @@ -428,7 +418,7 @@ os.remove(fname) def test_invalid_args(self): - """invalid arguments should raise ValueError""" + # invalid arguments should raise ValueError self.assertRaises(ValueError, subprocess.call, [sys.executable, "-c", "import sys; sys.exit(47)"], @@ -439,7 +429,7 @@ creationflags=47) def test_shell_sequence(self): - """Run command through the shell (sequence)""" + # Run command through the shell (sequence) newenv = os.environ.copy() newenv["FRUIT"] = "apple" p = subprocess.Popen(["echo $FRUIT"], shell=1, @@ -448,7 +438,7 @@ self.assertEqual(p.stdout.read().strip(), "apple") def test_shell_string(self): - """Run command through the shell (string)""" + # Run command through the shell (string) newenv = os.environ.copy() newenv["FRUIT"] = "apple" p = subprocess.Popen("echo $FRUIT", shell=1, @@ -457,7 +447,7 @@ self.assertEqual(p.stdout.read().strip(), "apple") def test_call_string(self): - """call() function with string argument on UNIX""" + # call() function with string argument on UNIX f, fname = self.mkstemp() os.write(f, "#!/bin/sh\n") os.write(f, "exec %s -c 'import sys; sys.exit(47)'\n" % @@ -473,7 +463,7 @@ # if mswindows: def test_startupinfo(self): - """startupinfo argument""" + # startupinfo argument # We uses hardcoded constants, because we do not want to # depend on win32all. STARTF_USESHOWWINDOW = 1 @@ -488,14 +478,14 @@ startupinfo=startupinfo) def test_creationflags(self): - """creationflags argument""" + # creationflags argument CREATE_NEW_CONSOLE = 16 subprocess.call(sys.executable + ' -c "import time; time.sleep(2)"', creationflags=CREATE_NEW_CONSOLE) def test_invalid_args(self): - """invalid arguments should raise ValueError""" + # invalid arguments should raise ValueError self.assertRaises(ValueError, subprocess.call, [sys.executable, "-c", "import sys; sys.exit(47)"], @@ -506,7 +496,7 @@ close_fds=True) def test_shell_sequence(self): - """Run command through the shell (sequence)""" + # Run command through the shell (sequence) newenv = os.environ.copy() newenv["FRUIT"] = "physalis" p = subprocess.Popen(["set"], shell=1, @@ -515,7 +505,7 @@ self.assertNotEqual(p.stdout.read().find("physalis"), -1) def test_shell_string(self): - """Run command through the shell (string)""" + # Run command through the shell (string) newenv = os.environ.copy() newenv["FRUIT"] = "physalis" p = subprocess.Popen("set", shell=1, @@ -524,7 +514,7 @@ self.assertNotEqual(p.stdout.read().find("physalis"), -1) def test_call_string(self): - """call() function with string argument on Windows""" + # call() function with string argument on Windows rc = subprocess.call(sys.executable + ' -c "import sys; sys.exit(47)"') self.assertEqual(rc, 47) From tim_one at users.sourceforge.net Wed Oct 13 05:14:42 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 13 05:14:44 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.4, 1.5 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15311/lib/test Modified Files: test_subprocess.py Log Message: XXX about extreme expense of test_no_leaking() on Windows. I'm not sure what this is trying to do. If it's necessary for it to create > 1000 processes, it should be controlled by a new resource and not run by default on Windows. Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- test_subprocess.py 12 Oct 2004 22:29:54 -0000 1.4 +++ test_subprocess.py 13 Oct 2004 03:14:40 -0000 1.5 @@ -317,6 +317,7 @@ # Interpreter without universal newline support self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6") + # XXX test_no_leaking takes > a minute to run on a high-end WinXP Pro box def test_no_leaking(self): # Make sure we leak no resources for i in range(1026): From tim_one at users.sourceforge.net Wed Oct 13 05:15:02 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 13 05:15:05 2004 Subject: [Python-checkins] python/dist/src/Lib subprocess.py,1.3,1.4 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15580/Lib Modified Files: subprocess.py Log Message: Folded long lines. Index: subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/subprocess.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- subprocess.py 12 Oct 2004 21:51:32 -0000 1.3 +++ subprocess.py 13 Oct 2004 03:15:00 -0000 1.4 @@ -378,11 +378,15 @@ error = IOError except ImportError: import pywintypes - from win32api import GetStdHandle, STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE - from win32api import GetCurrentProcess, DuplicateHandle, GetModuleFileName, GetVersion + from win32api import GetStdHandle, STD_INPUT_HANDLE, \ + STD_OUTPUT_HANDLE, STD_ERROR_HANDLE + from win32api import GetCurrentProcess, DuplicateHandle, \ + GetModuleFileName, GetVersion from win32con import DUPLICATE_SAME_ACCESS from win32pipe import CreatePipe - from win32process import CreateProcess, STARTUPINFO, GetExitCodeProcess, STARTF_USESTDHANDLES, CREATE_NEW_CONSOLE + from win32process import CreateProcess, STARTUPINFO, \ + GetExitCodeProcess, STARTF_USESTDHANDLES, \ + CREATE_NEW_CONSOLE from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 else: import select @@ -502,16 +506,20 @@ _cleanup() if mswindows: - if preexec_fn != None: - raise ValueError("preexec_fn is not supported on Windows platforms") + if preexec_fn is not None: + raise ValueError("preexec_fn is not supported on Windows " + "platforms") if close_fds: - raise ValueError("close_fds is not supported on Windows platforms") + raise ValueError("close_fds is not supported on Windows " + "platforms") else: # POSIX - if startupinfo != None: - raise ValueError("startupinfo is only supported on Windows platforms") + if startupinfo is not None: + raise ValueError("startupinfo is only supported on Windows " + "platforms") if creationflags != 0: - raise ValueError("creationflags is only supported on Windows platforms") + raise ValueError("creationflags is only supported on Windows " + "platforms") self.stdin = None self.stdout = None @@ -641,14 +649,17 @@ def _find_w9xpopen(self): """Find and return absolut path to w9xpopen.exe""" - w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)), "w9xpopen.exe") + w9xpopen = os.path.join(os.path.dirname(GetModuleFileName(0)), + "w9xpopen.exe") if not os.path.exists(w9xpopen): # Eeek - file-not-found - possibly an embedding # situation - see if we can locate it in sys.exec_prefix - w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix), "w9xpopen.exe") + w9xpopen = os.path.join(os.path.dirname(sys.exec_prefix), + "w9xpopen.exe") if not os.path.exists(w9xpopen): - raise RuntimeError("Cannot locate w9xpopen.exe, which is needed " - "for Popen to work with your shell or platform.") + raise RuntimeError("Cannot locate w9xpopen.exe, which is " + "needed for Popen to work with your " + "shell or platform.") return w9xpopen @@ -666,7 +677,8 @@ if shell: comspec = os.environ.get("COMSPEC", "cmd.exe") args = comspec + " /c " + args - if GetVersion() >= 0x80000000L or os.path.basename(comspec).lower() == "command.com": + if (GetVersion() >= 0x80000000L or + os.path.basename(comspec).lower() == "command.com"): # Win9x, or using command.com on NT. We need to # use the w9xpopen intermediate program. For more # information, see KB Q150956 @@ -693,12 +705,15 @@ # Start the process try: hp, ht, pid, tid = CreateProcess(executable, args, - None, None, # No special security - 1, # Must inherit handles to pass std handles - creationflags, - env, - cwd, - startupinfo) + # no special security + None, None, + # must inherit handles to pass std + # handles + 1, + creationflags, + env, + cwd, + startupinfo) except pywintypes.error, e: # Translate pywintypes.error to WindowsError, which is # a subclass of OSError. FIXME: We should really @@ -762,12 +777,14 @@ if self.stdout: stdout = [] - stdout_thread = threading.Thread(target=self._readerthread, args=(self.stdout, stdout,)) + stdout_thread = threading.Thread(target=self._readerthread, + args=(self.stdout, stdout)) stdout_thread.setDaemon(True) stdout_thread.start() if self.stderr: stderr = [] - stderr_thread = threading.Thread(target=self._readerthread, args=(self.stderr, stderr,)) + stderr_thread = threading.Thread(target=self._readerthread, + args=(self.stderr, stderr)) stderr_thread.setDaemon(True) stderr_thread.start() @@ -940,7 +957,9 @@ except: exc_type, exc_value, tb = sys.exc_info() # Save the traceback and attach it to the exception object - exc_lines = traceback.format_exception(exc_type, exc_value, tb) + exc_lines = traceback.format_exception(exc_type, + exc_value, + tb) exc_value.child_traceback = ''.join(exc_lines) os.write(errpipe_write, pickle.dumps(exc_value)) From tim_one at users.sourceforge.net Wed Oct 13 05:21:37 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 13 05:21:40 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.5, 1.6 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16613/Lib/test Modified Files: test_subprocess.py Log Message: Windows test_creationflags() test: print msg to stderr informing the tester that a DOS box is expected to flash. Slash the sleep from 2 seconds to a quarter second (why would we want to wait 2 seconds just to stare at a DOS box?). Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- test_subprocess.py 13 Oct 2004 03:14:40 -0000 1.5 +++ test_subprocess.py 13 Oct 2004 03:21:35 -0000 1.6 @@ -481,8 +481,9 @@ def test_creationflags(self): # creationflags argument CREATE_NEW_CONSOLE = 16 + sys.stderr.write(" a DOS box should flash briefly ...\n") subprocess.call(sys.executable + - ' -c "import time; time.sleep(2)"', + ' -c "import time; time.sleep(0.25)"', creationflags=CREATE_NEW_CONSOLE) def test_invalid_args(self): From tim_one at users.sourceforge.net Wed Oct 13 05:29:57 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 13 05:29:59 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.6, 1.7 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18553/Lib/test Modified Files: test_subprocess.py Log Message: test_stdout_none(): Don't print "banana" to the screen in the middle of the test. It's testing stdout in a different process, so it has to print something, but I didn't find "banana" to be self-explanatory. Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- test_subprocess.py 13 Oct 2004 03:21:35 -0000 1.6 +++ test_subprocess.py 13 Oct 2004 03:29:54 -0000 1.7 @@ -56,8 +56,11 @@ def test_stdout_none(self): # .stdout is None when not redirected - p = subprocess.Popen([sys.executable, "-c", 'print "banana"'], - stdin=subprocess.PIPE, stderr=subprocess.PIPE) + p = subprocess.Popen([sys.executable, "-c", + 'print " this bit of output is from a ' + 'test of stdout in a different ' + 'process ..."'], + stdin=subprocess.PIPE, stderr=subprocess.PIPE) p.wait() self.assertEqual(p.stdout, None) From tim_one at users.sourceforge.net Wed Oct 13 05:43:42 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 13 05:43:45 2004 Subject: [Python-checkins] python/dist/src/Lib/test/output test_subprocess, 1.1, NONE Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test/output In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19774/Lib/test/output Removed Files: test_subprocess Log Message: Kill several problems at once: test_poll() failed sometimes for me. Turns out the mysterious "expected output" file contained exactly N dots, because test_poll() has a loop that *usually* went around N times, printing one dot on each loop trip. But there's no guarantee of that, because the exact value of N depended on the vagaries of scheduling time.sleep()s across two different processes. So stopped printing dots, and got rid of the expected output file. Add a loop counter instead, and verify that the loop goes around at least a couple of times. Also cut the minimum time needed for this test from 4 seconds to 1. --- test_subprocess DELETED --- From tim_one at users.sourceforge.net Wed Oct 13 05:43:42 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 13 05:43:48 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.7, 1.8 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19774/Lib/test Modified Files: test_subprocess.py Log Message: Kill several problems at once: test_poll() failed sometimes for me. Turns out the mysterious "expected output" file contained exactly N dots, because test_poll() has a loop that *usually* went around N times, printing one dot on each loop trip. But there's no guarantee of that, because the exact value of N depended on the vagaries of scheduling time.sleep()s across two different processes. So stopped printing dots, and got rid of the expected output file. Add a loop counter instead, and verify that the loop goes around at least a couple of times. Also cut the minimum time needed for this test from 4 seconds to 1. Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- test_subprocess.py 13 Oct 2004 03:29:54 -0000 1.7 +++ test_subprocess.py 13 Oct 2004 03:43:40 -0000 1.8 @@ -56,7 +56,7 @@ def test_stdout_none(self): # .stdout is None when not redirected - p = subprocess.Popen([sys.executable, "-c", + p = subprocess.Popen([sys.executable, "-c", 'print " this bit of output is from a ' 'test of stdout in a different ' 'process ..."'], @@ -350,11 +350,16 @@ def test_poll(self): p = subprocess.Popen([sys.executable, - "-c", "import time; time.sleep(4)"]) - while p.poll() == None: - sys.stdout.write(".") - sys.stdout.flush() - time.sleep(0.5) + "-c", "import time; time.sleep(1)"]) + count = 0 + while p.poll() is None: + time.sleep(0.1) + count += 1 + # We expect that the poll loop probably went around about 10 times, + # but, based on system scheduling we can't control, it's possible + # poll() never returned None. It "should be" very rare that it + # didn't go around at least twice. + self.assert_(count >= 2) # Subsequent invocations should just return the returncode self.assertEqual(p.poll(), 0) From tim_one at users.sourceforge.net Wed Oct 13 06:07:15 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 13 06:07:18 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.8, 1.9 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24554/Lib/test Modified Files: test_subprocess.py Log Message: New helper remove_stderr_debug_decorations(). This test passes in a debug build on Windows now. More applications of the helper may be needed on non-Windows platforms. Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- test_subprocess.py 13 Oct 2004 03:43:40 -0000 1.8 +++ test_subprocess.py 13 Oct 2004 04:07:12 -0000 1.9 @@ -6,6 +6,7 @@ import os import tempfile import time +import re mswindows = (sys.platform == "win32") @@ -19,6 +20,14 @@ else: SETBINARY = '' +# In a debug build, stuff like "[6580 refs]" is printed to stderr at +# shutdown time. That frustrates tests trying to check stderr produced +# from a spawned Python process. +def remove_stderr_debug_decorations(stderr): + if __debug__: + stderr = re.sub(r"\[\d+ refs\]\r?\n?$", "", stderr) + return stderr + class ProcessTestCase(unittest.TestCase): def mkstemp(self): """wrapper for mkstemp, calling mktemp if mkstemp is not available""" @@ -144,7 +153,8 @@ p = subprocess.Popen([sys.executable, "-c", 'import sys; sys.stderr.write("strawberry")'], stderr=subprocess.PIPE) - self.assertEqual(p.stderr.read(), "strawberry") + self.assertEqual(remove_stderr_debug_decorations(p.stderr.read()), + "strawberry") def test_stderr_filedes(self): # stderr is set to open file descriptor @@ -155,7 +165,8 @@ stderr=d) p.wait() os.lseek(d, 0, 0) - self.assertEqual(os.read(d, 1024), "strawberry") + self.assertEqual(remove_stderr_debug_decorations(os.read(d, 1024)), + "strawberry") def test_stderr_fileobj(self): # stderr is set to open file object @@ -165,7 +176,8 @@ stderr=tf) p.wait() tf.seek(0) - self.assertEqual(tf.read(), "strawberry") + self.assertEqual(remove_stderr_debug_decorations(tf.read()), + "strawberry") def test_stdout_stderr_pipe(self): # capture stdout and stderr to the same pipe @@ -176,7 +188,9 @@ 'sys.stderr.write("orange")'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - self.assertEqual(p.stdout.read(), "appleorange") + output = p.stdout.read() + stripped = remove_stderr_debug_decorations(output) + self.assertEqual(stripped, "appleorange") def test_stdout_stderr_file(self): # capture stdout and stderr to the same open file @@ -190,7 +204,9 @@ stderr=tf) p.wait() tf.seek(0) - self.assertEqual(tf.read(), "appleorange") + output = tf.read() + stripped = remove_stderr_debug_decorations(output) + self.assertEqual(stripped, "appleorange") def test_cwd(self): tmpdir = os.getenv("TEMP", "/tmp") @@ -222,7 +238,8 @@ stderr=subprocess.PIPE) (stdout, stderr) = p.communicate("banana") self.assertEqual(stdout, "banana") - self.assertEqual(stderr, "pineapple") + self.assertEqual(remove_stderr_debug_decorations(stderr), + "pineapple") def test_communicate_returns(self): # communicate() should return None if no redirection is active @@ -266,7 +283,7 @@ p.stdin.write("banana") (stdout, stderr) = p.communicate("split") self.assertEqual(stdout, "bananasplit") - self.assertEqual(stderr, "") + self.assertEqual(remove_stderr_debug_decorations(stderr), "") def test_universal_newlines(self): p = subprocess.Popen([sys.executable, "-c", From loewis at users.sourceforge.net Wed Oct 13 07:29:42 2004 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed Oct 13 07:29:45 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_pep263.py,1.3,1.4 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6058 Modified Files: test_pep263.py Log Message: Add a comment explaining -kb. Index: test_pep263.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_pep263.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- test_pep263.py 30 Aug 2003 22:54:55 -0000 1.3 +++ test_pep263.py 13 Oct 2004 05:29:39 -0000 1.4 @@ -1,4 +1,5 @@ #! -*- coding: koi8-r -*- +# This file is marked as binary in the CVS, to prevent MacCVS from recoding it. import unittest from test import test_support From effbot at users.sourceforge.net Wed Oct 13 08:48:40 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Wed Oct 13 08:48:43 2004 Subject: [Python-checkins] python/dist/src/Lib xmlrpclib.py,1.35,1.36 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19105/Lib Modified Files: xmlrpclib.py Log Message: removed info@pythonware.com reference (should probably remove all traces of _xmlrpclib, but I'll leave that for another day.) Index: xmlrpclib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/xmlrpclib.py,v retrieving revision 1.35 retrieving revision 1.36 diff -u -d -r1.35 -r1.36 --- xmlrpclib.py 22 Aug 2004 16:04:50 -0000 1.35 +++ xmlrpclib.py 13 Oct 2004 06:48:37 -0000 1.36 @@ -439,8 +439,7 @@ # XML parsers try: - # optional xmlrpclib accelerator. for more information on this - # component, contact info@pythonware.com + # optional xmlrpclib accelerator import _xmlrpclib FastParser = _xmlrpclib.Parser FastUnmarshaller = _xmlrpclib.Unmarshaller From effbot at users.sourceforge.net Wed Oct 13 08:55:42 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Wed Oct 13 08:55:45 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.9, 1.10 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20569/Lib/test Modified Files: test_subprocess.py Log Message: normalize case when comparing directory names (problem reported by "Khalid A. B." on python-dev) Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- test_subprocess.py 13 Oct 2004 04:07:12 -0000 1.9 +++ test_subprocess.py 13 Oct 2004 06:55:40 -0000 1.10 @@ -216,7 +216,8 @@ 'sys.stdout.write(os.getcwd())'], stdout=subprocess.PIPE, cwd=tmpdir) - self.assertEqual(p.stdout.read(), tmpdir) + normcase = os.path.normcase + self.assertEqual(normcase(p.stdout.read()), normcase(tmpdir)) def test_env(self): newenv = os.environ.copy() From theller at python.net Wed Oct 13 09:41:45 2004 From: theller at python.net (Thomas Heller) Date: Wed Oct 13 09:41:28 2004 Subject: [Python-checkins] python/dist/src/Lib subprocess.py,NONE,1.1 In-Reply-To: (effbot@users.sourceforge.net's message of "Tue, 12 Oct 2004 08:26:29 -0700") References: Message-ID: effbot@users.sourceforge.net writes: > Update of /cvsroot/python/python/dist/src/Lib > In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24287/Lib > > Added Files: > subprocess.py > Log Message: > Added Peter Astrand's subprocess module. I suggest to remove the imports of the pywin32 stuff, it's not needed and confuses tools like freeze or py2exe. if mswindows: import threading import msvcrt try: from _subprocess import * class STARTUPINFO: dwFlags = 0 hStdInput = None hStdOutput = None hStdError = None class pywintypes: error = IOError except ImportError: import pywintypes from win32api import GetStdHandle, STD_INPUT_HANDLE, \ STD_OUTPUT_HANDLE, STD_ERROR_HANDLE from win32api import GetCurrentProcess, DuplicateHandle, \ GetModuleFileName, GetVersion from win32con import DUPLICATE_SAME_ACCESS from win32pipe import CreatePipe from win32process import CreateProcess, STARTUPINFO, \ GetExitCodeProcess, STARTF_USESTDHANDLES, \ CREATE_NEW_CONSOLE from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 From effbot at users.sourceforge.net Wed Oct 13 09:54:57 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Wed Oct 13 09:55:01 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.10, 1.11 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32411/Lib/test Modified Files: test_subprocess.py Log Message: Don't spend quite as much time looking for leaks on Windows, where it's rather expensive to create new processes. Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- test_subprocess.py 13 Oct 2004 06:55:40 -0000 1.10 +++ test_subprocess.py 13 Oct 2004 07:54:54 -0000 1.11 @@ -338,10 +338,12 @@ # Interpreter without universal newline support self.assertEqual(stdout, "line1\nline2\rline3\r\nline4\r\nline5\nline6") - # XXX test_no_leaking takes > a minute to run on a high-end WinXP Pro box def test_no_leaking(self): # Make sure we leak no resources - for i in range(1026): + max_handles = 1026 # too much for most UNIX systems + if mswindows: + max_handles = 65 # a full test is too slow on Windows + for i in range(max_handles): p = subprocess.Popen([sys.executable, "-c", "import sys;sys.stdout.write(sys.stdin.read())"], stdin=subprocess.PIPE, From anthonybaxter at users.sourceforge.net Wed Oct 13 14:35:30 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 14:35:34 2004 Subject: [Python-checkins] python/dist/src/Lib/distutils/command __init__.py, 1.19, 1.20 install.py, 1.70, 1.71 checkdep.py, 1.1, NONE Message-ID: Update of /cvsroot/python/python/dist/src/Lib/distutils/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29037/command Modified Files: __init__.py install.py Removed Files: checkdep.py Log Message: Backing out the basic dependency checking (from pycon sprint). This support was only a first cut, and doesn't deserve to be in a released version (where we have to support it in an ongoing manner) Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/command/__init__.py,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- __init__.py 22 Mar 2004 22:22:05 -0000 1.19 +++ __init__.py 13 Oct 2004 12:35:28 -0000 1.20 @@ -24,7 +24,6 @@ 'bdist_dumb', 'bdist_rpm', 'bdist_wininst', - 'checkdep', # These two are reserved for future use: #'bdist_sdux', #'bdist_pkgtool', Index: install.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/command/install.py,v retrieving revision 1.70 retrieving revision 1.71 diff -u -d -r1.70 -r1.71 --- install.py 18 Jul 2004 06:14:43 -0000 1.70 +++ install.py 13 Oct 2004 12:35:28 -0000 1.71 @@ -126,8 +126,6 @@ "force installation (overwrite any existing files)"), ('skip-build', None, "skip rebuilding everything (for testing/debugging)"), - ('skip-checkdep', None, - "skip checking dependencies (use at own risk)"), # Where to install documentation (eventually!) #('doc-format=', None, "format of documentation to generate"), @@ -185,15 +183,12 @@ # 'force' forces installation, even if target files are not # out-of-date. 'skip_build' skips running the "build" command, - # handy if you know it's not necessary. 'skip_checkdep' skips - # the 'checkdep' command, if you are sure you can work around the - # dependency failure in another way. 'warn_dir' (which is *not* + # handy if you know it's not necessary. 'warn_dir' (which is *not* # a user option, it's just there so the bdist_* commands can turn # it off) determines whether we warn about installing to a # directory not in sys.path. self.force = 0 self.skip_build = 0 - self.skip_checkdep = 0 self.warn_dir = 1 # These are only here as a conduit from the 'build' command to the @@ -505,12 +500,6 @@ if not self.skip_build: self.run_command('build') - # We check dependencies before we install - # For now, this is disabled. Before 2.4 is released, this will - # be turned on. - #if not self.skip_checkdep: - # self.run_command('checkdep') - # Run all sub-commands (at least those that need to be run) for cmd_name in self.get_sub_commands(): self.run_command(cmd_name) --- checkdep.py DELETED --- From anthonybaxter at users.sourceforge.net Wed Oct 13 14:35:30 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 14:35:35 2004 Subject: [Python-checkins] python/dist/src/Lib/distutils core.py, 1.61, 1.62 dist.py, 1.69, 1.70 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/distutils In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29037 Modified Files: core.py dist.py Log Message: Backing out the basic dependency checking (from pycon sprint). This support was only a first cut, and doesn't deserve to be in a released version (where we have to support it in an ongoing manner) Index: core.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/core.py,v retrieving revision 1.61 retrieving revision 1.62 diff -u -d -r1.61 -r1.62 --- core.py 18 Jul 2004 06:14:42 -0000 1.61 +++ core.py 13 Oct 2004 12:35:27 -0000 1.62 @@ -47,8 +47,7 @@ 'name', 'version', 'author', 'author_email', 'maintainer', 'maintainer_email', 'url', 'license', 'description', 'long_description', 'keywords', - 'platforms', 'classifiers', 'download_url', - 'provides', 'requires', ) + 'platforms', 'classifiers', 'download_url',) # Legal keyword arguments for the Extension constructor extension_keywords = ('name', 'sources', 'include_dirs', Index: dist.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/dist.py,v retrieving revision 1.69 retrieving revision 1.70 diff -u -d -r1.69 -r1.70 --- dist.py 3 Aug 2004 16:37:39 -0000 1.69 +++ dist.py 13 Oct 2004 12:35:27 -0000 1.70 @@ -223,51 +223,6 @@ else: sys.stderr.write(msg + "\n") - # Build up the requires sequence - from distutils.version import LooseVersion - requires = attrs.get('requires') - if requires: - if isinstance(requires, type('')): - raise DistutilsOptionError, 'requires should be a sequence' - newreq = [] - for req in requires: - if '-' not in req: - # We have a plain package name - any version will do - newreq.append((req,None)) - else: - pkg, ver = string.split(req, '-', 1) - newreq.append((pkg, LooseVersion(ver))) - attrs['requires'] = newreq - - # Build up the provides object. If the setup() has no - # provides line, we use packages or modules and the version - # to synthesise the provides. If no version is provided (no - # pun intended) we don't have a provides entry at all. - provides = attrs.get('provides') - if provides: - if isinstance(provides, type('')): - raise DistutilsOptionError, 'provides should be a sequence' - newprov = [] - for prov in provides: - if '-' not in prov: - # We have a plain package name - any version will do - newprov.append((prov,None)) - else: - pkg, ver = string.split(prov, '-', 1) - newprov.append((pkg, LooseVersion(ver))) - attrs['provides'] = newprov - elif attrs.get('version'): - # Build a provides line - prov = [] - if attrs.get('packages'): - for pkg in attrs['packages']: - pkg = string.replace(pkg, '/', '.') - prov.append('%s-%s'%(pkg, attrs['version'])) - elif attrs.get('modules'): - for mod in attrs['modules']: - prov.append('%s-%s'%(mod, attrs['version'])) - attrs['provides'] = prov - # Now work on the rest of the attributes. Any attribute that's # not already defined is invalid! for (key,val) in attrs.items(): @@ -275,7 +230,6 @@ setattr(self.metadata, key, val) elif hasattr(self, key): setattr(self, key, val) - else: msg = "Unknown distribution option: %s" % repr(key) if warnings is not None: warnings.warn(msg) @@ -1060,7 +1014,7 @@ "license", "description", "long_description", "keywords", "platforms", "fullname", "contact", "contact_email", "license", "classifiers", - "download_url", "provides", "requires",) + "download_url") def __init__ (self): self.name = None @@ -1077,8 +1031,6 @@ self.platforms = None self.classifiers = None self.download_url = None - self.requires = [] - self.provides = [] def write_pkg_info (self, base_dir): """Write the PKG-INFO file into the release tree. @@ -1094,10 +1046,6 @@ pkg_info.write('Author: %s\n' % self.get_contact() ) pkg_info.write('Author-email: %s\n' % self.get_contact_email() ) pkg_info.write('License: %s\n' % self.get_license() ) - for req in self.get_requires(): - pkg_info.write('Requires: %s\n' % req ) - for prov in self.get_provides(): - pkg_info.write('Provides: %s\n' % prov ) if self.download_url: pkg_info.write('Download-URL: %s\n' % self.download_url) @@ -1176,13 +1124,6 @@ def get_download_url(self): return self.download_url or "UNKNOWN" - def get_requires(self): - return [ '%s%s%s'%(x, (y and '-') or '', y or '') - for x,y in self.requires ] - - def get_provides(self): - return self.provides - # class DistributionMetadata From anthonybaxter at users.sourceforge.net Wed Oct 13 15:22:37 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 15:22:39 2004 Subject: [Python-checkins] python/dist/src/Lib/distutils dist.py,1.70,1.71 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/distutils In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7113 Modified Files: dist.py Log Message: oops. how did _that_ happen? Index: dist.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/dist.py,v retrieving revision 1.70 retrieving revision 1.71 diff -u -d -r1.70 -r1.71 --- dist.py 13 Oct 2004 12:35:27 -0000 1.70 +++ dist.py 13 Oct 2004 13:22:34 -0000 1.71 @@ -230,6 +230,7 @@ setattr(self.metadata, key, val) elif hasattr(self, key): setattr(self, key, val) + else: msg = "Unknown distribution option: %s" % repr(key) if warnings is not None: warnings.warn(msg) From fdrake at acm.org Wed Oct 13 15:26:18 2004 From: fdrake at acm.org (Fred L. Drake, Jr.) Date: Wed Oct 13 15:26:25 2004 Subject: [Python-checkins] python/dist/src/Lib/distutils/command __init__.py, 1.19, 1.20 install.py, 1.70, 1.71 checkdep.py, 1.1, NONE In-Reply-To: References: Message-ID: <200410130926.18709.fdrake@acm.org> On Wednesday 13 October 2004 08:35 am, Anthony Baxter wrote: > Backing out the basic dependency checking (from pycon sprint). > This support was only a first cut, and doesn't deserve to be in > a released version (where we have to support it in an ongoing > manner) Thanks, Anthony! -Fred -- Fred L. Drake, Jr. From dcjim at users.sourceforge.net Wed Oct 13 16:15:34 2004 From: dcjim at users.sourceforge.net (dcjim@users.sourceforge.net) Date: Wed Oct 13 16:15:38 2004 Subject: [Python-checkins] python/dist/src/Lib doctest.py,1.116,1.117 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19639/Lib Modified Files: doctest.py Log Message: Fixed a small bug. doctest didn't handle unicode docstrings containing non-ascii characters. Index: doctest.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/doctest.py,v retrieving revision 1.116 retrieving revision 1.117 diff -u -d -r1.116 -r1.117 --- doctest.py 28 Sep 2004 05:50:57 -0000 1.116 +++ doctest.py 13 Oct 2004 14:15:31 -0000 1.117 @@ -962,7 +962,9 @@ if obj.__doc__ is None: docstring = '' else: - docstring = str(obj.__doc__) + docstring = obj.__doc__ + if not isinstance(docstring, basestring): + docstring = str(docstring) except (TypeError, AttributeError): docstring = '' From dcjim at users.sourceforge.net Wed Oct 13 16:15:34 2004 From: dcjim at users.sourceforge.net (dcjim@users.sourceforge.net) Date: Wed Oct 13 16:15:39 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_doctest2.py, 1.5, 1.6 test_doctest2.txt, 1.2, 1.3 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19639/Lib/test Modified Files: test_doctest2.py test_doctest2.txt Log Message: Fixed a small bug. doctest didn't handle unicode docstrings containing non-ascii characters. Index: test_doctest2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_doctest2.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- test_doctest2.py 30 Jul 2002 23:27:11 -0000 1.5 +++ test_doctest2.py 13 Oct 2004 14:15:32 -0000 1.6 @@ -1,17 +1,31 @@ -"""A module to test whether doctest recognizes some 2.2 features, +# -*- coding: utf-8 -*- +u"""A module to test whether doctest recognizes some 2.2 features, like static and class methods. >>> print 'yup' # 1 yup + +We include some (random) encoded (utf-8) text in the text surrounding +the example. It should be ignored: + +ЉЊЈÐЂ + """ from test import test_support class C(object): - """Class C. + u"""Class C. >>> print C() # 2 42 + + + We include some (random) encoded (utf-8) text in the text surrounding + the example. It should be ignored: + + ЉЊЈÐЂ + """ def __init__(self): Index: test_doctest2.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_doctest2.txt,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- test_doctest2.txt 6 Aug 2004 22:02:59 -0000 1.2 +++ test_doctest2.txt 13 Oct 2004 14:15:32 -0000 1.3 @@ -5,3 +5,10 @@ >>> import test.test_doctest >>> test.test_doctest.sillySetup True + +This test also has some (random) encoded (utf-8) unicode text: + + ÉÊÈÃÂÂ + +This doesn't cause a problem in the tect surrounding the examples, but +we include it here (in this test text file) to make sure. :) From anthonybaxter at users.sourceforge.net Wed Oct 13 16:48:53 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 16:48:55 2004 Subject: [Python-checkins] python/dist/src/Modules posixmodule.c, 2.327, 2.328 signalmodule.c, 2.75, 2.76 socketmodule.c, 1.307, 1.308 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27121/Modules Modified Files: posixmodule.c signalmodule.c socketmodule.c Log Message: Patch #975056 - fixes for restartable signals on *BSD. In addition, a few remaining calls to signal() were converted to PyOS_setsig(). Index: posixmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/posixmodule.c,v retrieving revision 2.327 retrieving revision 2.328 diff -u -d -r2.327 -r2.328 --- posixmodule.c 27 Sep 2004 19:54:33 -0000 2.327 +++ posixmodule.c 13 Oct 2004 14:48:49 -0000 2.328 @@ -2903,18 +2903,18 @@ master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */ if (master_fd < 0) return posix_error(); - sig_saved = signal(SIGCHLD, SIG_DFL); + sig_saved = PyOS_setsig(SIGCHLD, SIG_DFL); /* change permission of slave */ if (grantpt(master_fd) < 0) { - signal(SIGCHLD, sig_saved); + PyOS_setsig(SIGCHLD, sig_saved); return posix_error(); } /* unlock slave */ if (unlockpt(master_fd) < 0) { - signal(SIGCHLD, sig_saved); + PyOS_setsig(SIGCHLD, sig_saved); return posix_error(); } - signal(SIGCHLD, sig_saved); + PyOS_setsig(SIGCHLD, sig_saved); slave_name = ptsname(master_fd); /* get name of slave */ if (slave_name == NULL) return posix_error(); Index: signalmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/signalmodule.c,v retrieving revision 2.75 retrieving revision 2.76 diff -u -d -r2.75 -r2.76 --- signalmodule.c 17 Jun 2004 15:55:53 -0000 2.75 +++ signalmodule.c 13 Oct 2004 14:48:50 -0000 2.76 @@ -137,9 +137,6 @@ return; } #endif -#ifdef HAVE_SIGINTERRUPT - siginterrupt(sig_num, 1); -#endif PyOS_setsig(sig_num, signal_handler); } @@ -217,9 +214,6 @@ } else func = signal_handler; -#ifdef HAVE_SIGINTERRUPT - siginterrupt(sig_num, 1); -#endif if (PyOS_setsig(sig_num, func) == SIG_ERR) { PyErr_SetFromErrno(PyExc_RuntimeError); return NULL; Index: socketmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/socketmodule.c,v retrieving revision 1.307 retrieving revision 1.308 diff -u -d -r1.307 -r1.308 --- socketmodule.c 28 Sep 2004 02:19:40 -0000 1.307 +++ socketmodule.c 13 Oct 2004 14:48:50 -0000 1.308 @@ -217,7 +217,7 @@ /* Generic includes */ #include -#include +//#include /* Generic socket object definitions and includes */ #define PySocket_BUILDING_SOCKET From anthonybaxter at users.sourceforge.net Wed Oct 13 16:48:53 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 16:48:56 2004 Subject: [Python-checkins] python/dist/src/Parser intrcheck.c,2.45,2.46 Message-ID: Update of /cvsroot/python/python/dist/src/Parser In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27121/Parser Modified Files: intrcheck.c Log Message: Patch #975056 - fixes for restartable signals on *BSD. In addition, a few remaining calls to signal() were converted to PyOS_setsig(). Index: intrcheck.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Parser/intrcheck.c,v retrieving revision 2.45 retrieving revision 2.46 diff -u -d -r2.45 -r2.46 --- intrcheck.c 20 Nov 2003 01:44:58 -0000 2.45 +++ intrcheck.c 13 Oct 2004 14:48:50 -0000 2.46 @@ -137,7 +137,7 @@ Py_Exit(1); break; } - signal(SIGINT, intcatcher); + PyOS_setsig(SIGINT, intcatcher); Py_AddPendingCall(checksignals_witharg, NULL); } @@ -146,23 +146,14 @@ void PyOS_InitInterrupts(void) { - if ((old_siginthandler = signal(SIGINT, SIG_IGN)) != SIG_IGN) - signal(SIGINT, intcatcher); -#ifdef HAVE_SIGINTERRUPT - /* This is for SunOS and other modern BSD derivatives. - It means that system calls (like read()) are not restarted - after an interrupt. This is necessary so interrupting a - read() or readline() call works as expected. - XXX On old BSD (pure 4.2 or older) you may have to do this - differently! */ - siginterrupt(SIGINT, 1); -#endif /* HAVE_SIGINTERRUPT */ + if ((old_siginthandler = PyOS_setsig(SIGINT, SIG_IGN)) != SIG_IGN) + PyOS_setsig(SIGINT, intcatcher); } void PyOS_FiniInterrupts(void) { - signal(SIGINT, old_siginthandler); + PyOS_setsig(SIGINT, old_siginthandler); } int From anthonybaxter at users.sourceforge.net Wed Oct 13 16:48:53 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 16:48:57 2004 Subject: [Python-checkins] python/dist/src/Python pythonrun.c,2.210,2.211 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27121/Python Modified Files: pythonrun.c Log Message: Patch #975056 - fixes for restartable signals on *BSD. In addition, a few remaining calls to signal() were converted to PyOS_setsig(). Index: pythonrun.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pythonrun.c,v retrieving revision 2.210 retrieving revision 2.211 diff -u -d -r2.210 -r2.211 --- pythonrun.c 11 Oct 2004 02:40:51 -0000 2.210 +++ pythonrun.c 13 Oct 2004 14:48:50 -0000 2.211 @@ -1576,13 +1576,13 @@ initsigs(void) { #ifdef SIGPIPE - signal(SIGPIPE, SIG_IGN); + PyOS_setsig(SIGPIPE, SIG_IGN); #endif #ifdef SIGXFZ - signal(SIGXFZ, SIG_IGN); + PyOS_setsig(SIGXFZ, SIG_IGN); #endif #ifdef SIGXFSZ - signal(SIGXFSZ, SIG_IGN); + PyOS_setsig(SIGXFSZ, SIG_IGN); #endif PyOS_InitInterrupts(); /* May imply initsignal() */ } @@ -1646,18 +1646,14 @@ { #ifdef HAVE_SIGACTION struct sigaction context; - /* Initialize context.sa_handler to SIG_ERR which makes about as - * much sense as anything else. It should get overwritten if - * sigaction actually succeeds and otherwise we avoid an - * uninitialized memory read. - */ - context.sa_handler = SIG_ERR; - sigaction(sig, NULL, &context); + if (sigaction(sig, NULL, &context) == -1) + return SIG_ERR; return context.sa_handler; #else PyOS_sighandler_t handler; handler = signal(sig, SIG_IGN); - signal(sig, handler); + if (handler != SIG_ERR) + signal(sig, handler); return handler; #endif } @@ -1666,20 +1662,19 @@ PyOS_setsig(int sig, PyOS_sighandler_t handler) { #ifdef HAVE_SIGACTION - struct sigaction context; - PyOS_sighandler_t oldhandler; - /* Initialize context.sa_handler to SIG_ERR which makes about as - * much sense as anything else. It should get overwritten if - * sigaction actually succeeds and otherwise we avoid an - * uninitialized memory read. - */ - context.sa_handler = SIG_ERR; - sigaction(sig, NULL, &context); - oldhandler = context.sa_handler; + struct sigaction context, ocontext; context.sa_handler = handler; - sigaction(sig, &context, NULL); - return oldhandler; + sigemptyset(&context.sa_mask); + context.sa_flags = 0; + if (sigaction(sig, &context, &ocontext) == -1) + return SIG_ERR; + return ocontext.sa_handler; #else - return signal(sig, handler); + PyOS_sighandler_t oldhandler; + oldhandler = signal(sig, handler); +#ifdef HAVE_SIGINTERRUPT + siginterrupt(sig, 1); +#endif + return oldhandler; #endif } From anthonybaxter at users.sourceforge.net Wed Oct 13 16:56:00 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 16:56:04 2004 Subject: [Python-checkins] python/dist/src/Misc ACKS, 1.283, 1.284 NEWS, 1.1160, 1.1161 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29208/Misc Modified Files: ACKS NEWS Log Message: 969574 Index: ACKS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/ACKS,v retrieving revision 1.283 retrieving revision 1.284 diff -u -d -r1.283 -r1.284 --- ACKS 18 Sep 2004 09:03:49 -0000 1.283 +++ ACKS 13 Oct 2004 14:55:56 -0000 1.284 @@ -391,6 +391,7 @@ Craig McPheeters Lambert Meertens Bill van Melle +Luke Mewburn Mike Meyer Steven Miale Trent Mick Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1160 retrieving revision 1.1161 diff -u -d -r1.1160 -r1.1161 --- NEWS 12 Oct 2004 15:32:10 -0000 1.1160 +++ NEWS 13 Oct 2004 14:55:56 -0000 1.1161 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #975056: Restartable signals were not correctly disabled on + BSD systems. Consistently use PyOS_setsig() instead of signal(). + - The internal portable implementation of thread-local storage (TLS), used by the ``PyGILState_Ensure()``/``PyGILState_Release()`` API, was not thread-correct. This could lead to a variety of problems, up to and From anthonybaxter at users.sourceforge.net Wed Oct 13 17:31:13 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 17:31:16 2004 Subject: [Python-checkins] python/dist/src/Modules posixmodule.c, 2.328, 2.329 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5027/Modules Modified Files: posixmodule.c Log Message: Patch 977343, Solaris likes sys/loadavg.h. Added support for sys/loadavg.h detection to configure &c. Index: posixmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/posixmodule.c,v retrieving revision 2.328 retrieving revision 2.329 diff -u -d -r2.328 -r2.329 --- posixmodule.c 13 Oct 2004 14:48:49 -0000 2.328 +++ posixmodule.c 13 Oct 2004 15:30:56 -0000 2.329 @@ -67,6 +67,10 @@ #include #endif /* HAVE_SYSEXITS_H */ +#ifdef HAVE_SYS_LOADAVG_H +#include +#endif + /* Various compilers have only certain posix functions */ /* XXX Gosh I wish these were all moved into pyconfig.h */ #if defined(PYCC_VACPP) && defined(PYOS_OS2) From anthonybaxter at users.sourceforge.net Wed Oct 13 17:31:29 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 17:31:33 2004 Subject: [Python-checkins] python/dist/src configure, 1.458, 1.459 configure.in, 1.471, 1.472 pyconfig.h.in, 1.104, 1.105 Message-ID: Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5027 Modified Files: configure configure.in pyconfig.h.in Log Message: Patch 977343, Solaris likes sys/loadavg.h. Added support for sys/loadavg.h detection to configure &c. Index: configure =================================================================== RCS file: /cvsroot/python/python/dist/src/configure,v retrieving revision 1.458 retrieving revision 1.459 diff -u -d -r1.458 -r1.459 --- configure 18 Sep 2004 10:07:02 -0000 1.458 +++ configure 13 Oct 2004 15:30:45 -0000 1.459 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 1.470 . +# From configure.in Revision: 1.471 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for python 2.4. # @@ -4532,11 +4532,13 @@ + for ac_header in curses.h dlfcn.h fcntl.h grp.h langinfo.h \ libintl.h ncurses.h poll.h pthread.h \ stropts.h termios.h thread.h \ unistd.h utime.h \ -sys/audioio.h sys/bsdtty.h sys/file.h sys/lock.h sys/mkdev.h sys/modem.h \ +sys/audioio.h sys/bsdtty.h sys/file.h sys/loadavg.h sys/lock.h sys/mkdev.h \ +sys/modem.h \ sys/param.h sys/poll.h sys/select.h sys/socket.h sys/time.h sys/times.h \ sys/un.h sys/utsname.h sys/wait.h pty.h libutil.h \ sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ Index: configure.in =================================================================== RCS file: /cvsroot/python/python/dist/src/configure.in,v retrieving revision 1.471 retrieving revision 1.472 diff -u -d -r1.471 -r1.472 --- configure.in 18 Sep 2004 10:07:03 -0000 1.471 +++ configure.in 13 Oct 2004 15:30:55 -0000 1.472 @@ -959,7 +959,8 @@ libintl.h ncurses.h poll.h pthread.h \ stropts.h termios.h thread.h \ unistd.h utime.h \ -sys/audioio.h sys/bsdtty.h sys/file.h sys/lock.h sys/mkdev.h sys/modem.h \ +sys/audioio.h sys/bsdtty.h sys/file.h sys/loadavg.h sys/lock.h sys/mkdev.h \ +sys/modem.h \ sys/param.h sys/poll.h sys/select.h sys/socket.h sys/time.h sys/times.h \ sys/un.h sys/utsname.h sys/wait.h pty.h libutil.h \ sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ Index: pyconfig.h.in =================================================================== RCS file: /cvsroot/python/python/dist/src/pyconfig.h.in,v retrieving revision 1.104 retrieving revision 1.105 diff -u -d -r1.104 -r1.105 --- pyconfig.h.in 18 Sep 2004 09:54:52 -0000 1.104 +++ pyconfig.h.in 13 Oct 2004 15:30:55 -0000 1.105 @@ -512,6 +512,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_LOADAVG_H + /* Define to 1 if you have the header file. */ #undef HAVE_SYS_LOCK_H From anthonybaxter at users.sourceforge.net Wed Oct 13 17:54:18 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 17:54:21 2004 Subject: [Python-checkins] python/dist/src setup.py,1.202,1.203 Message-ID: Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10291 Modified Files: setup.py Log Message: Patch 983206: distutils obeys LDSHARED env var. Removed the code in Python's own setup.py that did the same thing (and tested on Solaris, where LDSHARED is needed...) Index: setup.py =================================================================== RCS file: /cvsroot/python/python/dist/src/setup.py,v retrieving revision 1.202 retrieving revision 1.203 diff -u -d -r1.202 -r1.203 --- setup.py 28 Sep 2004 03:49:52 -0000 1.202 +++ setup.py 13 Oct 2004 15:54:16 -0000 1.203 @@ -167,15 +167,12 @@ # those environment variables passed into the setup.py phase. Here's # a small set of useful ones. compiler = os.environ.get('CC') - linker_so = os.environ.get('LDSHARED') args = {} # unfortunately, distutils doesn't let us provide separate C and C++ # compilers if compiler is not None: (ccshared,opt,base) = sysconfig.get_config_vars('CCSHARED','OPT','BASECFLAGS') args['compiler_so'] = compiler + ' ' + opt + ' ' + ccshared + ' ' + base - if linker_so is not None: - args['linker_so'] = linker_so self.compiler.set_executables(**args) build_ext.build_extensions(self) From anthonybaxter at users.sourceforge.net Wed Oct 13 17:54:19 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 17:54:22 2004 Subject: [Python-checkins] python/dist/src/Lib/distutils sysconfig.py, 1.60, 1.61 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/distutils In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10291/Lib/distutils Modified Files: sysconfig.py Log Message: Patch 983206: distutils obeys LDSHARED env var. Removed the code in Python's own setup.py that did the same thing (and tested on Solaris, where LDSHARED is needed...) Index: sysconfig.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/sysconfig.py,v retrieving revision 1.60 retrieving revision 1.61 diff -u -d -r1.60 -r1.61 --- sysconfig.py 18 Jul 2004 06:14:42 -0000 1.60 +++ sysconfig.py 13 Oct 2004 15:54:16 -0000 1.61 @@ -153,6 +153,8 @@ cc = os.environ['CC'] if os.environ.has_key('CXX'): cxx = os.environ['CXX'] + if os.environ.has_key('LDSHARED'): + ldshared = os.environ['LDSHARED'] if os.environ.has_key('CPP'): cpp = os.environ['CPP'] else: From anthonybaxter at users.sourceforge.net Wed Oct 13 17:54:19 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 13 17:54:23 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1161, 1.1162 ACKS, 1.284, 1.285 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10291/Misc Modified Files: NEWS ACKS Log Message: Patch 983206: distutils obeys LDSHARED env var. Removed the code in Python's own setup.py that did the same thing (and tested on Solaris, where LDSHARED is needed...) Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1161 retrieving revision 1.1162 diff -u -d -r1.1161 -r1.1162 --- NEWS 13 Oct 2004 14:55:56 -0000 1.1161 +++ NEWS 13 Oct 2004 15:54:17 -0000 1.1162 @@ -47,6 +47,9 @@ Library ------- +- Patch 983206: distutils now obeys environment variable LDSHARED, if + it is set. + - Added Peter Astrand's subprocess.py module. See PEP 324 for details. - time.strptime() now properly escapes timezones and all other locale-specific Index: ACKS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/ACKS,v retrieving revision 1.284 retrieving revision 1.285 diff -u -d -r1.284 -r1.285 --- ACKS 13 Oct 2004 14:55:56 -0000 1.284 +++ ACKS 13 Oct 2004 15:54:17 -0000 1.285 @@ -499,6 +499,7 @@ Hugo van Rossum Saskia van Rossum Donald Wallace Rouse II +Liam Routt Audun S. Runde Jeff Rush Sam Rushing From effbot at users.sourceforge.net Wed Oct 13 17:57:44 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Wed Oct 13 17:57:47 2004 Subject: [Python-checkins] python/nondist/peps pep-0291.txt,1.11,1.12 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11060 Modified Files: pep-0291.txt Log Message: added subprocess to the compatibility PEP Index: pep-0291.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0291.txt,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- pep-0291.txt 20 Aug 2004 07:32:06 -0000 1.11 +++ pep-0291.txt 13 Oct 2004 15:57:42 -0000 1.12 @@ -85,6 +85,7 @@ email Barry Warsaw 2.1 / 2.3 [1] logging Vinay Sajip 1.5.2 sre Fredrik Lundh 2.1 + subprocess Peter Astrand 2.2 xml (PyXML) Martin v. Loewis 2.0 xmlrpclib Fredrik Lundh 2.1 modulefinder Thomas Heller 2.2 From effbot at users.sourceforge.net Wed Oct 13 20:19:23 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Wed Oct 13 20:19:26 2004 Subject: [Python-checkins] python/dist/src/Lib subprocess.py,1.4,1.5 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14799/Lib Modified Files: subprocess.py Log Message: Replace dynamic try/except with "if 0", to keep py2exe happy. If you want to use pywin32 instead of _subprocess, you have to edit the file. Index: subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/subprocess.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- subprocess.py 13 Oct 2004 03:15:00 -0000 1.4 +++ subprocess.py 13 Oct 2004 18:19:18 -0000 1.5 @@ -367,16 +367,7 @@ if mswindows: import threading import msvcrt - try: - from _subprocess import * - class STARTUPINFO: - dwFlags = 0 - hStdInput = None - hStdOutput = None - hStdError = None - class pywintypes: - error = IOError - except ImportError: + if 0: # <-- change this to use pywin32 instead of the _subprocess driver import pywintypes from win32api import GetStdHandle, STD_INPUT_HANDLE, \ STD_OUTPUT_HANDLE, STD_ERROR_HANDLE @@ -388,6 +379,15 @@ GetExitCodeProcess, STARTF_USESTDHANDLES, \ CREATE_NEW_CONSOLE from win32event import WaitForSingleObject, INFINITE, WAIT_OBJECT_0 + else: + from _subprocess import * + class STARTUPINFO: + dwFlags = 0 + hStdInput = None + hStdOutput = None + hStdError = None + class pywintypes: + error = IOError else: import select import errno From loewis at users.sourceforge.net Wed Oct 13 21:50:13 2004 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed Oct 13 21:50:17 2004 Subject: [Python-checkins] python/dist/src/Modules pyexpat.c,2.88,2.89 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8030 Modified Files: pyexpat.c Log Message: Synchronize with PyXML 1.79: 73: Restore support for Python 2.1. 74: Factor the previous change differently 79: Conditionalize usage of PyTuple_Pack. Index: pyexpat.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/pyexpat.c,v retrieving revision 2.88 retrieving revision 2.89 diff -u -d -r2.88 -r2.89 --- pyexpat.c 26 Aug 2004 00:37:31 -0000 2.88 +++ pyexpat.c 13 Oct 2004 19:50:11 -0000 2.89 @@ -338,7 +338,11 @@ value = Py_None; Py_INCREF(value); } +#if PY_VERSION_HEX < 0x02040000 + arg = Py_BuildValue("(OOO)", type, value, traceback); +#else arg = PyTuple_Pack(3, type, value, traceback); +#endif if (arg == NULL) { PyErr_Restore(type, value, traceback); return 0; @@ -936,7 +940,12 @@ PyTuple_SET_ITEM(arg, 0, bytes); - if ((str = PyObject_Call(meth, arg, NULL)) == NULL) +#if PY_VERSION_HEX < 0x02020000 + str = PyObject_CallObject(meth, arg); +#else + str = PyObject_Call(meth, arg, NULL); +#endif + if (str == NULL) goto finally; /* XXX what to do if it returns a Unicode string? */ From loewis at users.sourceforge.net Wed Oct 13 21:57:17 2004 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed Oct 13 21:57:20 2004 Subject: [Python-checkins] python/dist/src/Lib/xml __init__.py,1.13,1.14 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/xml In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9930 Modified Files: __init__.py Log Message: Require minimally PyXML 0.8.4. Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/xml/__init__.py,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- __init__.py 26 Jan 2003 10:36:33 -0000 1.13 +++ __init__.py 13 Oct 2004 19:57:14 -0000 1.14 @@ -21,7 +21,7 @@ __version__ = "$Revision$".split()[-2:][0] -_MINIMUM_XMLPLUS_VERSION = (0, 8, 2) +_MINIMUM_XMLPLUS_VERSION = (0, 8, 4) try: From tim_one at users.sourceforge.net Thu Oct 14 05:09:50 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Thu Oct 14 05:09:54 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libdifflib.tex,1.20,1.21 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30325/Doc/lib Modified Files: libdifflib.tex Log Message: SF bug 1046690: difflib.HtmlDiff doc errors. Easy doc corrections from Dan Gass. Also repaired the LaTeX for optional keyword arguments throughout, which was (incorrectly) nested instead of flat. Index: libdifflib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libdifflib.tex,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- libdifflib.tex 12 Sep 2004 03:21:00 -0000 1.20 +++ libdifflib.tex 14 Oct 2004 03:09:48 -0000 1.21 @@ -61,11 +61,8 @@ The constructor for this class is: - \begin{funcdesc}{__init__}{ - \optional{, tabsize - \optional{, wrapcolumn - \optional{, linejunk - \optional{, charjunk}}}}} + \begin{funcdesc}{__init__}{\optional{tabsize}\optional{, + wrapcolumn}\optional{, linejunk}\optional{, charjunk}} Initializes instance of \class{HtmlDiff}. @@ -86,10 +83,8 @@ The following methods are public: \begin{funcdesc}{make_file}{fromlines, tolines - \optional{, fromdesc - \optional{, todesc - \optional{, context - \optional{, numlines}}}}} + \optional{, fromdesc}\optional{, todesc}\optional{, context}\optional{, + numlines}} Compares \var{fromlines} and \var{tolines} (lists of strings) and returns a string which is a complete HTML file containing a table showing line by line differences with inter-line and intra-line changes highlighted. @@ -110,16 +105,14 @@ \end{funcdesc} \begin{funcdesc}{make_table}{fromlines, tolines - \optional{, fromdesc - \optional{, todesc - \optional{, context}}}} + \optional{, fromdesc}\optional{, todesc}\optional{, context}\optional{, + numlines}} Compares \var{fromlines} and \var{tolines} (lists of strings) and returns a string which is a complete HTML table showing line by line differences with inter-line and intra-line changes highlighted. - The arguments of this method are a subset of those for the - \code{make_file} method. Refer to the \code{make_file} method - documentation. + The arguments for this method are the same as those for the + \method{make_file()} method. \end{funcdesc} \file{Tools/scripts/diff.py} is a command-line front-end to this class @@ -128,9 +121,9 @@ \versionadded{2.4} \end{classdesc*} -\begin{funcdesc}{context_diff}{a, b\optional{, fromfile\optional{, tofile - \optional{, fromfiledate\optional{, tofiledate\optional{, n - \optional{, lineterm}}}}}}} +\begin{funcdesc}{context_diff}{a, b\optional{, fromfile}\optional{, + tofile}\optional{, fromfiledate}\optional{, tofiledate}\optional{, + n}\optional{, lineterm}} Compare \var{a} and \var{b} (lists of strings); return a delta (a generator generating the delta lines) in context diff format. @@ -162,7 +155,7 @@ \end{funcdesc} \begin{funcdesc}{get_close_matches}{word, possibilities\optional{, - n\optional{, cutoff}}} + n}\optional{, cutoff}} Return a list of the best ``good enough'' matches. \var{word} is a sequence for which close matches are desired (typically a string), and \var{possibilities} is a list of sequences against which to @@ -191,8 +184,7 @@ \end{verbatim} \end{funcdesc} -\begin{funcdesc}{ndiff}{a, b\optional{, linejunk\optional{, - charjunk}}} +\begin{funcdesc}{ndiff}{a, b\optional{, linejunk}\optional{, charjunk}} Compare \var{a} and \var{b} (lists of strings); return a \class{Differ}-style delta (a generator generating the delta lines). @@ -260,9 +252,9 @@ \end{funcdesc} -\begin{funcdesc}{unified_diff}{a, b\optional{, fromfile\optional{, tofile - \optional{, fromfiledate\optional{, tofiledate\optional{, n - \optional{, lineterm}}}}}}} +\begin{funcdesc}{unified_diff}{a, b\optional{, fromfile}\optional{, + tofile}\optional{, fromfiledate}\optional{, tofiledate}\optional{, + n}\optional{, lineterm}} Compare \var{a} and \var{b} (lists of strings); return a delta (a generator generating the delta lines) in unified diff format. From nnorwitz at users.sourceforge.net Thu Oct 14 05:46:21 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Thu Oct 14 05:46:24 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_xrange.py,1.2,1.3 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4834/Lib/test Modified Files: test_xrange.py Log Message: Get test to pass on amd64 (opteron). This is pretty hacky, but rangeobject.c has an #ifdef that is reached only when LONG_MAX != INT_MAX Index: test_xrange.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_xrange.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- test_xrange.py 8 Aug 2004 07:17:39 -0000 1.2 +++ test_xrange.py 14 Oct 2004 03:46:18 -0000 1.3 @@ -53,8 +53,13 @@ self.assertRaises(OverflowError, xrange, -sys.maxint, sys.maxint) self.assertRaises(OverflowError, xrange, 0, 2*sys.maxint) - self.assertEqual(len(xrange(-sys.maxint, sys.maxint, 2)), - sys.maxint) + r = xrange(-sys.maxint, sys.maxint, 2) + if sys.maxint > 0x7fffffff: + # XXX raising ValueError is less than ideal, but this can't + # be fixed until range_length() returns a long in rangeobject.c + self.assertRaises(ValueError, len, r) + else: + self.assertEqual(len(r), sys.maxint) self.assertRaises(OverflowError, xrange, -sys.maxint-1, sys.maxint, 2) def test_main(): From nnorwitz at users.sourceforge.net Thu Oct 14 05:48:33 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Thu Oct 14 05:48:35 2004 Subject: [Python-checkins] python/dist/src/Modules socketmodule.c, 1.308, 1.309 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5734/Modules Modified Files: socketmodule.c Log Message: Use C89 style comment for old compilers Index: socketmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/socketmodule.c,v retrieving revision 1.308 retrieving revision 1.309 diff -u -d -r1.308 -r1.309 --- socketmodule.c 13 Oct 2004 14:48:50 -0000 1.308 +++ socketmodule.c 14 Oct 2004 03:48:30 -0000 1.309 @@ -217,7 +217,7 @@ /* Generic includes */ #include -//#include +/*#include */ /* Generic socket object definitions and includes */ #define PySocket_BUILDING_SOCKET From tim_one at users.sourceforge.net Thu Oct 14 06:16:56 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Thu Oct 14 06:16:59 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.11, 1.12 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10138/Lib/test Modified Files: test_subprocess.py Log Message: remove_stderr_debug_decorations(): Always try the substitution. Else this test failed under the combination of passing -O to a debug-build Python. Now all 4 of those pass ({debug, release} x {-O, no -O}). Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- test_subprocess.py 13 Oct 2004 07:54:54 -0000 1.11 +++ test_subprocess.py 14 Oct 2004 04:16:54 -0000 1.12 @@ -24,9 +24,7 @@ # shutdown time. That frustrates tests trying to check stderr produced # from a spawned Python process. def remove_stderr_debug_decorations(stderr): - if __debug__: - stderr = re.sub(r"\[\d+ refs\]\r?\n?$", "", stderr) - return stderr + return re.sub(r"\[\d+ refs\]\r?\n?$", "", stderr) class ProcessTestCase(unittest.TestCase): def mkstemp(self): From fdrake at users.sourceforge.net Thu Oct 14 07:07:32 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Thu Oct 14 07:07:35 2004 Subject: [Python-checkins] python/dist/src/Include patchlevel.h,2.79,2.80 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18884 Modified Files: patchlevel.h Log Message: bump the version number prior to release Index: patchlevel.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/patchlevel.h,v retrieving revision 2.79 retrieving revision 2.80 diff -u -d -r2.79 -r2.80 --- patchlevel.h 31 Aug 2004 09:53:05 -0000 2.79 +++ patchlevel.h 14 Oct 2004 05:07:17 -0000 2.80 @@ -22,11 +22,11 @@ #define PY_MAJOR_VERSION 2 #define PY_MINOR_VERSION 4 #define PY_MICRO_VERSION 0 -#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_ALPHA -#define PY_RELEASE_SERIAL 3 +#define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_BETA +#define PY_RELEASE_SERIAL 1 /* Version as a string */ -#define PY_VERSION "2.4a3" +#define PY_VERSION "2.4b1" /* Version as a single 4-byte hex number, e.g. 0x010502B2 == 1.5.2b2. Use this for numeric comparisons, e.g. #if PY_VERSION_HEX >= ... */ From anthonybaxter at users.sourceforge.net Thu Oct 14 12:02:10 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Thu Oct 14 12:02:13 2004 Subject: [Python-checkins] python/dist/src/Misc ACKS, 1.285, 1.286 NEWS, 1.1162, 1.1163 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4862/Misc Modified Files: ACKS NEWS Log Message: Patch 1046644 - improved distutils support for SWIG. Index: ACKS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/ACKS,v retrieving revision 1.285 retrieving revision 1.286 diff -u -d -r1.285 -r1.286 --- ACKS 13 Oct 2004 15:54:17 -0000 1.285 +++ ACKS 14 Oct 2004 10:02:04 -0000 1.286 @@ -284,6 +284,7 @@ Jeremy Hylton Mihai Ibanescu Juan David Ibáñez Palomar +Lars Immisch Tony Ingraldi John Interrante Bob Ippolito Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1162 retrieving revision 1.1163 diff -u -d -r1.1162 -r1.1163 --- NEWS 13 Oct 2004 15:54:17 -0000 1.1162 +++ NEWS 14 Oct 2004 10:02:05 -0000 1.1163 @@ -47,6 +47,11 @@ Library ------- +- Patch 1046644: distutils build_ext grew two new options - --swig for + specifying the swig executable to use, and --swig-opts to specify + options to pass to swig. --swig-opts="-c++" is the new way to spell + --swig-cpp. + - Patch 983206: distutils now obeys environment variable LDSHARED, if it is set. From anthonybaxter at users.sourceforge.net Thu Oct 14 12:02:11 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Thu Oct 14 12:02:15 2004 Subject: [Python-checkins] python/dist/src/Lib/distutils core.py, 1.62, 1.63 extension.py, 1.18, 1.19 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/distutils In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4862/Lib/distutils Modified Files: core.py extension.py Log Message: Patch 1046644 - improved distutils support for SWIG. Index: core.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/core.py,v retrieving revision 1.62 retrieving revision 1.63 diff -u -d -r1.62 -r1.63 --- core.py 13 Oct 2004 12:35:27 -0000 1.62 +++ core.py 14 Oct 2004 10:02:07 -0000 1.63 @@ -54,7 +54,7 @@ 'define_macros', 'undef_macros', 'library_dirs', 'libraries', 'runtime_library_dirs', 'extra_objects', 'extra_compile_args', 'extra_link_args', - 'export_symbols', 'depends', 'language') + 'swig_opts', 'export_symbols', 'depends', 'language') def setup (**attrs): """The gateway to the Distutils: do everything your setup script needs Index: extension.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/extension.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- extension.py 27 Jan 2003 16:30:36 -0000 1.18 +++ extension.py 14 Oct 2004 10:02:08 -0000 1.19 @@ -75,6 +75,9 @@ used on all platforms, and not generally necessary for Python extensions, which typically export exactly one symbol: "init" + extension_name. + swig_opts : [string] + any extra options to pass to SWIG if a source file has the .i + extension. depends : [string] list of files that the extension depends on language : string @@ -95,6 +98,7 @@ extra_compile_args=None, extra_link_args=None, export_symbols=None, + swig_opts = None, depends=None, language=None, **kw # To catch unknown keywords @@ -116,6 +120,7 @@ self.extra_compile_args = extra_compile_args or [] self.extra_link_args = extra_link_args or [] self.export_symbols = export_symbols or [] + self.swig_opts = swig_opts or [] self.depends = depends or [] self.language = language From anthonybaxter at users.sourceforge.net Thu Oct 14 12:02:11 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Thu Oct 14 12:02:16 2004 Subject: [Python-checkins] python/dist/src/Lib/distutils/command build_ext.py, 1.96, 1.97 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/distutils/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4862/Lib/distutils/command Modified Files: build_ext.py Log Message: Patch 1046644 - improved distutils support for SWIG. Index: build_ext.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/command/build_ext.py,v retrieving revision 1.96 retrieving revision 1.97 diff -u -d -r1.96 -r1.97 --- build_ext.py 18 Jul 2004 06:14:43 -0000 1.96 +++ build_ext.py 14 Oct 2004 10:02:08 -0000 1.97 @@ -81,6 +81,10 @@ "specify the compiler type"), ('swig-cpp', None, "make SWIG create C++ files (default is C)"), + ('swig-opts=', None, + "list of SWIG command line options"), + ('swig=', None, + "path to the SWIG executable"), ] boolean_options = ['inplace', 'debug', 'force', 'swig-cpp'] @@ -107,8 +111,9 @@ self.debug = None self.force = None self.compiler = None + self.swig = None self.swig_cpp = None - + self.swig_opts = None def finalize_options (self): from distutils import sysconfig @@ -205,6 +210,11 @@ if self.undef: self.undef = string.split(self.undef, ',') + if self.swig_opts is None: + self.swig_opts = [] + else: + self.swig_opts = self.swig_opts.split(' ') + # finalize_options () @@ -429,7 +439,7 @@ # First, scan the sources for SWIG definition files (.i), run # SWIG on 'em to create .c files, and modify the sources list # accordingly. - sources = self.swig_sources(sources) + sources = self.swig_sources(sources, ext) # Next, compile the source code to object files. @@ -492,7 +502,7 @@ target_lang=language) - def swig_sources (self, sources): + def swig_sources (self, sources, extension): """Walk the list of source files in 'sources', looking for SWIG interface (.i) files. Run SWIG on all that are found, and @@ -510,6 +520,9 @@ # the temp dir. if self.swig_cpp: + log.warn("--swig-cpp is deprecated - use --swig-opts=-c++") + + if self.swig_cpp or ('-c++' in self.swig_opts): target_ext = '.cpp' else: target_ext = '.c' @@ -526,11 +539,17 @@ if not swig_sources: return new_sources - swig = self.find_swig() + swig = self.swig or self.find_swig() swig_cmd = [swig, "-python"] + swig_cmd.extend(self.swig_opts) if self.swig_cpp: swig_cmd.append("-c++") + # Do not override commandline arguments + if not self.swig_opts: + for o in extension.swig_opts: + swig_cmd.append(o) + for source in swig_sources: target = swig_targets[source] log.info("swigging %s to %s", source, target) From mwh at users.sourceforge.net Thu Oct 14 15:27:17 2004 From: mwh at users.sourceforge.net (mwh@users.sourceforge.net) Date: Thu Oct 14 15:27:20 2004 Subject: [Python-checkins] python/dist/src/Modules socketmodule.c, 1.309, 1.310 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17531 Modified Files: socketmodule.c Log Message: Just remove the #include of signal.h. That it was C++-commented out was a mistake of mine in updating patch #975056 (I think). Index: socketmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/socketmodule.c,v retrieving revision 1.309 retrieving revision 1.310 diff -u -d -r1.309 -r1.310 --- socketmodule.c 14 Oct 2004 03:48:30 -0000 1.309 +++ socketmodule.c 14 Oct 2004 13:27:14 -0000 1.310 @@ -217,7 +217,6 @@ /* Generic includes */ #include -/*#include */ /* Generic socket object definitions and includes */ #define PySocket_BUILDING_SOCKET From rhettinger at users.sourceforge.net Thu Oct 14 17:23:48 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu Oct 14 17:23:52 2004 Subject: [Python-checkins] python/dist/src/Lib httplib.py,1.92,1.93 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14843 Modified Files: httplib.py Log Message: SF bug #1046855: httplib index out of range Index: httplib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/httplib.py,v retrieving revision 1.92 retrieving revision 1.93 diff -u -d -r1.92 -r1.93 --- httplib.py 18 Sep 2004 09:03:49 -0000 1.92 +++ httplib.py 14 Oct 2004 15:23:38 -0000 1.93 @@ -593,7 +593,7 @@ host = host[:i] else: port = self.default_port - if host[0] == '[' and host[-1] == ']': + if host and host[0] == '[' and host[-1] == ']': host = host[1:-1] self.host = host self.port = port From loewis at users.sourceforge.net Fri Oct 15 06:26:32 2004 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Fri Oct 15 06:26:35 2004 Subject: [Python-checkins] python/dist/src/PC pyconfig.h,1.30,1.31 Message-ID: Update of /cvsroot/python/python/dist/src/PC In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4872 Modified Files: pyconfig.h Log Message: Patch #1020042: Only define HAVE_UINTPTR_T for VC 7.x. Index: pyconfig.h =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/pyconfig.h,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- pyconfig.h 23 Sep 2004 19:11:32 -0000 1.30 +++ pyconfig.h 15 Oct 2004 04:26:18 -0000 1.31 @@ -273,10 +273,12 @@ /* VC 7.1 has them and VC 6.0 does not. VC 6.0 has a version number of 1200. If some compiler does not provide them, modify the #if appropriately. */ -#if _MSC_VER != 1200 +#if defined(_MSC_VER) +#if _MSC_VER > 1200 #define HAVE_UINTPTR_T 1 #define HAVE_INTPTR_T 1 -#endif +#endif /* _MSC_VER > 1200 */ +#endif /* _MSC_VER */ #endif From loewis at users.sourceforge.net Fri Oct 15 06:27:53 2004 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Fri Oct 15 06:27:56 2004 Subject: [Python-checkins] python/dist/src/PC/VC6 pythoncore.dsp,1.14,1.15 Message-ID: Update of /cvsroot/python/python/dist/src/PC/VC6 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5171 Modified Files: pythoncore.dsp Log Message: Add _subprocess.c Index: pythoncore.dsp =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/VC6/pythoncore.dsp,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- pythoncore.dsp 31 Aug 2004 18:54:35 -0000 1.14 +++ pythoncore.dsp 15 Oct 2004 04:27:51 -0000 1.15 @@ -149,6 +149,10 @@ # End Source File # Begin Source File +SOURCE=..\..\PC\_subprocess.c +# End Source File +# Begin Source File + SOURCE=..\..\Modules\_weakref.c # End Source File # Begin Source File From loewis at users.sourceforge.net Fri Oct 15 07:44:43 2004 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Fri Oct 15 07:44:46 2004 Subject: [Python-checkins] python/dist/src/PCbuild BUILDno.txt, 1.61, 1.62 pythoncore.vcproj, 1.21, 1.22 Message-ID: Update of /cvsroot/python/python/dist/src/PCbuild In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17456 Modified Files: BUILDno.txt pythoncore.vcproj Log Message: Bump buildno for 2.4b1 Index: BUILDno.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/BUILDno.txt,v retrieving revision 1.61 retrieving revision 1.62 diff -u -d -r1.61 -r1.62 --- BUILDno.txt 1 Sep 2004 18:29:25 -0000 1.61 +++ BUILDno.txt 15 Oct 2004 05:44:39 -0000 1.62 @@ -33,6 +33,8 @@ Windows Python BUILD numbers ---------------------------- + 57 2.4.0b1 + 15-Oct-2004 56 2.4.0a3 2-Sep-2004 55 2.4.0a2 Index: pythoncore.vcproj =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/pythoncore.vcproj,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- pythoncore.vcproj 12 Oct 2004 21:48:57 -0000 1.21 +++ pythoncore.vcproj 15 Oct 2004 05:44:39 -0000 1.22 @@ -1385,7 +1385,7 @@ Name="VCCLCompilerTool" Optimization="2" AdditionalIncludeDirectories="" - PreprocessorDefinitions="BUILD=56"/> + PreprocessorDefinitions="BUILD=57"/> @@ -1393,7 +1393,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="" - PreprocessorDefinitions="BUILD=56"/> + PreprocessorDefinitions="BUILD=57"/> @@ -1401,7 +1401,7 @@ Name="VCCLCompilerTool" Optimization="2" AdditionalIncludeDirectories="" - PreprocessorDefinitions="BUILD=56"/> + PreprocessorDefinitions="BUILD=57"/> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22522/Lib Modified Files: sre_compile.py Log Message: make sure to check for this limit even if we're running with -O Index: sre_compile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/sre_compile.py,v retrieving revision 1.55 retrieving revision 1.56 diff -u -d -r1.55 -r1.56 --- sre_compile.py 7 May 2004 07:18:12 -0000 1.55 +++ sre_compile.py 15 Oct 2004 06:15:08 -0000 1.56 @@ -502,8 +502,10 @@ # print code # XXX: get rid of this limitation! - assert p.pattern.groups <= 100,\ - "sorry, but this version only supports 100 named groups" + if p.pattern.groups > 100: + raise AssertionError( + "sorry, but this version only supports 100 named groups" + ) # map in either direction groupindex = p.pattern.groupdict From lemburg at users.sourceforge.net Fri Oct 15 09:45:08 2004 From: lemburg at users.sourceforge.net (lemburg@users.sourceforge.net) Date: Fri Oct 15 09:45:12 2004 Subject: [Python-checkins] python/dist/src/Objects unicodeobject.c, 2.228, 2.229 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8568 Modified Files: unicodeobject.c Log Message: Applied patch for [ 1047269 ] Buffer overwrite in PyUnicode_AsWideChar. Python 2.3.x candidate. Index: unicodeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/unicodeobject.c,v retrieving revision 2.228 retrieving revision 2.229 diff -u -d -r2.228 -r2.229 --- unicodeobject.c 16 Sep 2004 03:28:13 -0000 2.228 +++ unicodeobject.c 15 Oct 2004 07:45:05 -0000 2.229 @@ -368,7 +368,7 @@ register Py_UNICODE *u; register int i; u = PyUnicode_AS_UNICODE(unicode); - for (i = size; i >= 0; i--) + for (i = size; i > 0; i--) *u++ = *w++; } #endif @@ -393,7 +393,7 @@ register Py_UNICODE *u; register int i; u = PyUnicode_AS_UNICODE(unicode); - for (i = size; i >= 0; i--) + for (i = size; i > 0; i--) *w++ = *u++; } #endif From anthonybaxter at users.sourceforge.net Fri Oct 15 10:07:24 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Fri Oct 15 10:07:27 2004 Subject: [Python-checkins] python/dist/src/Lib/idlelib NEWS.txt,1.40,1.41 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/idlelib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13309/Lib/idlelib Modified Files: NEWS.txt Log Message: release shenanigans Index: NEWS.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/NEWS.txt,v retrieving revision 1.40 retrieving revision 1.41 diff -u -d -r1.40 -r1.41 --- NEWS.txt 22 Aug 2004 05:14:32 -0000 1.40 +++ NEWS.txt 15 Oct 2004 08:07:21 -0000 1.41 @@ -1,3 +1,9 @@ +What's New in IDLE 1.1b1? +========================= + +*Release date: 15-OCT-2004* + + What's New in IDLE 1.1a3? ========================= From anthonybaxter at users.sourceforge.net Fri Oct 15 10:07:24 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Fri Oct 15 10:07:30 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1163,1.1164 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13309/Misc Modified Files: NEWS Log Message: release shenanigans Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1163 retrieving revision 1.1164 diff -u -d -r1.1163 -r1.1164 --- NEWS 14 Oct 2004 10:02:05 -0000 1.1163 +++ NEWS 15 Oct 2004 08:07:12 -0000 1.1164 @@ -7,7 +7,7 @@ What's New in Python 2.4 beta 1? ================================ -*Release date: XXXX-XX-XX* +*Release date: 15-OCT-2004* Core and builtins ----------------- From anthonybaxter at users.sourceforge.net Fri Oct 15 10:07:44 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Fri Oct 15 10:07:47 2004 Subject: [Python-checkins] python/dist/src/Misc/RPM python-2.4.spec,1.3,1.4 Message-ID: Update of /cvsroot/python/python/dist/src/Misc/RPM In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13309/Misc/RPM Modified Files: python-2.4.spec Log Message: release shenanigans Index: python-2.4.spec =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/RPM/python-2.4.spec,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- python-2.4.spec 2 Sep 2004 16:38:20 -0000 1.3 +++ python-2.4.spec 15 Oct 2004 08:07:11 -0000 1.4 @@ -30,7 +30,7 @@ ################################# %define name python -%define version 2.4a3 +%define version 2.4b1 %define libvers 2.4 %define release 1pydotorg %define __prefix /usr From facundobatista at users.sourceforge.net Sat Oct 16 23:40:38 2004 From: facundobatista at users.sourceforge.net (facundobatista@users.sourceforge.net) Date: Sat Oct 16 23:40:41 2004 Subject: [Python-checkins] python/dist/src/Doc/lib tkinter.tex,1.25,1.26 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9414 Modified Files: tkinter.tex Log Message: SF Bug #1046800: Importing Tkinter correctly (thanks Vishnu). Index: tkinter.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/tkinter.tex,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- tkinter.tex 11 Sep 2004 16:50:05 -0000 1.25 +++ tkinter.tex 16 Oct 2004 21:40:35 -0000 1.26 @@ -664,7 +664,7 @@ Here are some examples of typical usage: \begin{verbatim} -import Tkinter +from Tkinter import * class App(Frame): def __init__(self, master=None): Frame.__init__(self, master) From pje at users.sourceforge.net Sun Oct 17 15:34:34 2004 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun Oct 17 15:34:37 2004 Subject: [Python-checkins] python/nondist/peps pep-0333.txt,1.21,1.22 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21685 Modified Files: pep-0333.txt Log Message: Add SERVER_PROTOCOL as a required variable, since it's needed in order to obey the RFC's. Note that 'wsgi.errors' should be a "text mode" file. Fix a problem with the "URL reconstruction" algorithm: HTTP_HOST can contain a port number, so don't try to add SERVER_PORT if you use HTTP_HOST. Index: pep-0333.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0333.txt,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- pep-0333.txt 6 Oct 2004 06:23:54 -0000 1.21 +++ pep-0333.txt 17 Oct 2004 13:34:31 -0000 1.22 @@ -531,6 +531,16 @@ section below for more detail. ``SERVER_NAME`` and ``SERVER_PORT`` can never be empty strings, and so are always required. +``SERVER_PROTOCOL`` + The version of the protocol the client used to send the request. + Typically this will be something like ``"HTTP/1.0"`` or ``"HTTP/1.1"`` + and may be used by the application to determine how to treat any + HTTP request headers. (This variable should probably be called + ``REQUEST_PROTOCOL``, since it denotes the protocol used in the + request, and is not necessarily the protocol that will be used in the + server's response. However, for compatibility with CGI we have to + keep the existing name.) + ``HTTP_`` Variables Variables corresponding to the client-supplied HTTP request headers (i.e., variables whose names begin with ``"HTTP_"``). The presence or @@ -541,7 +551,7 @@ variables as are applicable. In addition, if SSL is in use, the server or gateway **should** also provide as many of the Apache SSL environment variables [5]_ as are applicable, such as ``HTTPS=on`` and -``SSL_PROTOCOL``. Note, however, an application that uses any CGI +``SSL_PROTOCOL``. Note, however, that an application that uses any CGI variables other than the ones listed above are necessarily non-portable to web servers that do not support the relevant extensions. (For example, web servers that do not publish files will not be able to @@ -586,16 +596,19 @@ error output can be written, for the purpose of recording program or other errors in a standardized and possibly centralized location. - For many servers, this will be the server's - main error log. + This should be a "text mode" stream; i.e., + applications should use ``"\n"`` as a line + ending, and assume that it will be converted to + the correct line ending by the server/gateway. - Alternatively, this may be ``sys.stderr``, or - a log file of some sort. The server's - documentation should include an explanation of - how to configure this or where to find the - recorded output. A server or gateway may - supply different error streams to different - applications, if this is desired. + For many servers, ``wsgi.errors`` will be the + server's main error log. Alternatively, this + may be ``sys.stderr``, or a log file of some + sort. The server's documentation should + include an explanation of how to configure this + or where to find the recorded output. A server + or gateway may supply different error streams + to different applications, if this is desired. ``wsgi.multithread`` This value should evaluate true if the application object may be simultaneously @@ -938,7 +951,7 @@ words, before ``write()`` returns, it must guarantee that the passed-in string was either completely sent to the client, or that it is buffered for transmission while the application -proceeds forward. +proceeds onward. An application **must** return an iterable object, even if it uses ``write()`` to produce all or part of its response body. @@ -1247,12 +1260,12 @@ else: url += environ['SERVER_NAME'] - if environ['wsgi.url_scheme'] == 'https': - if environ['SERVER_PORT'] != '443': - url += ':' + environ['SERVER_PORT'] - else: - if environ['SERVER_PORT'] != '80': - url += ':' + environ['SERVER_PORT'] + if environ['wsgi.url_scheme'] == 'https': + if environ['SERVER_PORT'] != '443': + url += ':' + environ['SERVER_PORT'] + else: + if environ['SERVER_PORT'] != '80': + url += ':' + environ['SERVER_PORT'] url += quote(environ.get('SCRIPT_NAME','')) url += quote(environ.get('PATH_INFO','')) From effbot at users.sourceforge.net Sun Oct 17 16:47:07 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Sun Oct 17 16:47:12 2004 Subject: [Python-checkins] python/dist/src/Lib subprocess.py,1.5,1.6 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8196/Lib Modified Files: subprocess.py Log Message: return codes are available on all platforms, not just on Unix Index: subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/subprocess.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- subprocess.py 13 Oct 2004 18:19:18 -0000 1.5 +++ subprocess.py 17 Oct 2004 14:47:05 -0000 1.6 @@ -27,10 +27,9 @@ """subprocess - Subprocesses with accessible I/O streams -This module allows you to spawn processes and connect to their -input/output/error pipes and obtain their return codes under Unix. -This module intends to replace several other, older modules and -functions, like: +This module allows you to spawn processes, connect to their +input/output/error pipes, and obtain their return codes. This module +intends to replace several other, older modules and functions, like: os.system os.spawn* From nnorwitz at users.sourceforge.net Sun Oct 17 18:23:55 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Sun Oct 17 18:23:58 2004 Subject: [Python-checkins] python/dist/src/Lib cookielib.py,1.3,1.4 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32171/Lib Modified Files: cookielib.py Log Message: Remove unnecessary imports Index: cookielib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/cookielib.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- cookielib.py 10 Jul 2004 18:32:12 -0000 1.3 +++ cookielib.py 17 Oct 2004 16:23:52 -0000 1.4 @@ -25,7 +25,7 @@ """ -import sys, re, urlparse, copy, time, struct, urllib, types, logging +import sys, re, urlparse, copy, time, urllib, logging from types import StringTypes try: import threading as _threading @@ -643,7 +643,7 @@ # And here, kind of: draft-fielding-uri-rfc2396bis-03 # (And in draft IRI specification: draft-duerst-iri-05) # (And here, for new URI schemes: RFC 2718) - if isinstance(path, types.UnicodeType): + if isinstance(path, unicode): path = path.encode("utf-8") path = urllib.quote(path, HTTP_PATH_SAFE) path = ESCAPED_CHAR_RE.sub(uppercase_escaped_char, path) From nnorwitz at users.sourceforge.net Sun Oct 17 18:24:40 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Sun Oct 17 18:24:43 2004 Subject: [Python-checkins] python/dist/src/Lib optparse.py,1.9,1.10 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32375/Lib Modified Files: optparse.py Log Message: Use proper value for False Index: optparse.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/optparse.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- optparse.py 31 Jul 2004 16:15:44 -0000 1.9 +++ optparse.py 17 Oct 2004 16:24:25 -0000 1.10 @@ -767,7 +767,7 @@ elif isinstance(other, dict): return self.__dict__ == other else: - return false + return False def __ne__(self, other): return not (self == other) From nnorwitz at users.sourceforge.net Sun Oct 17 18:27:20 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Sun Oct 17 18:27:23 2004 Subject: [Python-checkins] python/dist/src/Lib string.py,1.85,1.86 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv439/Lib Modified Files: string.py Log Message: Invalid patterns to substitute and safe_substitute would crash since pattern is not a local variable. Add a test case. Index: string.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/string.py,v retrieving revision 1.85 retrieving revision 1.86 diff -u -d -r1.85 -r1.86 --- string.py 26 Sep 2004 18:56:44 -0000 1.85 +++ string.py 17 Oct 2004 16:27:17 -0000 1.86 @@ -167,7 +167,8 @@ return self.delimiter if mo.group('invalid') is not None: self._invalid(mo) - raise ValueError('Unrecognized named group in pattern', pattern) + raise ValueError('Unrecognized named group in pattern', + self.pattern) return self.pattern.sub(convert, self.template) def safe_substitute(self, *args, **kws): @@ -199,7 +200,8 @@ return self.delimiter if mo.group('invalid') is not None: self._invalid(mo) - raise ValueError('Unrecognized named group in pattern', pattern) + raise ValueError('Unrecognized named group in pattern', + self.pattern) return self.pattern.sub(convert, self.template) From nnorwitz at users.sourceforge.net Sun Oct 17 18:27:20 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Sun Oct 17 18:27:24 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_pep292.py,1.6,1.7 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv439/Lib/test Modified Files: test_pep292.py Log Message: Invalid patterns to substitute and safe_substitute would crash since pattern is not a local variable. Add a test case. Index: test_pep292.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_pep292.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- test_pep292.py 14 Sep 2004 02:34:08 -0000 1.6 +++ test_pep292.py 17 Oct 2004 16:27:18 -0000 1.7 @@ -113,6 +113,18 @@ s = MyPattern('@bag.foo.who likes to eat a bag of @bag.what') self.assertEqual(s.substitute(m), 'tim likes to eat a bag of ham') + class BadPattern(Template): + pattern = r""" + (?P.*) | + (?P@{2}) | + @(?P[_a-z][._a-z0-9]*) | + @{(?P[_a-z][._a-z0-9]*)} | + (?P@) | + """ + s = BadPattern('@bag.foo.who likes to eat a bag of @bag.what') + self.assertRaises(ValueError, s.substitute, {}) + self.assertRaises(ValueError, s.safe_substitute, {}) + def test_unicode_values(self): s = Template('$who likes $what') d = dict(who=u't\xffm', what=u'f\xfe\fed') From effbot at users.sourceforge.net Sun Oct 17 18:29:50 2004 From: effbot at users.sourceforge.net (effbot@users.sourceforge.net) Date: Sun Oct 17 18:29:54 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libsubprocess.tex, NONE, 1.1 lib.tex, 1.230, 1.231 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1126/lib Modified Files: lib.tex Added Files: libsubprocess.tex Log Message: SF Patch #1048341: subprocess documentation, based on PEP/docstring by Peter Astrand, with markup by Fredrik Lundh and Raymond Hettinger. --- NEW FILE: libsubprocess.tex --- \section{\module{subprocess} --- Subprocess management} \declaremodule{standard}{subprocess} \modulesynopsis{Subprocess management.} \moduleauthor{Peter \AA strand}{astrand@lysator.liu.se} \sectionauthor{Peter \AA strand}{astrand@lysator.liu.se} \versionadded{2.4} The \module{subprocess} module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several other, older modules and functions, such as: % XXX Should add pointers to this module to at least the popen2 % and commands sections. \begin{verbatim} os.system os.spawn* os.popen* popen2.* commands.* \end{verbatim} Information about how the \module{subprocess} module can be used to replace these modules and functions can be found in the following sections. \subsection{Using the subprocess Module} This module defines one class called \class{Popen}: \begin{classdesc}{Popen}{args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0} Arguments are: \var{args} should be a string, or a sequence of program arguments. The program to execute is normally the first item in the args sequence or string, but can be explicitly set by using the executable argument. On \UNIX{}, with \var{shell=False} (default): In this case, the Popen class uses \method{os.execvp()} to execute the child program. \var{args} should normally be a sequence. A string will be treated as a sequence with the string as the only item (the program to execute). On \UNIX{}, with \var{shell=True}: If args is a string, it specifies the command string to execute through the shell. If \var{args} is a sequence, the first item specifies the command string, and any additional items will be treated as additional shell arguments. On Windows: the \class{Popen} class uses CreateProcess() to execute the child program, which operates on strings. If \var{args} is a sequence, it will be converted to a string using the \method{list2cmdline} method. Please note that not all MS Windows applications interpret the command line the same way: \method{list2cmdline} is designed for applications using the same rules as the MS C runtime. \var{bufsize}, if given, has the same meaning as the corresponding argument to the built-in open() function: \constant{0} means unbuffered, \constant{1} means line buffered, any other positive value means use a buffer of (approximately) that size. A negative \var{bufsize} means to use the system default, which usually means fully buffered. The default value for \var{bufsize} is \constant{0} (unbuffered). \var{stdin}, \var{stdout} and \var{stderr} specify the executed programs' standard input, standard output and standard error file handles, respectively. Valid values are \code{PIPE}, an existing file descriptor (a positive integer), an existing file object, and \code{None}. \code{PIPE} indicates that a new pipe to the child should be created. With \code{None}, no redirection will occur; the child's file handles will be inherited from the parent. Additionally, \var{stderr} can be \code{STDOUT}, which indicates that the stderr data from the applications should be captured into the same file handle as for stdout. If \var{preexec_fn} is set to a callable object, this object will be called in the child process just before the child is executed. If \var{close_fds} is true, all file descriptors except \constant{0}, \constant{1} and \constant{2} will be closed before the child process is executed. If \var{shell} is \constant{True}, the specified command will be executed through the shell. If \var{cwd} is not \code{None}, the current directory will be changed to cwd before the child is executed. If \var{env} is not \code{None}, it defines the environment variables for the new process. If \var{universal_newlines} is \constant{True}, the file objects stdout and stderr are opened as a text files, but lines may be terminated by any of \code{'\e n'}, the Unix end-of-line convention, \code{'\e r'}, the Macintosh convention or \code{'\e r\e n'}, the Windows convention. All of these external representations are seen as \code{'\e n'} by the Python program. \note{This feature is only available if Python is built with universal newline support (the default). Also, the newlines attribute of the file objects \member{stdout}, \member{stdin} and \member{stderr} are not updated by the communicate() method.} The \var{startupinfo} and \var{creationflags}, if given, will be passed to the underlying CreateProcess() function. They can specify things such as appearance of the main window and priority for the new process. (Windows only) \end{classdesc} \subsubsection{Convenience Functions} This module also defines one shortcut function: \begin{funcdesc}{call}{*args, **kwargs} Run command with arguments. Wait for command to complete, then return the \member{returncode} attribute. The arguments are the same as for the Popen constructor. Example: \begin{verbatim} retcode = call(["ls", "-l"]) \end{verbatim} \end{funcdesc} \subsubsection{Exceptions} Exceptions raised in the child process, before the new program has started to execute, will be re-raised in the parent. Additionally, the exception object will have one extra attribute called \member{child_traceback}, which is a string containing traceback information from the childs point of view. The most common exception raised is \exception{OSError}. This occurs, for example, when trying to execute a non-existent file. Applications should prepare for \exception{OSError} exceptions. A \exception{ValueError} will be raised if \class{Popen} is called with invalid arguments. \subsubsection{Security} Unlike some other popen functions, this implementation will never call /bin/sh implicitly. This means that all characters, including shell metacharacters, can safely be passed to child processes. \subsection{Popen Objects} Instances of the \class{Popen} class have the following methods: \begin{methoddesc}{poll}{} Check if child process has terminated. Returns returncode attribute. \end{methoddesc} \begin{methoddesc}{wait}{} Wait for child process to terminate. Returns returncode attribute. \end{methoddesc} \begin{methoddesc}{communicate}{input=None} Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate. The optional \var{stdin} argument should be a string to be sent to the child process, or \code{None}, if no data should be sent to the child. communicate() returns a tuple (stdout, stderr). \note{The data read is buffered in memory, so do not use this method if the data size is large or unlimited.} \end{methoddesc} The following attributes are also available: \begin{memberdesc}{stdin} If the \var{stdin} argument is \code{PIPE}, this attribute is a file object that provides input to the child process. Otherwise, it is \code{None}. \end{memberdesc} \begin{memberdesc}{stdout} If the \var{stdout} argument is \code{PIPE}, this attribute is a file object that provides output from the child process. Otherwise, it is \code{None}. \end{memberdesc} \begin{memberdesc}{stderr} If the \var{stderr} argument is \code{PIPE}, this attribute is file object that provides error output from the child process. Otherwise, it is \code{None}. \end{memberdesc} \begin{memberdesc}{pid} The process ID of the child process. \end{memberdesc} \begin{memberdesc}{returncode} The child return code. A \code{None} value indicates that the process hasn't terminated yet. A negative value -N indicates that the child was terminated by signal N (\UNIX{} only). \end{memberdesc} \subsection{Replacing Older Functions with the subprocess Module} In this section, "a ==> b" means that b can be used as a replacement for a. \note{All functions in this section fail (more or less) silently if the executed program cannot be found; this module raises an \exception{OSError} exception.} In the following examples, we assume that the subprocess module is imported with "from subprocess import *". \subsubsection{Replacing /bin/sh shell backquote} \begin{verbatim} output=`mycmd myarg` ==> output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0] \end{verbatim} \subsubsection{Replacing shell pipe line} \begin{verbatim} output=`dmesg | grep hda` ==> p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout) output = p2.communicate()[0] \end{verbatim} \subsubsection{Replacing os.system()} \begin{verbatim} sts = os.system("mycmd" + " myarg") ==> p = Popen("mycmd" + " myarg", shell=True) sts = os.waitpid(p.pid, 0) \end{verbatim} Notes: \begin{itemize} \item Calling the program through the shell is usually not required. \item It's easier to look at the \member{returncode} attribute than the exit status. \end{itemize} A more realistic example would look like this: \begin{verbatim} try: retcode = call("mycmd" + " myarg", shell=True) if retcode < 0: print >>sys.stderr, "Child was terminated by signal", -retcode else: print >>sys.stderr, "Child returned", retcode except OSError, e: print >>sys.stderr, "Execution failed:", e \end{verbatim} \subsubsection{Replacing os.spawn*} P_NOWAIT example: \begin{verbatim} pid = os.spawnlp(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg") ==> pid = Popen(["/bin/mycmd", "myarg"]).pid \end{verbatim} P_WAIT example: \begin{verbatim} retcode = os.spawnlp(os.P_WAIT, "/bin/mycmd", "mycmd", "myarg") ==> retcode = call(["/bin/mycmd", "myarg"]) \end{verbatim} Vector example: \begin{verbatim} os.spawnvp(os.P_NOWAIT, path, args) ==> Popen([path] + args[1:]) \end{verbatim} Environment example: \begin{verbatim} os.spawnlpe(os.P_NOWAIT, "/bin/mycmd", "mycmd", "myarg", env) ==> Popen(["/bin/mycmd", "myarg"], env={"PATH": "/usr/bin"}) \end{verbatim} \subsubsection{Replacing os.popen*} \begin{verbatim} pipe = os.popen(cmd, mode='r', bufsize) ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdout=PIPE).stdout \end{verbatim} \begin{verbatim} pipe = os.popen(cmd, mode='w', bufsize) ==> pipe = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE).stdin \end{verbatim} \begin{verbatim} (child_stdin, child_stdout) = os.popen2(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdin, child_stdout) = (p.stdin, p.stdout) \end{verbatim} \begin{verbatim} (child_stdin, child_stdout, child_stderr) = os.popen3(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) (child_stdin, child_stdout, child_stderr) = (p.stdin, p.stdout, p.stderr) \end{verbatim} \begin{verbatim} (child_stdin, child_stdout_and_stderr) = os.popen4(cmd, mode, bufsize) ==> p = Popen(cmd, shell=True, bufsize=bufsize, stdin=PIPE, stdout=PIPE, stderr=STDOUT, close_fds=True) (child_stdin, child_stdout_and_stderr) = (p.stdin, p.stdout) \end{verbatim} \subsubsection{Replacing popen2.*} \note{If the cmd argument to popen2 functions is a string, the command is executed through /bin/sh. If it is a list, the command is directly executed.} \begin{verbatim} (child_stdout, child_stdin) = popen2.popen2("somestring", bufsize, mode) ==> p = Popen(["somestring"], shell=True, bufsize=bufsize stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdout, child_stdin) = (p.stdout, p.stdin) \end{verbatim} \begin{verbatim} (child_stdout, child_stdin) = popen2.popen2(["mycmd", "myarg"], bufsize, mode) ==> p = Popen(["mycmd", "myarg"], bufsize=bufsize, stdin=PIPE, stdout=PIPE, close_fds=True) (child_stdout, child_stdin) = (p.stdout, p.stdin) \end{verbatim} The popen2.Popen3 and popen3.Popen4 basically works as subprocess.Popen, except that: \begin{itemize} \item subprocess.Popen raises an exception if the execution fails \item the \var{capturestderr} argument is replaced with the \var{stderr} argument. \item stdin=PIPE and stdout=PIPE must be specified. \item popen2 closes all file descriptors by default, but you have to specify close_fds=True with subprocess.Popen. \end{itemize} Index: lib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/lib.tex,v retrieving revision 1.230 retrieving revision 1.231 diff -u -d -r1.230 -r1.231 --- lib.tex 31 Aug 2004 13:19:43 -0000 1.230 +++ lib.tex 17 Oct 2004 16:29:48 -0000 1.231 @@ -145,6 +145,7 @@ \input{libstatcache} \input{libstatvfs} \input{libfilecmp} +\input{libsubprocess} \input{libpopen2} \input{libdatetime} \input{libtime} From nnorwitz at users.sourceforge.net Sun Oct 17 18:36:08 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Sun Oct 17 18:36:11 2004 Subject: [Python-checkins] python/dist/src/Doc/lib liblocale.tex,1.38,1.39 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3233/Doc/lib Modified Files: liblocale.tex Log Message: SF patch #1047577, typo in liblocale.tex Index: liblocale.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liblocale.tex,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- liblocale.tex 29 Jul 2004 03:48:59 -0000 1.38 +++ liblocale.tex 17 Oct 2004 16:36:05 -0000 1.39 @@ -397,7 +397,7 @@ \begin{verbatim} >>> import locale ->>> loc = locale.setlocale(locale.LC_ALL) # get current locale +>>> loc = locale.getlocale(locale.LC_ALL) # get current locale >>> locale.setlocale(locale.LC_ALL, 'de_DE') # use German locale; name might vary with platform >>> locale.strcoll('f\xe4n', 'foo') # compare a string containing an umlaut >>> locale.setlocale(locale.LC_ALL, '') # use user's preferred locale From rhettinger at users.sourceforge.net Sun Oct 17 18:36:56 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun Oct 17 18:36:58 2004 Subject: [Python-checkins] python/dist/src/Lib subprocess.py,1.6,1.7 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3412 Modified Files: subprocess.py Log Message: Fix docstring formatting of escape sequences. Index: subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/subprocess.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- subprocess.py 17 Oct 2004 14:47:05 -0000 1.6 +++ subprocess.py 17 Oct 2004 16:36:53 -0000 1.7 @@ -25,7 +25,7 @@ # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -"""subprocess - Subprocesses with accessible I/O streams +r"""subprocess - Subprocesses with accessible I/O streams This module allows you to spawn processes, connect to their input/output/error pipes, and obtain their return codes. This module From rhettinger at users.sourceforge.net Sun Oct 17 18:40:16 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun Oct 17 18:40:19 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_itertools.py, 1.35, 1.36 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4458/Lib/test Modified Files: test_itertools.py Log Message: Fix and test weak referencing of itertools.tee objects. Index: test_itertools.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_itertools.py,v retrieving revision 1.35 retrieving revision 1.36 diff -u -d -r1.35 -r1.36 --- test_itertools.py 29 Sep 2004 11:40:50 -0000 1.35 +++ test_itertools.py 17 Oct 2004 16:40:14 -0000 1.36 @@ -1,6 +1,7 @@ import unittest from test import test_support from itertools import * +from weakref import proxy import sys import operator import random @@ -382,6 +383,13 @@ t3 = tnew(t1) self.assert_(list(t1) == list(t2) == list(t3) == list('abc')) + # test that tee objects are weak referencable + a, b = tee(xrange(10)) + p = proxy(a) + self.assertEqual(getattr(p, '__class__'), type(b)) + del a + self.assertRaises(ReferenceError, getattr, p, '__class__') + def test_StopIteration(self): self.assertRaises(StopIteration, izip().next) From rhettinger at users.sourceforge.net Sun Oct 17 18:40:16 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun Oct 17 18:40:20 2004 Subject: [Python-checkins] python/dist/src/Modules itertoolsmodule.c, 1.37, 1.38 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4458/Modules Modified Files: itertoolsmodule.c Log Message: Fix and test weak referencing of itertools.tee objects. Index: itertoolsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/itertoolsmodule.c,v retrieving revision 1.37 retrieving revision 1.38 diff -u -d -r1.37 -r1.38 --- itertoolsmodule.c 2 Oct 2004 10:56:43 -0000 1.37 +++ itertoolsmodule.c 17 Oct 2004 16:40:14 -0000 1.38 @@ -329,6 +329,7 @@ PyObject_HEAD teedataobject *dataobj; int index; + PyObject *weakreflist; } teeobject; static PyTypeObject teedataobject_type; @@ -452,6 +453,7 @@ Py_INCREF(to->dataobj); newto->dataobj = to->dataobj; newto->index = to->index; + newto->weakreflist = NULL; return (PyObject *)newto; } @@ -476,6 +478,7 @@ goto done; to->dataobj = (teedataobject *)teedataobject_new(it); to->index = 0; + to->weakreflist = NULL; done: Py_XDECREF(it); return (PyObject *)to; @@ -494,6 +497,8 @@ static void tee_dealloc(teeobject *to) { + if (to->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) to); Py_XDECREF(to->dataobj); PyObject_Del(to); } @@ -533,7 +538,7 @@ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ + offsetof(teeobject, weakreflist), /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)tee_next, /* tp_iternext */ tee_methods, /* tp_methods */ From nnorwitz at users.sourceforge.net Sun Oct 17 18:46:30 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Sun Oct 17 18:46:33 2004 Subject: [Python-checkins] python/dist/src/Doc/lib liblocale.tex, 1.33.10.2, 1.33.10.3 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6505/Doc/lib Modified Files: Tag: release23-maint liblocale.tex Log Message: SF patch #1047577, typo in liblocale.tex Index: liblocale.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liblocale.tex,v retrieving revision 1.33.10.2 retrieving revision 1.33.10.3 diff -u -d -r1.33.10.2 -r1.33.10.3 --- liblocale.tex 3 Sep 2003 04:53:17 -0000 1.33.10.2 +++ liblocale.tex 17 Oct 2004 16:46:28 -0000 1.33.10.3 @@ -397,7 +397,7 @@ \begin{verbatim} >>> import locale ->>> loc = locale.setlocale(locale.LC_ALL) # get current locale +>>> loc = locale.getlocale(locale.LC_ALL) # get current locale >>> locale.setlocale(locale.LC_ALL, 'de_DE') # use German locale; name might vary with platform >>> locale.strcoll('f\xe4n', 'foo') # compare a string containing an umlaut >>> locale.setlocale(locale.LC_ALL, '') # use user's preferred locale From fdrake at users.sourceforge.net Sun Oct 17 21:37:11 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Sun Oct 17 21:37:14 2004 Subject: [Python-checkins] python/dist/src/Modules itertoolsmodule.c, 1.38, 1.39 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22219 Modified Files: itertoolsmodule.c Log Message: some platforms still need offsetof() from structmember.h Index: itertoolsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/itertoolsmodule.c,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- itertoolsmodule.c 17 Oct 2004 16:40:14 -0000 1.38 +++ itertoolsmodule.c 17 Oct 2004 19:36:57 -0000 1.39 @@ -1,5 +1,6 @@ #include "Python.h" +#include "structmember.h" /* Itertools module written and maintained by Raymond D. Hettinger From nnorwitz at users.sourceforge.net Sun Oct 17 21:55:50 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Sun Oct 17 21:55:53 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libpdb.tex,1.40,1.41 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26943/Doc/lib Modified Files: libpdb.tex Log Message: SF bug #1048756, Doc typo for pdb Index: libpdb.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libpdb.tex,v retrieving revision 1.40 retrieving revision 1.41 diff -u -d -r1.40 -r1.41 --- libpdb.tex 4 Jul 2004 04:47:40 -0000 1.40 +++ libpdb.tex 17 Oct 2004 19:55:47 -0000 1.41 @@ -285,7 +285,7 @@ \item[pp \var{expression}] -Like the \samp{p} command, except the value of the exception is +Like the \samp{p} command, except the value of the expression is pretty-printed using the \module{pprint} module. \item[alias \optional{\var{name} \optional{command}}] From nnorwitz at users.sourceforge.net Sun Oct 17 21:56:42 2004 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Sun Oct 17 21:56:44 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libpdb.tex, 1.37.8.1, 1.37.8.2 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27181/Doc/lib Modified Files: Tag: release23-maint libpdb.tex Log Message: SF bug #1048756, Doc typo for pdb Index: libpdb.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libpdb.tex,v retrieving revision 1.37.8.1 retrieving revision 1.37.8.2 diff -u -d -r1.37.8.1 -r1.37.8.2 --- libpdb.tex 25 Aug 2003 04:34:46 -0000 1.37.8.1 +++ libpdb.tex 17 Oct 2004 19:56:40 -0000 1.37.8.2 @@ -285,7 +285,7 @@ \item[pp \var{expression}] -Like the \samp{p} command, except the value of the exception is +Like the \samp{p} command, except the value of the expression is pretty-printed using the \module{pprint} module. \item[alias \optional{\var{name} \optional{command}}] From perky at users.sourceforge.net Mon Oct 18 01:51:23 2004 From: perky at users.sourceforge.net (perky@users.sourceforge.net) Date: Mon Oct 18 01:51:26 2004 Subject: [Python-checkins] python/dist/src/Lib codecs.py,1.34,1.35 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27701/Lib Modified Files: codecs.py Log Message: SF #1048865: Fix a trivial typo that breaks StreamReader.readlines() Index: codecs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/codecs.py,v retrieving revision 1.34 retrieving revision 1.35 diff -u -d -r1.34 -r1.35 --- codecs.py 7 Sep 2004 20:24:04 -0000 1.34 +++ codecs.py 17 Oct 2004 23:51:21 -0000 1.35 @@ -334,7 +334,7 @@ """ data = self.read() - return self.splitlines(keepends) + return data.splitlines(keepends) def reset(self): From perky at users.sourceforge.net Mon Oct 18 01:51:24 2004 From: perky at users.sourceforge.net (perky@users.sourceforge.net) Date: Mon Oct 18 01:51:27 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_codecs.py, 1.13, 1.14 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27701/Lib/test Modified Files: test_codecs.py Log Message: SF #1048865: Fix a trivial typo that breaks StreamReader.readlines() Index: test_codecs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_codecs.py,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- test_codecs.py 7 Sep 2004 20:24:21 -0000 1.13 +++ test_codecs.py 17 Oct 2004 23:51:21 -0000 1.14 @@ -458,6 +458,16 @@ self.assertEquals(codecs.encode(u'\xe4\xf6\xfc', 'latin-1'), '\xe4\xf6\xfc') +class StreamReaderTest(unittest.TestCase): + + def setUp(self): + self.reader = codecs.getreader('utf-8') + self.stream = StringIO.StringIO('\xed\x95\x9c\n\xea\xb8\x80') + + def test_readlines(self): + f = self.reader(self.stream) + self.assertEquals(f.readlines(), [u'\ud55c\n', u'\uae00']) + def test_main(): test_support.run_unittest( UTF16Test, @@ -469,7 +479,8 @@ PunycodeTest, NameprepTest, CodecTest, - CodecsModuleTest + CodecsModuleTest, + StreamReaderTest ) From bcannon at users.sourceforge.net Mon Oct 18 03:32:12 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:32:14 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1164,1.1165 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21354/Misc Modified Files: NEWS Log Message: Add sections for 2.4b2 Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1164 retrieving revision 1.1165 diff -u -d -r1.1164 -r1.1165 --- NEWS 15 Oct 2004 08:07:12 -0000 1.1164 +++ NEWS 18 Oct 2004 01:32:09 -0000 1.1165 @@ -4,6 +4,67 @@ (editors: check NEWS.help for information about editing NEWS using ReST.) +What's New in Python 2.4 beta 2? +================================ + +*Release date: XX-XXX-XXXX* + +Core and builtins +----------------- + +... + +Extension Modules +----------------- + +... + +Library +------- + +... + +Build +----- + +... + +C API +----- + +... + +Documentation +------------- + +... + +Tests +----- + +... + +Windows +------- + +... + +Mac +--- + +... + +New platforms +------------- + +... + +Tools/Demos +----------- + +... + + What's New in Python 2.4 beta 1? ================================ From bcannon at users.sourceforge.net Mon Oct 18 03:37:59 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:38:02 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_strptime.py, 1.27, 1.28 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22698/Lib/test Modified Files: test_strptime.py Log Message: Add support for %U and %W to contribute to calculating the date when the year and day of the week are specified. Closes bug #1045381. Index: test_strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_strptime.py,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- test_strptime.py 6 Oct 2004 02:11:36 -0000 1.27 +++ test_strptime.py 18 Oct 2004 01:37:57 -0000 1.28 @@ -6,6 +6,7 @@ import re import sys from test import test_support +from datetime import date as datetime_date import _strptime @@ -417,6 +418,27 @@ "Calculation of day of the week failed;" "%s != %s" % (result.tm_wday, self.time_tuple.tm_wday)) + def test_week_of_year_and_day_of_week_calculation(self): + # Should be able to infer date if given year, week of year (%U or %W) + # and day of the week + def test_helper(ymd_tuple, test_reason): + for directive in ('W', 'U'): + format_string = "%%Y %%%s %%w" % directive + strp_input = datetime_date(*ymd_tuple).strftime(format_string) + strp_output = _strptime.strptime(strp_input, format_string) + self.failUnless(strp_output[:3] == ymd_tuple, + "%s(%s) test failed w/ '%s': %s != %s" % + (test_reason, directive, strp_input, + strp_output[:3], ymd_tuple[:3])) + test_helper((1901, 1, 3), "week 0") + test_helper((1901, 1, 8), "common case") + test_helper((1901, 1, 13), "day on Sunday") + test_helper((1901, 1, 14), "day on Monday") + test_helper((1905, 1, 1), "Jan 1 on Sunday") + test_helper((1906, 1, 1), "Jan 1 on Monday") + test_helper((1905, 12, 31), "Dec 31 on Sunday") + test_helper((1906, 12, 31), "Dec 31 on Monday") + class CacheTests(unittest.TestCase): """Test that caching works properly.""" From bcannon at users.sourceforge.net Mon Oct 18 03:37:59 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:38:03 2004 Subject: [Python-checkins] python/dist/src/Lib _strptime.py,1.35,1.36 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22698/Lib Modified Files: _strptime.py Log Message: Add support for %U and %W to contribute to calculating the date when the year and day of the week are specified. Closes bug #1045381. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.35 retrieving revision 1.36 diff -u -d -r1.35 -r1.36 --- _strptime.py 6 Oct 2004 22:48:58 -0000 1.35 +++ _strptime.py 18 Oct 2004 01:37:57 -0000 1.36 @@ -212,7 +212,7 @@ for tz in tz_names), 'Z'), '%': '%'}) - base.__setitem__('W', base.__getitem__('U')) + base.__setitem__('W', base.__getitem__('U').replace('U', 'W')) base.__setitem__('c', self.pattern(self.locale_time.LC_date_time)) base.__setitem__('x', self.pattern(self.locale_time.LC_date)) base.__setitem__('X', self.pattern(self.locale_time.LC_time)) @@ -298,10 +298,17 @@ month = day = 1 hour = minute = second = 0 tz = -1 + week_of_year = -1 + week_of_year_start = -1 # weekday and julian defaulted to -1 so as to signal need to calculate values weekday = julian = -1 found_dict = found.groupdict() for group_key in found_dict.iterkeys(): + # Directives not explicitly handled below: + # c, x, X + # handled by making out of other directives + # U, W + # worthless without day of the week if group_key == 'y': year = int(found_dict['y']) # Open Group specification for strptime() states that a %y @@ -355,6 +362,14 @@ weekday -= 1 elif group_key == 'j': julian = int(found_dict['j']) + elif group_key in ('U', 'W'): + week_of_year = int(found_dict[group_key]) + if group_key == 'U': + # U starts week on Sunday + week_of_year_start = 6 + else: + # W starts week on Monday + week_of_year_start = 0 elif group_key == 'Z': # Since -1 is default value only need to worry about setting tz if # it can be something other than -1. @@ -370,6 +385,33 @@ else: tz = value break + # If we know the week of the year and what day of that week, we can figure + # out the Julian day of the year + # Calculations below assume 0 is a Monday + # XXX only works for W + if julian == -1 and week_of_year != -1 and weekday != -1 and year != -1: + # Adjust for U directive so that calculations are not dependent on + # directive used to figure out week of year + if weekday == 6 and week_of_year_start == 6: + week_of_year -= 1 + # For some reason when Dec 31 falls on a Monday the week of the year is + # off by a week; verified on both OS X and Solaris. + elif weekday == 0 and week_of_year_start == 6 and week_of_year >= 52: + week_of_year += 1 + # Calculate how many days in week 0 + first_weekday = datetime_date(year, 1, 1).weekday() + preceeding_days = 7 - first_weekday + if preceeding_days == 7: + preceeding_days = 0 + # If in week 0, then just figure out how many days from Jan 1 to day of + # week specified, else calculate by multiplying week of year by 7, + # adding in days in week 0, and the number of days from Monday to the + # day of the week + if not week_of_year: + julian = 1 + weekday - first_weekday + else: + days_to_week = preceeding_days + (7 * (week_of_year - 1)) + julian = 1 + days_to_week + weekday # Cannot pre-calculate datetime_date() since can change in Julian #calculation and thus could have different value for the day of the week #calculation From bcannon at users.sourceforge.net Mon Oct 18 03:38:00 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:38:04 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libtime.tex,1.67,1.68 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22698/Doc/lib Modified Files: libtime.tex Log Message: Add support for %U and %W to contribute to calculating the date when the year and day of the week are specified. Closes bug #1045381. Index: libtime.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libtime.tex,v retrieving revision 1.67 retrieving revision 1.68 diff -u -d -r1.67 -r1.68 --- libtime.tex 28 Sep 2004 18:30:03 -0000 1.67 +++ libtime.tex 18 Oct 2004 01:37:57 -0000 1.68 @@ -247,11 +247,11 @@ \lineiii{\%S}{Second as a decimal number [00,61].}{(2)} \lineiii{\%U}{Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year - preceding the first Sunday are considered to be in week 0.}{} + preceding the first Sunday are considered to be in week 0.}{(3)} \lineiii{\%w}{Weekday as a decimal number [0(Sunday),6].}{} \lineiii{\%W}{Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year - preceding the first Monday are considered to be in week 0.}{} + preceding the first Monday are considered to be in week 0.}{(3)} \lineiii{\%x}{Locale's appropriate date representation.}{} \lineiii{\%X}{Locale's appropriate time representation.}{} \lineiii{\%y}{Year without century as a decimal number [00,99].}{} @@ -271,6 +271,9 @@ \item[(2)] The range really is \code{0} to \code{61}; this accounts for leap seconds and the (very rare) double leap seconds. + \item[(3)] + \code{\%U} and \code{\%W} are only used in calculations when the day of the + week and the year are specified. \end{description} Here is an example, a format for dates compatible with that specified From bcannon at users.sourceforge.net Mon Oct 18 03:38:00 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:38:05 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1165,1.1166 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22698/Misc Modified Files: NEWS Log Message: Add support for %U and %W to contribute to calculating the date when the year and day of the week are specified. Closes bug #1045381. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1165 retrieving revision 1.1166 diff -u -d -r1.1165 -r1.1166 --- NEWS 18 Oct 2004 01:32:09 -0000 1.1165 +++ NEWS 18 Oct 2004 01:37:57 -0000 1.1166 @@ -22,7 +22,8 @@ Library ------- -... +- Bug #1045381: time.strptime() can now infer the date using %U or %W (week of + the year) when the day of the week and year are also specified. Build ----- From bcannon at users.sourceforge.net Mon Oct 18 03:47:48 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:47:51 2004 Subject: [Python-checkins] python/dist/src/Lib _strptime.py,1.36,1.37 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25257/Lib Modified Files: _strptime.py Log Message: Fix comments. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.36 retrieving revision 1.37 diff -u -d -r1.36 -r1.37 --- _strptime.py 18 Oct 2004 01:37:57 -0000 1.36 +++ _strptime.py 18 Oct 2004 01:47:46 -0000 1.37 @@ -298,9 +298,12 @@ month = day = 1 hour = minute = second = 0 tz = -1 + # Default to -1 to signify that values not known; not critical to have, + # though week_of_year = -1 week_of_year_start = -1 - # weekday and julian defaulted to -1 so as to signal need to calculate values + # weekday and julian defaulted to -1 so as to signal need to calculate + # values weekday = julian = -1 found_dict = found.groupdict() for group_key in found_dict.iterkeys(): @@ -388,7 +391,6 @@ # If we know the week of the year and what day of that week, we can figure # out the Julian day of the year # Calculations below assume 0 is a Monday - # XXX only works for W if julian == -1 and week_of_year != -1 and weekday != -1 and year != -1: # Adjust for U directive so that calculations are not dependent on # directive used to figure out week of year From bcannon at users.sourceforge.net Mon Oct 18 03:53:18 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:53:20 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libtime.tex,1.68,1.69 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26307/Doc/lib Modified Files: libtime.tex Log Message: Clarify note about using %U and %W with strptime(). Index: libtime.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libtime.tex,v retrieving revision 1.68 retrieving revision 1.69 diff -u -d -r1.68 -r1.69 --- libtime.tex 18 Oct 2004 01:37:57 -0000 1.68 +++ libtime.tex 18 Oct 2004 01:53:15 -0000 1.69 @@ -272,8 +272,9 @@ The range really is \code{0} to \code{61}; this accounts for leap seconds and the (very rare) double leap seconds. \item[(3)] - \code{\%U} and \code{\%W} are only used in calculations when the day of the - week and the year are specified. + When used with the \function{strptime()} function, \code{\%U} and \code{\%W} + are only used in calculations when the day of the week and the year are + specified. \end{description} Here is an example, a format for dates compatible with that specified From bcannon at users.sourceforge.net Mon Oct 18 03:56:19 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:56:21 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_strptime.py, 1.19.4.4, 1.19.4.5 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27014/Lib/test Modified Files: Tag: release23-maint test_strptime.py Log Message: Add support for using %U and %W in strptime when year and day of the week are also specified. Closes bug #1045381. Index: test_strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_strptime.py,v retrieving revision 1.19.4.4 retrieving revision 1.19.4.5 diff -u -d -r1.19.4.4 -r1.19.4.5 --- test_strptime.py 29 Aug 2003 02:34:22 -0000 1.19.4.4 +++ test_strptime.py 18 Oct 2004 01:56:16 -0000 1.19.4.5 @@ -6,6 +6,7 @@ import re import sys from test import test_support +from datetime import date as datetime_date import _strptime @@ -450,6 +451,29 @@ "Calculation of day of the week failed;" "%s != %s" % (result.tm_wday, self.time_tuple.tm_wday)) + def test_week_of_year_and_day_of_week_calculation(self): + # Should be able to infer date if given year, week of year (%U or %W) + # and day of the week + def test_helper(ymd_tuple, test_reason): + for directive in ('W', 'U'): + format_string = "%%Y %%%s %%w" % directive + strp_input = datetime_date(*ymd_tuple).strftime(format_string) + strp_output = _strptime.strptime(strp_input, format_string) + self.failUnless(strp_output[:3] == ymd_tuple, + "%s(%s) test failed w/ '%s': %s != %s" % + (test_reason, directive, strp_input, + strp_output[:3], ymd_tuple[:3])) + test_helper((1901, 1, 3), "week 0") + test_helper((1901, 1, 8), "common case") + test_helper((1901, 1, 13), "day on Sunday") + test_helper((1901, 1, 14), "day on Monday") + test_helper((1905, 1, 1), "Jan 1 on Sunday") + test_helper((1906, 1, 1), "Jan 1 on Monday") + test_helper((1905, 12, 31), "Dec 31 on Sunday") + test_helper((1906, 12, 31), "Dec 31 on Monday") + + + class CacheTests(unittest.TestCase): """Test that caching works properly.""" From bcannon at users.sourceforge.net Mon Oct 18 03:56:18 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:56:24 2004 Subject: [Python-checkins] python/dist/src/Lib _strptime.py, 1.23.4.5, 1.23.4.6 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27014/Lib Modified Files: Tag: release23-maint _strptime.py Log Message: Add support for using %U and %W in strptime when year and day of the week are also specified. Closes bug #1045381. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.23.4.5 retrieving revision 1.23.4.6 diff -u -d -r1.23.4.5 -r1.23.4.6 --- _strptime.py 6 Oct 2004 02:16:45 -0000 1.23.4.5 +++ _strptime.py 18 Oct 2004 01:56:16 -0000 1.23.4.6 @@ -311,7 +311,7 @@ # W is set below by using 'U' 'y': r"(?P\d\d)", 'Y': r"(?P\d\d\d\d)"}) - base.__setitem__('W', base.__getitem__('U')) + base.__setitem__('W', base.__getitem__('U').replace('U', 'W')) if locale_time: self.locale_time = locale_time else: @@ -431,6 +431,8 @@ month = day = 1 hour = minute = second = 0 tz = -1 + week_of_year = -1 + week_of_year_start = -1 # weekday and julian defaulted to -1 so as to signal need to calculate values weekday = julian = -1 found_dict = found.groupdict() @@ -490,6 +492,14 @@ weekday -= 1 elif group_key == 'j': julian = int(found_dict['j']) + elif group_key in ('U', 'W'): + week_of_year = int(found_dict[group_key]) + if group_key == 'U': + # U starts week on Sunday + week_of_year_start = 6 + else: + # W starts week on Monday + week_of_year_start = 0 elif group_key == 'Z': # Since -1 is default value only need to worry about setting tz if # it can be something other than -1. @@ -505,7 +515,32 @@ elif time.daylight and \ locale_time.timezone[3].lower() == found_zone: tz = 1 - + # If we know the week of the year and what day of that week, we can figure + # out the Julian day of the year + # Calculations below assume 0 is a Monday + if julian == -1 and week_of_year != -1 and weekday != -1 and year != -1: + # Adjust for U directive so that calculations are not dependent on + # directive used to figure out week of year + if weekday == 6 and week_of_year_start == 6: + week_of_year -= 1 + # For some reason when Dec 31 falls on a Monday the week of the year is + # off by a week; verified on both OS X and Solaris. + elif weekday == 0 and week_of_year_start == 6 and week_of_year >= 52: + week_of_year += 1 + # Calculate how many days in week 0 + first_weekday = datetime_date(year, 1, 1).weekday() + preceeding_days = 7 - first_weekday + if preceeding_days == 7: + preceeding_days = 0 + # If in week 0, then just figure out how many days from Jan 1 to day of + # week specified, else calculate by multiplying week of year by 7, + # adding in days in week 0, and the number of days from Monday to the + # day of the week + if not week_of_year: + julian = 1 + weekday - first_weekday + else: + days_to_week = preceeding_days + (7 * (week_of_year - 1)) + julian = 1 + days_to_week + weekday # Cannot pre-calculate datetime_date() since can change in Julian #calculation and thus could have different value for the day of the week #calculation From bcannon at users.sourceforge.net Mon Oct 18 03:56:19 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:56:25 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libtime.tex, 1.60.8.1, 1.60.8.2 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27014/Doc/lib Modified Files: Tag: release23-maint libtime.tex Log Message: Add support for using %U and %W in strptime when year and day of the week are also specified. Closes bug #1045381. Index: libtime.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libtime.tex,v retrieving revision 1.60.8.1 retrieving revision 1.60.8.2 diff -u -d -r1.60.8.1 -r1.60.8.2 --- libtime.tex 8 Sep 2003 18:55:01 -0000 1.60.8.1 +++ libtime.tex 18 Oct 2004 01:56:16 -0000 1.60.8.2 @@ -235,11 +235,11 @@ \lineiii{\%S}{Second as a decimal number [00,61].}{(1)} \lineiii{\%U}{Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year - preceding the first Sunday are considered to be in week 0.}{} + preceding the first Sunday are considered to be in week 0.}{(2)} \lineiii{\%w}{Weekday as a decimal number [0(Sunday),6].}{} \lineiii{\%W}{Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year - preceding the first Monday are considered to be in week 0.}{} + preceding the first Monday are considered to be in week 0.}{(2)} \lineiii{\%x}{Locale's appropriate date representation.}{} \lineiii{\%X}{Locale's appropriate time representation.}{} \lineiii{\%y}{Year without century as a decimal number [00,99].}{} @@ -255,6 +255,10 @@ \item[(1)] The range really is \code{0} to \code{61}; this accounts for leap seconds and the (very rare) double leap seconds. + \item[(2)] + When used with the \function{strptime()} function, \code{\%U} and \code{\%W} + are only used in calculations when the day of the week and the year are + specified. \end{description} Here is an example, a format for dates compatible with that specified From bcannon at users.sourceforge.net Mon Oct 18 03:56:20 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon Oct 18 03:56:26 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.831.4.153, 1.831.4.154 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27014/Misc Modified Files: Tag: release23-maint NEWS Log Message: Add support for using %U and %W in strptime when year and day of the week are also specified. Closes bug #1045381. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.831.4.153 retrieving revision 1.831.4.154 diff -u -d -r1.831.4.153 -r1.831.4.154 --- NEWS 6 Oct 2004 02:16:45 -0000 1.831.4.153 +++ NEWS 18 Oct 2004 01:56:17 -0000 1.831.4.154 @@ -53,6 +53,9 @@ Library ------- +- Bug #1045381: strptime() now uses %U and %W for date calculations if the year + and day of the week are also specified. + - Bug #1039270: Locale data is now escaped for regex metacharacters. - Bug #807871: Fix tkMessageBox.askyesno result. From akuchling at users.sourceforge.net Mon Oct 18 18:16:56 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Mon Oct 18 18:17:00 2004 Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew24.tex, 1.110, 1.111 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23453 Modified Files: whatsnew24.tex Log Message: Bump version Index: whatsnew24.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew24.tex,v retrieving revision 1.110 retrieving revision 1.111 diff -u -d -r1.110 -r1.111 --- whatsnew24.tex 12 Oct 2004 16:36:57 -0000 1.110 +++ whatsnew24.tex 18 Oct 2004 16:16:53 -0000 1.111 @@ -10,7 +10,7 @@ % \title{What's New in Python 2.4} -\release{0.4} +\release{0.5} \author{A.M.\ Kuchling} \authoraddress{ \strong{Python Software Foundation}\\ From fdrake at users.sourceforge.net Mon Oct 18 23:30:42 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Mon Oct 18 23:30:46 2004 Subject: [Python-checkins] python/dist/src/Doc/doc doc.tex,1.87,1.88 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/doc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11494 Modified Files: doc.tex Log Message: made it clear that this isn't a complete reference to LaTeX-as-used-in-Python-documentation, and added some notes about what's missing Index: doc.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/doc/doc.tex,v retrieving revision 1.87 retrieving revision 1.88 diff -u -d -r1.87 -r1.88 --- doc.tex 1 Aug 2004 22:36:40 -0000 1.87 +++ doc.tex 18 Oct 2004 21:30:40 -0000 1.88 @@ -214,7 +214,11 @@ This section is a brief introduction to \LaTeX{} concepts and syntax, to provide authors enough information to author documents - productively without having to become ``\TeX{}nicians.'' + productively without having to become ``\TeX{}nicians.'' This does + not teach everything needed to know about writing \LaTeX{} for + Python documentation; many of the standard ``environments'' are not + described here (though you will learn how to mark something as an + environment). Perhaps the most important concept to keep in mind while marking up Python documentation is that while \TeX{} is unstructured, \LaTeX{} was @@ -445,6 +449,34 @@ \end{description} + \subsection{Common Environments \label{latex-environments}} + + \LaTeX{} provides a variety of environments even without the + additional markup provided by the Python-specific document classes + introducted in the next section. The following environments are + provided as part of standard \LaTeX{} and are being used in the + standard Python documentation; descriptions will be added here as + time allows. + +\begin{verbatim} +abstract +alltt +description +displaymath +document +enumerate +figure +flushleft +itemize +list +math +quotation +quote +sloppypar +verbatim +\end{verbatim} + + \section{Document Classes \label{classes}} Two \LaTeX{} document classes are defined specifically for use with @@ -480,7 +512,8 @@ The Python document classes define a lot of new environments and macros. This section contains the reference material for these - facilities. + facilities. Documentation for ``standard'' \LaTeX{} constructs is + not included here, though they are used in the Python documentation. \subsection{Markup for the Preamble \label{preamble-info}} From fdrake at users.sourceforge.net Tue Oct 19 17:40:42 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Tue Oct 19 17:40:45 2004 Subject: [Python-checkins] python/dist/src/Doc/perl distutils.perl,1.2,1.3 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/perl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1892/perl Modified Files: distutils.perl Log Message: Rely on the style sheet more for the distutils markup. Index: distutils.perl =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/perl/distutils.perl,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- distutils.perl 15 Nov 2002 20:32:03 -0000 1.2 +++ distutils.perl 19 Oct 2004 15:40:38 -0000 1.3 @@ -3,19 +3,19 @@ package main; sub do_cmd_command { - return use_wrappers(@_[0], '', ''); + return use_wrappers(@_[0], '', ''); } sub do_cmd_option { - return use_wrappers(@_[0], '', ''); + return use_wrappers(@_[0], '', ''); } sub do_cmd_filevar { - return use_wrappers(@_[0], '', ''); + return use_wrappers(@_[0], '', ''); } sub do_cmd_XXX { - return use_wrappers(@_[0], '** ', ' **'); + return use_wrappers(@_[0], '', ''); } -1; +1; # Bad Perl. From fdrake at users.sourceforge.net Tue Oct 19 17:40:41 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Tue Oct 19 17:40:46 2004 Subject: [Python-checkins] python/dist/src/Doc/html style.css,1.36,1.37 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/html In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1892/html Modified Files: style.css Log Message: Rely on the style sheet more for the distutils markup. Index: style.css =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/html/style.css,v retrieving revision 1.36 retrieving revision 1.37 diff -u -d -r1.36 -r1.37 --- style.css 23 Jan 2004 08:51:51 -0000 1.36 +++ style.css 19 Oct 2004 15:40:38 -0000 1.37 @@ -151,6 +151,19 @@ /* + * Additional styles for the distutils package. + */ +.du-command { font-family: monospace; } +.du-option { font-family: avantgarde, sans-serif; } +.du-filevar { font-family: avantgarde, sans-serif; + font-style: italic; } +.du-xxx:before { content: "** "; + font-weight: bold; } +.du-xxx:after { content: " **"; + font-weight: bold; } + + +/* * Some specialization for printed output. */ @media print { From akuchling at users.sourceforge.net Tue Oct 19 20:52:51 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 20:52:54 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libzlib.tex,1.28,1.29 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23424 Modified Files: libzlib.tex Log Message: [Bug #1049826] Update version of zlib referenced in text Index: libzlib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libzlib.tex,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- libzlib.tex 21 Jun 2003 14:15:25 -0000 1.28 +++ libzlib.tex 19 Oct 2004 18:52:49 -0000 1.29 @@ -9,8 +9,8 @@ For applications that require data compression, the functions in this module allow compression and decompression, using the zlib library. The zlib library has its own home page at -\url{http://www.gzip.org/zlib/}. Version 1.1.3 is the -most recent version as of September 2000; use a later version if one +\url{http://www.gzip.org/zlib/}. Version 1.2.1 is the +most recent version as of October 2004; use a later version if one is available. There are known incompatibilities between the Python module and earlier versions of the zlib library. From akuchling at users.sourceforge.net Tue Oct 19 20:53:48 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 20:53:51 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libzlib.tex, 1.28, 1.28.10.1 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23701 Modified Files: Tag: release23-maint libzlib.tex Log Message: [Bug #1049826] Update version of zlib referenced in text Index: libzlib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libzlib.tex,v retrieving revision 1.28 retrieving revision 1.28.10.1 diff -u -d -r1.28 -r1.28.10.1 --- libzlib.tex 21 Jun 2003 14:15:25 -0000 1.28 +++ libzlib.tex 19 Oct 2004 18:53:46 -0000 1.28.10.1 @@ -9,8 +9,8 @@ For applications that require data compression, the functions in this module allow compression and decompression, using the zlib library. The zlib library has its own home page at -\url{http://www.gzip.org/zlib/}. Version 1.1.3 is the -most recent version as of September 2000; use a later version if one +\url{http://www.gzip.org/zlib/}. Version 1.2.1 is the +most recent version as of October 2004; use a later version if one is available. There are known incompatibilities between the Python module and earlier versions of the zlib library. From akuchling at users.sourceforge.net Tue Oct 19 21:21:22 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:21:25 2004 Subject: [Python-checkins] python/dist/src/Lib/curses textpad.py,1.8,1.9 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/curses In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30494 Modified Files: textpad.py Log Message: Make magic coordinates more readable Index: textpad.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/curses/textpad.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- textpad.py 29 Sep 2002 00:25:51 -0000 1.8 +++ textpad.py 19 Oct 2004 19:21:20 -0000 1.9 @@ -3,7 +3,9 @@ import curses, ascii def rectangle(win, uly, ulx, lry, lrx): - "Draw a rectangle." + """Draw a rectangle with corners at the provided upper-left + and lower-right coordinates. + """ win.vline(uly+1, ulx, curses.ACS_VLINE, lry - uly - 1) win.hline(uly, ulx+1, curses.ACS_HLINE, lrx - ulx - 1) win.hline(lry, ulx+1, curses.ACS_HLINE, lrx - ulx - 1) @@ -157,8 +159,10 @@ if __name__ == '__main__': def test_editbox(stdscr): - win = curses.newwin(4, 9, 15, 20) - rectangle(stdscr, 14, 19, 19, 29) + ncols, nlines = 9, 4 + uly, ulx = 15, 20 + win = curses.newwin(nlines, ncols, uly, ulx) + rectangle(stdscr, uly-1, ulx-1, uly + nlines, ulx + ncols) stdscr.refresh() return Textbox(win).edit() From akuchling at users.sourceforge.net Tue Oct 19 21:29:43 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:29:46 2004 Subject: [Python-checkins] python/dist/src/Lib/curses textpad.py,1.9,1.10 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/curses In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32173 Modified Files: textpad.py Log Message: [Bug #1048816] Fix bug when you do Ctrl-K at the start of a line; fix from Stefan Heimann Index: textpad.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/curses/textpad.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- textpad.py 19 Oct 2004 19:21:20 -0000 1.9 +++ textpad.py 19 Oct 2004 19:29:40 -0000 1.10 @@ -111,6 +111,8 @@ if x == 0 and self._end_of_line(y) == 0: self.win.deleteln() else: + # first undo the effect of self._end_of_line + self.win.move(y, x) self.win.clrtoeol() elif ch == ascii.FF: # ^l self.win.refresh() From akuchling at users.sourceforge.net Tue Oct 19 21:34:10 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:34:13 2004 Subject: [Python-checkins] python/dist/src/Lib/curses textpad.py, 1.8, 1.8.14.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/curses In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv790 Modified Files: Tag: release23-maint textpad.py Log Message: [Bug #1048816] Fix bug when you do Ctrl-K at the start of a line; fix from Stefan Heimann Index: textpad.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/curses/textpad.py,v retrieving revision 1.8 retrieving revision 1.8.14.1 diff -u -d -r1.8 -r1.8.14.1 --- textpad.py 29 Sep 2002 00:25:51 -0000 1.8 +++ textpad.py 19 Oct 2004 19:34:07 -0000 1.8.14.1 @@ -109,6 +109,8 @@ if x == 0 and self._end_of_line(y) == 0: self.win.deleteln() else: + # first undo the effect of self._end_of_line + self.win.move(y, x) self.win.clrtoeol() elif ch == ascii.FF: # ^l self.win.refresh() From akuchling at users.sourceforge.net Tue Oct 19 21:36:12 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:36:17 2004 Subject: [Python-checkins] python/dist/src/Lib/curses textpad.py,1.10,1.11 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/curses In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1381 Modified Files: textpad.py Log Message: Display helpful message; print repr() of return value so the whitespace is clearer Index: textpad.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/curses/textpad.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- textpad.py 19 Oct 2004 19:29:40 -0000 1.10 +++ textpad.py 19 Oct 2004 19:36:09 -0000 1.11 @@ -163,10 +163,11 @@ def test_editbox(stdscr): ncols, nlines = 9, 4 uly, ulx = 15, 20 + stdscr.addstr(uly-2, ulx, "Use Ctrl-G to end editing.") win = curses.newwin(nlines, ncols, uly, ulx) rectangle(stdscr, uly-1, ulx-1, uly + nlines, ulx + ncols) stdscr.refresh() return Textbox(win).edit() str = curses.wrapper(test_editbox) - print str + print 'Contents of text box:', repr(str) From akuchling at users.sourceforge.net Tue Oct 19 21:39:05 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:39:07 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libcurses.tex,1.47,1.48 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2066 Modified Files: libcurses.tex Log Message: Typo fixes, and a minor edit to clarify a sentence Index: libcurses.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcurses.tex,v retrieving revision 1.47 retrieving revision 1.48 diff -u -d -r1.47 -r1.48 --- libcurses.tex 8 Oct 2004 18:48:43 -0000 1.47 +++ libcurses.tex 19 Oct 2004 19:39:02 -0000 1.48 @@ -1275,7 +1275,7 @@ Draw a rectangle. The first argument must be a window object; the remaining arguments are coordinates relative to that window. The second and third arguments are the y and x coordinates of the upper -left hand corner of the rectangle To be drawn; the fourth and fifth +left hand corner of the rectangle to be drawn; the fourth and fifth arguments are the y and x coordinates of the lower right hand corner. The rectangle will be drawn using VT100/IBM PC forms characters on terminals that make this possible (including xterm and most other @@ -1292,7 +1292,7 @@ Return a textbox widget object. The \var{win} argument should be a curses \class{WindowObject} in which the textbox is to be contained. The edit cursor of the textbox is initially located at the upper left -hand corner of the containin window, with coordinates \code{(0, 0)}. +hand corner of the containing window, with coordinates \code{(0, 0)}. The instance's \member{stripspaces} flag is initially on. \end{classdesc} @@ -1358,7 +1358,7 @@ the window. When it is on, trailing blanks on each line are ignored; any cursor motion that would land the cursor on a trailing blank goes to the end of that line instead, and trailing blanks are stripped when -the window contents is gathered. +the window contents are gathered. \end{memberdesc} @@ -1375,7 +1375,7 @@ another function which should be the rest of your curses-using application. If the application raises an exception, \function{wrapper()} will restore the terminal to a sane state before -passing it further up the stack and generating a traceback. +re-raising the exception and generating a traceback. \begin{funcdesc}{wrapper}{func, \moreargs} Wrapper function that initializes curses and calls another function, From akuchling at users.sourceforge.net Tue Oct 19 21:41:01 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:41:03 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libcurses.tex, 1.42.8.3, 1.42.8.4 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2415 Modified Files: Tag: release23-maint libcurses.tex Log Message: Typo fixes, and a minor edit to clarify a sentence Index: libcurses.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcurses.tex,v retrieving revision 1.42.8.3 retrieving revision 1.42.8.4 diff -u -d -r1.42.8.3 -r1.42.8.4 --- libcurses.tex 8 Oct 2004 18:56:40 -0000 1.42.8.3 +++ libcurses.tex 19 Oct 2004 19:40:58 -0000 1.42.8.4 @@ -1266,7 +1266,7 @@ Draw a rectangle. The first argument must be a window object; the remaining arguments are coordinates relative to that window. The second and third arguments are the y and x coordinates of the upper -left hand corner of the rectangle To be drawn; the fourth and fifth +left hand corner of the rectangle to be drawn; the fourth and fifth arguments are the y and x coordinates of the lower right hand corner. The rectangle will be drawn using VT100/IBM PC forms characters on terminals that make this possible (including xterm and most other @@ -1283,7 +1283,7 @@ Return a textbox widget object. The \var{win} argument should be a curses \class{WindowObject} in which the textbox is to be contained. The edit cursor of the textbox is initially located at the upper left -hand corner of the containin window, with coordinates \code{(0, 0)}. +hand corner of the containing window, with coordinates \code{(0, 0)}. The instance's \member{stripspaces} flag is initially on. \end{classdesc} @@ -1349,7 +1349,7 @@ the window. When it is on, trailing blanks on each line are ignored; any cursor motion that would land the cursor on a trailing blank goes to the end of that line instead, and trailing blanks are stripped when -the window contents is gathered. +the window contents are gathered. \end{memberdesc} @@ -1366,7 +1366,7 @@ another function which should be the rest of your curses-using application. If the application raises an exception, \function{wrapper()} will restore the terminal to a sane state before -passing it further up the stack and generating a traceback. +re-raising the exception and generating a traceback. \begin{funcdesc}{wrapper}{func, \moreargs} Wrapper function that initializes curses and calls another function, From akuchling at users.sourceforge.net Tue Oct 19 21:50:26 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:50:30 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libzlib.tex,1.29,1.30 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4422 Modified Files: libzlib.tex Log Message: Remove the current version of zlib (we'll just have to keep updating it); rewrite following sentence to make sense without the previous one Index: libzlib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libzlib.tex,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- libzlib.tex 19 Oct 2004 18:52:49 -0000 1.29 +++ libzlib.tex 19 Oct 2004 19:50:23 -0000 1.30 @@ -8,11 +8,10 @@ For applications that require data compression, the functions in this module allow compression and decompression, using the zlib library. -The zlib library has its own home page at -\url{http://www.gzip.org/zlib/}. Version 1.2.1 is the -most recent version as of October 2004; use a later version if one -is available. There are known incompatibilities between the Python -module and earlier versions of the zlib library. +The zlib library has its own home page at \url{http://www.gzip.org/zlib/}. +There are known incompatibilities between the Python module and +versions of the zlib library earlier than 1.1.3; 1.1.3 has a security +vulnerability, so we recommend using 1.1.4 or later. The available exception and functions in this module are: From akuchling at users.sourceforge.net Tue Oct 19 21:54:53 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:54:56 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1166,1.1167 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5340 Modified Files: NEWS Log Message: Add item Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1166 retrieving revision 1.1167 diff -u -d -r1.1166 -r1.1167 --- NEWS 18 Oct 2004 01:37:57 -0000 1.1166 +++ NEWS 19 Oct 2004 19:54:41 -0000 1.1167 @@ -25,6 +25,8 @@ - Bug #1045381: time.strptime() can now infer the date using %U or %W (week of the year) when the day of the week and year are also specified. +- Bug #1048816: fix bug in Ctrl-K at start of line in curses.textpad.Textbox + Build ----- From akuchling at users.sourceforge.net Tue Oct 19 21:55:40 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:55:43 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.831.4.154, 1.831.4.155 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5546 Modified Files: Tag: release23-maint NEWS Log Message: Add item Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.831.4.154 retrieving revision 1.831.4.155 diff -u -d -r1.831.4.154 -r1.831.4.155 --- NEWS 18 Oct 2004 01:56:17 -0000 1.831.4.154 +++ NEWS 19 Oct 2004 19:55:35 -0000 1.831.4.155 @@ -120,6 +120,8 @@ - Bug #902501: fix unicode value of CYRILLIC CAPITAL LETTER UKRAINIAN IE in KOI8-U to unicode convertion table. +- Bug #1048816: fix bug in Ctrl-K at start of line in curses.textpad.Textbox + Tools/Demos ----------- From akuchling at users.sourceforge.net Tue Oct 19 21:56:58 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue Oct 19 21:57:00 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1167,1.1168 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5850 Modified Files: NEWS Log Message: Delete empty sections in beta1 news Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1167 retrieving revision 1.1168 diff -u -d -r1.1167 -r1.1168 --- NEWS 19 Oct 2004 19:54:41 -0000 1.1167 +++ NEWS 19 Oct 2004 19:56:55 -0000 1.1168 @@ -235,21 +235,11 @@ ``PyUnicode_DecodeUTF16Stateful`` have been added, which implement stateful decoding. -Documentation -------------- - -... - Tests ----- - test__locale ported to unittest -Windows -------- - -... - Mac --- @@ -257,11 +247,6 @@ interface for reading and writing plist files: ``readPlist(pathOrFile)`` and ``writePlist(rootObject, pathOrFile)`` -New platforms -------------- - -... - Tools/Demos ----------- From rhettinger at users.sourceforge.net Wed Oct 20 08:58:31 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed Oct 20 08:58:35 2004 Subject: [Python-checkins] python/dist/src/Lib decimal.py,1.27,1.28 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1503 Modified Files: decimal.py Log Message: SF bug #1048728: Bug fixes and cleanup for decimal.py (Contributed by Neal Norwitz. Reviewed by Facundo Bastista.) Index: decimal.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/decimal.py,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- decimal.py 12 Oct 2004 09:12:16 -0000 1.27 +++ decimal.py 20 Oct 2004 06:58:28 -0000 1.28 @@ -136,7 +136,6 @@ import threading import copy -import operator #Rounding ROUND_DOWN = 'ROUND_DOWN' @@ -1716,14 +1715,11 @@ val = Decimal(1) context = context._shallow_copy() context.prec = firstprec + elength + 1 - rounding = context.rounding if n < 0: #n is a long now, not Decimal instance n = -n mul = Decimal(1).__div__(mul, context=context) - shouldround = context._rounding_decision == ALWAYS_ROUND - spot = 1 while spot <= n: spot <<= 1 @@ -1742,7 +1738,7 @@ spot >>= 1 context.prec = firstprec - if shouldround: + if context._rounding_decision == ALWAYS_ROUND: return val._fix(context) return val @@ -1823,8 +1819,6 @@ if ans: return ans - out = 0 - if watchexp and (context.Emax < exp or context.Etiny() > exp): return context._raise_error(InvalidOperation, 'rescale(a, INF)') @@ -1844,7 +1838,6 @@ tmp._int = (0,) + tmp._int digits += 1 - prevexact = context.flags[Inexact] if digits < 0: tmp._exp = -digits + tmp._exp tmp._int = (0,1) @@ -1940,7 +1933,6 @@ half = Decimal('0.5') - count = 1 maxp = firstprec + 2 rounding = context._set_rounding(ROUND_HALF_EVEN) while 1: @@ -2043,8 +2035,9 @@ if context is None: context = getcontext() - context._rounding_decision == ALWAYS_ROUND - return ans._fix(context) + if context._rounding_decision == ALWAYS_ROUND: + return ans._fix(context) + return ans def min(self, other, context=None): """Returns the smaller value. @@ -2089,8 +2082,9 @@ if context is None: context = getcontext() - context._rounding_decision == ALWAYS_ROUND - return ans._fix(context) + if context._rounding_decision == ALWAYS_ROUND: + return ans._fix(context) + return ans def _isinteger(self): """Returns whether self is an integer""" From rhettinger at users.sourceforge.net Wed Oct 20 09:17:18 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed Oct 20 09:17:21 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1168,1.1169 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5737/Misc Modified Files: NEWS Log Message: SF patch #1038388: __main__ for whichdb.py (Contributed by Oleg Broytmann.) Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1168 retrieving revision 1.1169 diff -u -d -r1.1168 -r1.1169 --- NEWS 19 Oct 2004 19:56:55 -0000 1.1168 +++ NEWS 20 Oct 2004 07:17:15 -0000 1.1169 @@ -22,6 +22,8 @@ Library ------- +- The whichdb module can now be run from the command line. + - Bug #1045381: time.strptime() can now infer the date using %U or %W (week of the year) when the day of the week and year are also specified. From rhettinger at users.sourceforge.net Wed Oct 20 09:17:18 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed Oct 20 09:17:22 2004 Subject: [Python-checkins] python/dist/src/Lib whichdb.py,1.18,1.19 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5737/Lib Modified Files: whichdb.py Log Message: SF patch #1038388: __main__ for whichdb.py (Contributed by Oleg Broytmann.) Index: whichdb.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/whichdb.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- whichdb.py 20 Oct 2003 14:01:51 -0000 1.18 +++ whichdb.py 20 Oct 2004 07:17:16 -0000 1.19 @@ -1,3 +1,4 @@ +# !/usr/bin/env python """Guess which db package to use to open a db file.""" import os @@ -110,3 +111,7 @@ # Unknown return "" + +if __name__ == "__main__": + for filename in sys.argv[1:]: + print whichdb(filename) or "UNKNOWN", filename From rhettinger at users.sourceforge.net Wed Oct 20 10:21:22 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed Oct 20 10:21:25 2004 Subject: [Python-checkins] python/dist/src/Lib/xml/sax saxutils.py, 1.23, 1.24 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/xml/sax In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18768 Modified Files: saxutils.py Log Message: SF bug #902037: relative on-disk SYSTEM id handling is incorrect (Contributed by Bob Ippolito.) backport candidate. Index: saxutils.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/xml/sax/saxutils.py,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- saxutils.py 6 May 2004 02:22:43 -0000 1.23 +++ saxutils.py 20 Oct 2004 08:21:19 -0000 1.24 @@ -283,10 +283,11 @@ if source.getByteStream() is None: sysid = source.getSystemId() - if os.path.isfile(sysid): - basehead = os.path.split(os.path.normpath(base))[0] - source.setSystemId(os.path.join(basehead, sysid)) - f = open(sysid, "rb") + basehead = os.path.split(os.path.normpath(base))[0] + sysidfilename = os.path.join(basehead, sysid) + if os.path.isfile(sysidfilename): + source.setSystemId(sysidfilename) + f = open(sysidfilename, "rb") else: source.setSystemId(urlparse.urljoin(base, sysid)) f = urllib.urlopen(source.getSystemId()) From rhettinger at users.sourceforge.net Wed Oct 20 10:22:03 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed Oct 20 10:22:04 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1169,1.1170 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19135 Modified Files: NEWS Log Message: SF bug #902037: relative on-disk SYSTEM id handling is incorrect Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1169 retrieving revision 1.1170 diff -u -d -r1.1169 -r1.1170 --- NEWS 20 Oct 2004 07:17:15 -0000 1.1169 +++ NEWS 20 Oct 2004 08:21:57 -0000 1.1170 @@ -22,6 +22,9 @@ Library ------- +- Bug #902037: XML.sax.saxutils.prepare_input_source() now combines relative + paths with a base path before checking os.path.isfile(). + - The whichdb module can now be run from the command line. - Bug #1045381: time.strptime() can now infer the date using %U or %W (week of From vsajip at users.sourceforge.net Wed Oct 20 10:39:42 2004 From: vsajip at users.sourceforge.net (vsajip@users.sourceforge.net) Date: Wed Oct 20 10:39:45 2004 Subject: [Python-checkins] python/dist/src/Lib/logging __init__.py, 1.22, 1.23 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/logging In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23159 Modified Files: __init__.py Log Message: Changed handling of args in LogRecord.__init__. Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/logging/__init__.py,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- __init__.py 3 Oct 2004 19:10:53 -0000 1.22 +++ __init__.py 20 Oct 2004 08:39:40 -0000 1.23 @@ -36,8 +36,8 @@ __author__ = "Vinay Sajip " __status__ = "beta" -__version__ = "0.4.9.5" -__date__ = "02 October 2004" +__version__ = "0.4.9.6" +__date__ = "20 October 2004" #--------------------------------------------------------------------------- # Miscellaneous module data @@ -191,6 +191,21 @@ ct = time.time() self.name = name self.msg = msg + # + # The following statement allows passing of a dictionary as a sole + # argument, so that you can do something like + # logging.debug("a %(a)d b %(b)s", {'a':1, 'b':2}) + # Suggested by Stefan Behnel. + # Note that without the test for args[0], we get a problem because + # during formatting, we test to see if the arg is present using + # 'if self.args:'. If the event being logged is e.g. 'Value is %d' + # and if the passed arg fails 'if self.args:' then no formatting + # is done. For example, logger.warn('Value is %d', 0) would log + # 'Value is %d' instead of 'Value is 0'. + # For the use case of passing a dictionary, this should not be a + # problem. + if args and (len(args) == 1) and args[0]: + args = args[0] self.args = args self.levelname = getLevelName(level) self.levelno = level From fdrake at users.sourceforge.net Wed Oct 20 13:08:38 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Wed Oct 20 13:08:41 2004 Subject: [Python-checkins] python/dist/src/Lib/xml/sax saxutils.py, 1.24, 1.25 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/xml/sax In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24823 Modified Files: saxutils.py Log Message: when only using half of the return value of os.path.split(), use os.path.dirname() or os.path.basename() instead Index: saxutils.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/xml/sax/saxutils.py,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- saxutils.py 20 Oct 2004 08:21:19 -0000 1.24 +++ saxutils.py 20 Oct 2004 11:08:35 -0000 1.25 @@ -283,7 +283,7 @@ if source.getByteStream() is None: sysid = source.getSystemId() - basehead = os.path.split(os.path.normpath(base))[0] + basehead = os.path.dirname(os.path.normpath(base)) sysidfilename = os.path.join(basehead, sysid) if os.path.isfile(sysidfilename): source.setSystemId(sysidfilename) From akuchling at users.sourceforge.net Wed Oct 20 13:47:03 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed Oct 20 13:47:07 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_tarfile.py, 1.14, 1.15 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2365/Lib/test Modified Files: test_tarfile.py Log Message: Add test case for bug #1017553 Index: test_tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_tarfile.py,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- test_tarfile.py 22 Aug 2004 21:28:33 -0000 1.14 +++ test_tarfile.py 20 Oct 2004 11:47:01 -0000 1.15 @@ -327,6 +327,14 @@ class WriteStreamTestGzip(WriteStreamTest): comp = "gz" +# Filemode test cases + +class FileModeTest(unittest.TestCase): + def test_modes(self): + self.assertEqual(tarfile.filemode(0755), '-rwxr-xr-x') + self.assertEqual(tarfile.filemode(07111), '---s--s--t') + + if bz2: # Bzip2 TestCases class ReadTestBzip2(ReadTestGzip): @@ -354,6 +362,7 @@ bz2.BZ2File(tarname("bz2"), "wb").write(file(tarname(), "rb").read()) tests = [ + FileModeTest, ReadTest, ReadStreamTest, WriteTest, From akuchling at users.sourceforge.net Wed Oct 20 13:48:45 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed Oct 20 13:48:48 2004 Subject: [Python-checkins] python/dist/src/Lib tarfile.py,1.20,1.21 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2800 Modified Files: tarfile.py Log Message: [Patch #1043972, for bug #1017553] filemode() returns an incorrect value for the mode 07111 Index: tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/tarfile.py,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- tarfile.py 18 Sep 2004 09:08:50 -0000 1.20 +++ tarfile.py 20 Oct 2004 11:48:42 -0000 1.21 @@ -174,39 +174,46 @@ return filemode_table = ( - (S_IFLNK, "l", - S_IFREG, "-", - S_IFBLK, "b", - S_IFDIR, "d", - S_IFCHR, "c", - S_IFIFO, "p"), - (TUREAD, "r"), - (TUWRITE, "w"), - (TUEXEC, "x", TSUID, "S", TUEXEC|TSUID, "s"), - (TGREAD, "r"), - (TGWRITE, "w"), - (TGEXEC, "x", TSGID, "S", TGEXEC|TSGID, "s"), - (TOREAD, "r"), - (TOWRITE, "w"), - (TOEXEC, "x", TSVTX, "T", TOEXEC|TSVTX, "t")) + ((S_IFLNK, "l"), + (S_IFREG, "-"), + (S_IFBLK, "b"), + (S_IFDIR, "d"), + (S_IFCHR, "c"), + (S_IFIFO, "p")), + + ((TUREAD, "r"),), + ((TUWRITE, "w"),), + ((TUEXEC|TSUID, "s"), + (TSUID, "S"), + (TUEXEC, "x")), + + ((TGREAD, "r"),), + ((TGWRITE, "w"),), + ((TGEXEC|TSGID, "s"), + (TSGID, "S"), + (TGEXEC, "x")), + + ((TOREAD, "r"),), + ((TOWRITE, "w"),), + ((TOEXEC|TSVTX, "t"), + (TSVTX, "T"), + (TOEXEC, "x")) +) def filemode(mode): """Convert a file's mode to a string of the form -rwxrwxrwx. Used by TarFile.list() """ - s = "" - for t in filemode_table: - while True: - if mode & t[0] == t[0]: - s += t[1] - elif len(t) > 2: - t = t[2:] - continue - else: - s += "-" - break - return s + perm = [] + for table in filemode_table: + for bit, char in table: + if mode & bit == bit: + perm.append(char) + break + else: + perm.append("-") + return "".join(perm) if os.sep != "/": normpath = lambda path: os.path.normpath(path).replace(os.sep, "/") From akuchling at users.sourceforge.net Wed Oct 20 13:49:31 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed Oct 20 13:49:34 2004 Subject: [Python-checkins] python/dist/src/Lib tarfile.py,1.8.12.4,1.8.12.5 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3031 Modified Files: Tag: release23-maint tarfile.py Log Message: [Patch #1043972, for bug #1017553] filemode() returns an incorrect value for the mode 07111 Index: tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/tarfile.py,v retrieving revision 1.8.12.4 retrieving revision 1.8.12.5 diff -u -d -r1.8.12.4 -r1.8.12.5 --- tarfile.py 25 Aug 2004 10:53:30 -0000 1.8.12.4 +++ tarfile.py 20 Oct 2004 11:49:28 -0000 1.8.12.5 @@ -174,39 +174,46 @@ return filemode_table = ( - (S_IFLNK, "l", - S_IFREG, "-", - S_IFBLK, "b", - S_IFDIR, "d", - S_IFCHR, "c", - S_IFIFO, "p"), - (TUREAD, "r"), - (TUWRITE, "w"), - (TUEXEC, "x", TSUID, "S", TUEXEC|TSUID, "s"), - (TGREAD, "r"), - (TGWRITE, "w"), - (TGEXEC, "x", TSGID, "S", TGEXEC|TSGID, "s"), - (TOREAD, "r"), - (TOWRITE, "w"), - (TOEXEC, "x", TSVTX, "T", TOEXEC|TSVTX, "t")) + ((S_IFLNK, "l"), + (S_IFREG, "-"), + (S_IFBLK, "b"), + (S_IFDIR, "d"), + (S_IFCHR, "c"), + (S_IFIFO, "p")), + + ((TUREAD, "r"),), + ((TUWRITE, "w"),), + ((TUEXEC|TSUID, "s"), + (TSUID, "S"), + (TUEXEC, "x")), + + ((TGREAD, "r"),), + ((TGWRITE, "w"),), + ((TGEXEC|TSGID, "s"), + (TSGID, "S"), + (TGEXEC, "x")), + + ((TOREAD, "r"),), + ((TOWRITE, "w"),), + ((TOEXEC|TSVTX, "t"), + (TSVTX, "T"), + (TOEXEC, "x")) +) def filemode(mode): """Convert a file's mode to a string of the form -rwxrwxrwx. Used by TarFile.list() """ - s = "" - for t in filemode_table: - while True: - if mode & t[0] == t[0]: - s += t[1] - elif len(t) > 2: - t = t[2:] - continue - else: - s += "-" - break - return s + perm = [] + for table in filemode_table: + for bit, char in table: + if mode & bit == bit: + perm.append(char) + break + else: + perm.append("-") + return "".join(perm) if os.sep != "/": normpath = lambda path: os.path.normpath(path).replace(os.sep, "/") From akuchling at users.sourceforge.net Wed Oct 20 13:55:58 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed Oct 20 13:56:01 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.831.4.155, 1.831.4.156 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4490 Modified Files: Tag: release23-maint NEWS Log Message: Add item Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.831.4.155 retrieving revision 1.831.4.156 diff -u -d -r1.831.4.155 -r1.831.4.156 --- NEWS 19 Oct 2004 19:55:35 -0000 1.831.4.155 +++ NEWS 20 Oct 2004 11:55:54 -0000 1.831.4.156 @@ -122,6 +122,8 @@ - Bug #1048816: fix bug in Ctrl-K at start of line in curses.textpad.Textbox +- Bug #1017553: fix bug in tarfile.filemode() + Tools/Demos ----------- From akuchling at users.sourceforge.net Wed Oct 20 13:56:18 2004 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed Oct 20 13:56:20 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1170,1.1171 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4611/Misc Modified Files: NEWS Log Message: Add item Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1170 retrieving revision 1.1171 diff -u -d -r1.1170 -r1.1171 --- NEWS 20 Oct 2004 08:21:57 -0000 1.1170 +++ NEWS 20 Oct 2004 11:56:15 -0000 1.1171 @@ -32,6 +32,8 @@ - Bug #1048816: fix bug in Ctrl-K at start of line in curses.textpad.Textbox +- Bug #1017553: fix bug in tarfile.filemode() + Build ----- From astrand at users.sourceforge.net Thu Oct 21 21:28:36 2004 From: astrand at users.sourceforge.net (astrand@users.sourceforge.net) Date: Thu Oct 21 21:28:40 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_subprocess.py, 1.12, 1.13 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14067 Modified Files: test_subprocess.py Log Message: Removed test_close_fds, because it's too unreliable. We simply cannot know that the newly-started Python process only has 3 filedescriptors open. Fixes bug 1048808. Index: test_subprocess.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_subprocess.py,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- test_subprocess.py 14 Oct 2004 04:16:54 -0000 1.12 +++ test_subprocess.py 21 Oct 2004 19:28:34 -0000 1.13 @@ -421,16 +421,6 @@ preexec_fn=lambda: os.putenv("FRUIT", "apple")) self.assertEqual(p.stdout.read(), "apple") - def test_close_fds(self): - # Make sure we have some fds open - os.pipe() - p = subprocess.Popen([sys.executable, "-c", - 'import sys,os;' \ - 'sys.stdout.write(str(os.dup(0)))'], - stdout=subprocess.PIPE, close_fds=1) - # When all fds are closed, the next free fd should be 3. - self.assertEqual(p.stdout.read(), "3") - def test_args_string(self): # args is a string f, fname = self.mkstemp() From vsajip at users.sourceforge.net Thu Oct 21 23:24:30 2004 From: vsajip at users.sourceforge.net (vsajip@users.sourceforge.net) Date: Thu Oct 21 23:24:33 2004 Subject: [Python-checkins] python/dist/src/Lib/logging __init__.py, 1.23, 1.24 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/logging In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4738 Modified Files: __init__.py Log Message: Fixed bug in handling of args in LogRecord.__init__. Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/logging/__init__.py,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- __init__.py 20 Oct 2004 08:39:40 -0000 1.23 +++ __init__.py 21 Oct 2004 21:24:27 -0000 1.24 @@ -204,7 +204,7 @@ # 'Value is %d' instead of 'Value is 0'. # For the use case of passing a dictionary, this should not be a # problem. - if args and (len(args) == 1) and args[0]: + if args and (len(args) == 1) and args[0] and (type(args[0]) == types.DictType): args = args[0] self.args = args self.levelname = getLevelName(level) From jafo at users.sourceforge.net Fri Oct 22 01:35:47 2004 From: jafo at users.sourceforge.net (jafo@users.sourceforge.net) Date: Fri Oct 22 01:35:51 2004 Subject: [Python-checkins] python/dist/src/Misc/RPM python-2.4.spec,1.4,1.5 Message-ID: Update of /cvsroot/python/python/dist/src/Misc/RPM In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5780 Modified Files: python-2.4.spec Log Message: Latest version for beta 1. Index: python-2.4.spec =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/RPM/python-2.4.spec,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- python-2.4.spec 15 Oct 2004 08:07:11 -0000 1.4 +++ python-2.4.spec 21 Oct 2004 23:35:45 -0000 1.5 @@ -25,6 +25,9 @@ %define config_ipv6 yes %define config_ipv6 no +# Location of the HTML directory. +%define config_htmldir /var/www/html/python + ################################# # End of user-modifiable configs ################################# @@ -40,6 +43,7 @@ %define pymalloc %(if [ "%{config_pymalloc}" = yes ]; then echo --with-pymalloc; else echo --without-pymalloc; fi) %define binsuffix %(if [ "%{config_binsuffix}" = none ]; then echo ; else echo "%{config_binsuffix}"; fi) %define include_tkinter %(if [ \\( "%{config_tkinter}" = auto -a -f /usr/bin/wish \\) -o "%{config_tkinter}" = yes ]; then echo 1; else echo 0; fi) +%define libdirname %(( uname -m | egrep -q '_64$' && [ -d /usr/lib64 ] && echo lib64 ) || echo lib) # detect if documentation is available %define include_docs %(if [ -f "%{_sourcedir}/html-%{version}.tar.bz2" ]; then echo 1; else echo 0; fi) @@ -50,7 +54,7 @@ Release: %{release} Copyright: Modified CNRI Open Source License Group: Development/Languages -Source: Python-%{version}.tgz +Source: Python-%{version}.tar.bz2 %if %{include_docs} Source1: html-%{version}.tar.bz2 %endif @@ -127,6 +131,15 @@ %endif %changelog +* Tue Oct 19 2004 Sean Reifschneider [2.4b1-1pydotorg] +- Updating to 2.4. + +* Thu Jul 22 2004 Sean Reifschneider [2.3.4-3pydotorg] +- Paul Tiemann fixes for %{prefix}. +- Adding permission changes for directory as suggested by reimeika.ca +- Adding code to detect when it should be using lib64. +- Adding a define for the location of /var/www/html for docs. + * Thu May 27 2004 Sean Reifschneider [2.3.4-2pydotorg] - Including changes from Ian Holsman to build under Red Hat 7.3. - Fixing some problems with the /usr/local path change. @@ -213,10 +226,10 @@ %install # set the install path echo '[install_scripts]' >setup.cfg -echo 'install_dir='"${RPM_BUILD_ROOT}/usr/bin" >>setup.cfg +echo 'install_dir='"${RPM_BUILD_ROOT}%{__prefix}/bin" >>setup.cfg [ -d "$RPM_BUILD_ROOT" -a "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT%{__prefix}/lib/python%{libvers}/lib-dynload +mkdir -p $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload make prefix=$RPM_BUILD_ROOT%{__prefix} install # REPLACE PATH IN PYDOC @@ -225,7 +238,7 @@ ( cd $RPM_BUILD_ROOT%{__prefix}/bin mv pydoc pydoc.old - sed 's|#!.*|#!/usr/bin/env python'%{binsuffix}'|' \ + sed 's|#!.*|#!%{__prefix}/bin/env python'%{binsuffix}'|' \ pydoc.old >pydoc chmod 755 pydoc rm -f pydoc.old @@ -244,14 +257,14 @@ ######## # Tools -echo '#!/bin/bash' >${RPM_BUILD_ROOT}%{_bindir}/idle%{binsuffix} -echo 'exec %{__prefix}/bin/python%{binsuffix} /usr/lib/python%{libvers}/idlelib/idle.py' >>$RPM_BUILD_ROOT%{_bindir}/idle%{binsuffix} -chmod 755 $RPM_BUILD_ROOT%{_bindir}/idle%{binsuffix} -cp -a Tools $RPM_BUILD_ROOT%{__prefix}/lib/python%{libvers} +echo '#!/bin/bash' >${RPM_BUILD_ROOT}%{__prefix}/bin/idle%{binsuffix} +echo 'exec %{__prefix}/bin/python%{binsuffix} %{__prefix}/%{libdirname}/python%{libvers}/idlelib/idle.py' >>$RPM_BUILD_ROOT%{__prefix}/bin/idle%{binsuffix} +chmod 755 $RPM_BUILD_ROOT%{__prefix}/bin/idle%{binsuffix} +cp -a Tools $RPM_BUILD_ROOT%{__prefix}/%{libdirname}/python%{libvers} # MAKE FILE LISTS rm -f mainpkg.files -find "$RPM_BUILD_ROOT""%{__prefix}"/lib/python%{libvers}/lib-dynload -type f | +find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/lib-dynload -type f | sed "s|^${RPM_BUILD_ROOT}|/|" | grep -v -e '_tkinter.so$' >mainpkg.files find "$RPM_BUILD_ROOT""%{__prefix}"/bin -type f | @@ -259,17 +272,17 @@ grep -v -e '/bin/idle%{binsuffix}$' >>mainpkg.files rm -f tools.files -find "$RPM_BUILD_ROOT""%{__prefix}"/lib/python%{libvers}/idlelib \ - "$RPM_BUILD_ROOT""%{__prefix}"/lib/python%{libvers}/Tools -type f | +find "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/idlelib \ + "$RPM_BUILD_ROOT""%{__prefix}"/%{libdirname}/python%{libvers}/Tools -type f | sed "s|^${RPM_BUILD_ROOT}|/|" >tools.files echo "%{__prefix}"/bin/idle%{binsuffix} >>tools.files ###### # Docs %if %{include_docs} -mkdir -p "$RPM_BUILD_ROOT"/var/www/html/python +mkdir -p "$RPM_BUILD_ROOT"%{config_htmldir} ( - cd "$RPM_BUILD_ROOT"/var/www/html/python + cd "$RPM_BUILD_ROOT"%{config_htmldir} bunzip2 < %{SOURCE1} | tar x ) %endif @@ -279,7 +292,7 @@ xargs -0 grep -l /usr/local/bin/python | while read file do FIXFILE="$file" - sed 's|^#!.*python|#!/usr/bin/env python'"%{binsuffix}"'|' \ + sed 's|^#!.*python|#!%{__prefix}/bin/env python'"%{binsuffix}"'|' \ "$FIXFILE" >/tmp/fix-python-path.$$ cat /tmp/fix-python-path.$$ >"$FIXFILE" rm -f /tmp/fix-python-path.$$ @@ -321,30 +334,30 @@ %doc LICENSE Misc/ACKS Misc/HISTORY Misc/NEWS %{__prefix}/man/man1/python%{binsuffix}.1* -%dir %{__prefix}/include/python%{libvers} -%dir %{__prefix}/lib/python%{libvers}/ -%{__prefix}/lib/python%{libvers}/*.txt -%{__prefix}/lib/python%{libvers}/*.py* -%{__prefix}/lib/python%{libvers}/pdb.doc -%{__prefix}/lib/python%{libvers}/profile.doc -%{__prefix}/lib/python%{libvers}/curses -%{__prefix}/lib/python%{libvers}/distutils -%{__prefix}/lib/python%{libvers}/encodings -%{__prefix}/lib/python%{libvers}/plat-linux2 -%{__prefix}/lib/python%{libvers}/site-packages -%{__prefix}/lib/python%{libvers}/test -%{__prefix}/lib/python%{libvers}/xml -%{__prefix}/lib/python%{libvers}/email -%{__prefix}/lib/python%{libvers}/compiler -%{__prefix}/lib/python%{libvers}/bsddb -%{__prefix}/lib/python%{libvers}/hotshot -%{__prefix}/lib/python%{libvers}/logging -%{__prefix}/lib/python%{libvers}/lib-old +%attr(755,root,root) %dir %{__prefix}/include/python%{libvers} +%attr(755,root,root) %dir %{__prefix}/%{libdirname}/python%{libvers}/ +%{__prefix}/%{libdirname}/python%{libvers}/*.txt +%{__prefix}/%{libdirname}/python%{libvers}/*.py* +%{__prefix}/%{libdirname}/python%{libvers}/pdb.doc +%{__prefix}/%{libdirname}/python%{libvers}/profile.doc +%{__prefix}/%{libdirname}/python%{libvers}/curses +%{__prefix}/%{libdirname}/python%{libvers}/distutils +%{__prefix}/%{libdirname}/python%{libvers}/encodings +%{__prefix}/%{libdirname}/python%{libvers}/plat-linux2 +%{__prefix}/%{libdirname}/python%{libvers}/site-packages +%{__prefix}/%{libdirname}/python%{libvers}/test +%{__prefix}/%{libdirname}/python%{libvers}/xml +%{__prefix}/%{libdirname}/python%{libvers}/email +%{__prefix}/%{libdirname}/python%{libvers}/compiler +%{__prefix}/%{libdirname}/python%{libvers}/bsddb +%{__prefix}/%{libdirname}/python%{libvers}/hotshot +%{__prefix}/%{libdirname}/python%{libvers}/logging +%{__prefix}/%{libdirname}/python%{libvers}/lib-old %files devel %defattr(-,root,root) %{__prefix}/include/python%{libvers}/*.h -%{__prefix}/lib/python%{libvers}/config +%{__prefix}/%{libdirname}/python%{libvers}/config %files -f tools.files tools %defattr(-,root,root) @@ -352,12 +365,12 @@ %if %{include_tkinter} %files tkinter %defattr(-,root,root) -%{__prefix}/lib/python%{libvers}/lib-tk -%{__prefix}/lib/python%{libvers}/lib-dynload/_tkinter.so* +%{__prefix}/%{libdirname}/python%{libvers}/lib-tk +%{__prefix}/%{libdirname}/python%{libvers}/lib-dynload/_tkinter.so* %endif %if %{include_docs} %files docs %defattr(-,root,root) -/var/www/html/python/* +%{config_htmldir}/* %endif From bcannon at users.sourceforge.net Fri Oct 22 08:22:57 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Fri Oct 22 08:23:00 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1171, 1.1172 ACKS, 1.286, 1.287 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19923/Misc Modified Files: NEWS ACKS Log Message: Fix minor reST error in Misc/NEWS. Applies patch #1051866. Thanks Felix Wiemann. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1171 retrieving revision 1.1172 diff -u -d -r1.1171 -r1.1172 --- NEWS 20 Oct 2004 11:56:15 -0000 1.1171 +++ NEWS 22 Oct 2004 06:22:53 -0000 1.1172 @@ -134,6 +134,7 @@ Closes bug #1039270. - Updates for the email package: + + email.Utils.formatdate() grew a 'usegmt' argument for HTTP support. + All deprecated APIs that in email 2.x issued warnings have been removed: _encoder argument to the MIMEText constructor, Message.add_payload(), Index: ACKS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/ACKS,v retrieving revision 1.286 retrieving revision 1.287 diff -u -d -r1.286 -r1.287 --- ACKS 14 Oct 2004 10:02:04 -0000 1.286 +++ ACKS 22 Oct 2004 06:22:54 -0000 1.287 @@ -621,6 +621,7 @@ Rickard Westman Mats Wichmann Truida Wiedijk +Felix Wiemann Gerry Wiener Bryce "Zooko" Wilcox-O'Hearn Gerald S. Williams From theller at users.sourceforge.net Fri Oct 22 12:29:59 2004 From: theller at users.sourceforge.net (theller@users.sourceforge.net) Date: Fri Oct 22 12:30:02 2004 Subject: [Python-checkins] python/dist/src/Lib warnings.py,1.21,1.21.6.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3368 Modified Files: Tag: release23-maint warnings.py Log Message: Backport from trunk: SF bug 917108: warnings.py does not define _test(). Removed the entire __name__ == '__main__' block. Index: warnings.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/warnings.py,v retrieving revision 1.21 retrieving revision 1.21.6.1 diff -u -d -r1.21 -r1.21.6.1 --- warnings.py 11 Jul 2003 15:37:56 -0000 1.21 +++ warnings.py 22 Oct 2004 10:29:56 -0000 1.21.6.1 @@ -249,11 +249,6 @@ return cat # Module initialization -if __name__ == "__main__": - import __main__ - sys.modules['warnings'] = __main__ - _test() -else: - _processoptions(sys.warnoptions) - simplefilter("ignore", category=OverflowWarning, append=1) - simplefilter("ignore", category=PendingDeprecationWarning, append=1) +_processoptions(sys.warnoptions) +simplefilter("ignore", category=OverflowWarning, append=1) +simplefilter("ignore", category=PendingDeprecationWarning, append=1) From vsajip at users.sourceforge.net Fri Oct 22 23:43:18 2004 From: vsajip at users.sourceforge.net (vsajip@users.sourceforge.net) Date: Fri Oct 22 23:43:20 2004 Subject: [Python-checkins] python/dist/src/Doc/lib liblogging.tex,1.27,1.28 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23865 Modified Files: liblogging.tex Log Message: Added example of multiple destinations Index: liblogging.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liblogging.tex,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- liblogging.tex 3 Oct 2004 19:10:05 -0000 1.27 +++ liblogging.tex 22 Oct 2004 21:43:15 -0000 1.28 @@ -507,15 +507,79 @@ datefmt='%a, %d %b %Y %H:%M:%S', filename='/temp/myapp.log', filemode='w') -logging.error('Pack my box with %d dozen %s', 12, 'liquor jugs') +logging.error('Pack my box with %d dozen %s', 5, 'liquor jugs') \end{verbatim} which would result in \begin{verbatim} -Wed, 21 Jul 2004 15:35:16 ERROR Pack my box with 12 dozen liquor jugs +Wed, 21 Jul 2004 15:35:16 ERROR Pack my box with 5 dozen liquor jugs +\end{verbatim} + +\subsection{Logging to multiple destinations \label{multiple-destinations}} + +Let's say you want to log to console and file with different message formats +and in differing circumstances. Say you want to log messages with levels +of DEBUG and higher to file, and those messages at level INFO and higher to +the console. Let's also assume that the file should contain timestamps, but +the console messages should not. Here's how you can achieve this: + +\begin{verbatim} +import logging + +#set up logging to file - see previous section for more details +logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', + datefmt='%m-%d %H:%M', + filename='/temp/myapp.log', + filemode='w') +#define a Handler which writes INFO messages or higher to the sys.stderr +console = logging.StreamHandler() +console.setLevel(logging.INFO) +#set a format which is simpler for console use +formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') +#tell the handler to use this format +console.setFormatter(formatter) +#add the handler to the root logger +logging.getLogger('').addHandler(console) + +#Now, we can log to the root logger, or any other logger. First the root... +logging.info('Jackdaws love my big sphinx of quartz.') + +#Now, define a couple of other loggers which might represent areas in your +#application: + +logger1 = logging.getLogger('myapp.area1') +logger2 = logging.getLogger('myapp.area2') + +logger1.debug('Quick zephyrs blow, vexing daft Jim.') +logger1.info('How quickly daft jumping zebras vex.') +logger2.warning('Jail zesty vixen who grabbed pay from quack.') +logger2.error('The five boxing wizards jump quickly.') +\end{verbatim} + +When you run this, on the console you will see + +\begin{verbatim} +root : INFO Jackdaws love my big sphinx of quartz. +myapp.area1 : INFO How quickly daft jumping zebras vex. +myapp.area2 : WARNING Jail zesty vixen who grabbed pay from quack. +myapp.area2 : ERROR The five boxing wizards jump quickly. \end{verbatim} +and in the file you will see something like + +\begin{verbatim} +10-22 22:19 root INFO Jackdaws love my big sphinx of quartz. +10-22 22:19 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim. +10-22 22:19 myapp.area1 INFO How quickly daft jumping zebras vex. +10-22 22:19 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack. +10-22 22:19 myapp.area2 ERROR The five boxing wizards jump quickly. +\end{verbatim} + +As you can see, the DEBUG message only shows up in the file. The other +messages are sent to both destinations. + \subsection{Handler Objects} Handlers have the following attributes and methods. Note that From tim_one at users.sourceforge.net Sat Oct 23 05:43:56 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sat Oct 23 05:43:59 2004 Subject: [Python-checkins] python/dist/src LICENSE,1.30,1.31 Message-ID: Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11868 Modified Files: LICENSE Log Message: Move to version 2 of the PSF license, approved by the Board earlier today. Index: LICENSE =================================================================== RCS file: /cvsroot/python/python/dist/src/LICENSE,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- LICENSE 8 Jul 2004 05:57:59 -0000 1.30 +++ LICENSE 23 Oct 2004 03:43:53 -0000 1.31 @@ -69,40 +69,40 @@ B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON =============================================================== -PSF LICENSE AGREEMENT FOR PYTHON 2.4 ------------------------------------- +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using Python 2.4 software in source or binary form and its +otherwise using Python software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, -prepare derivative works, distribute, and otherwise use Python 2.4 +prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004 Python Software Foundation; All Rights Reserved" -are retained in Python 2.4 alone or in any derivative version prepared +are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on -or incorporates Python 2.4 or any part thereof, and wants to make +or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of -the changes made to Python 2.4. +the changes made to Python. -4. PSF is making Python 2.4 available to Licensee on an "AS IS" +4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 2.4 WILL NOT +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON -2.4 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS -A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.4, +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material @@ -114,7 +114,7 @@ trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. -8. By copying, installing or otherwise using Python 2.4, Licensee +8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. From tim_one at users.sourceforge.net Sat Oct 23 05:43:57 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sat Oct 23 05:44:00 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1172,1.1173 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11868/Misc Modified Files: NEWS Log Message: Move to version 2 of the PSF license, approved by the Board earlier today. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1172 retrieving revision 1.1173 diff -u -d -r1.1172 -r1.1173 --- NEWS 22 Oct 2004 06:22:53 -0000 1.1172 +++ NEWS 23 Oct 2004 03:43:54 -0000 1.1173 @@ -9,6 +9,26 @@ *Release date: XX-XXX-XXXX* +License +------- + +The Python Software Foundation changed the license under which Python +is released, to remove Python version numbers. There were no other +changes to the license. So, for example, wherever the license for +Python 2.3 said "Python 2.3", the new license says "Python". The +intent is to make it possible to refer to the PSF license in a more +durable way. For example, some people say they're confused by that +the Open Source Initiative's entry for the Python Software Foundation +License:: + + http://www.opensource.org/licenses/PythonSoftFoundation.php + +says "Python 2.1.1" all over it, wondering whether it applies only +to Python 2.1.1. + +The official name of the new license is the Python Software Foundation +License Version 2. + Core and builtins ----------------- @@ -83,7 +103,7 @@ Core and builtins ----------------- -- Patch #975056: Restartable signals were not correctly disabled on +- Patch #975056: Restartable signals were not correctly disabled on BSD systems. Consistently use PyOS_setsig() instead of signal(). - The internal portable implementation of thread-local storage (TLS), used @@ -119,7 +139,7 @@ ------- - Patch 1046644: distutils build_ext grew two new options - --swig for - specifying the swig executable to use, and --swig-opts to specify + specifying the swig executable to use, and --swig-opts to specify options to pass to swig. --swig-opts="-c++" is the new way to spell --swig-cpp. From tim_one at users.sourceforge.net Sat Oct 23 05:48:59 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sat Oct 23 05:49:01 2004 Subject: [Python-checkins] python/dist/src LICENSE,1.31,1.32 Message-ID: Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12761 Modified Files: LICENSE Log Message: Converted some stinking hard tabs. Left the fragrant hard tabs alone. Index: LICENSE =================================================================== RCS file: /cvsroot/python/python/dist/src/LICENSE,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- LICENSE 23 Oct 2004 03:43:53 -0000 1.31 +++ LICENSE 23 Oct 2004 03:48:57 -0000 1.32 @@ -26,7 +26,7 @@ the various releases. Release Derived Year Owner GPL- - from compatible? (1) + from compatible? (1) 0.9.0 thru 1.2 1991-1995 CWI yes 1.3 thru 1.5.2 1.2 1995-1999 CNRI yes From rhettinger at users.sourceforge.net Sun Oct 24 02:10:08 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun Oct 24 02:10:15 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1173,1.1174 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30133/Misc Modified Files: NEWS Log Message: SF bug #1048870: call arg of lambda not updating Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1173 retrieving revision 1.1174 diff -u -d -r1.1173 -r1.1174 --- NEWS 23 Oct 2004 03:43:54 -0000 1.1173 +++ NEWS 24 Oct 2004 00:10:03 -0000 1.1174 @@ -37,7 +37,10 @@ Extension Modules ----------------- -... +- Bug #1048870: the compiler now generates distinct code objects for + functions with identical bodies. This was producing confusing + traceback messages which pointed to the function where the code + object was first defined rather than the function being executed. Library ------- From rhettinger at users.sourceforge.net Sun Oct 24 02:10:09 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun Oct 24 02:10:17 2004 Subject: [Python-checkins] python/dist/src/Python compile.c,2.330,2.331 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30133/Python Modified Files: compile.c Log Message: SF bug #1048870: call arg of lambda not updating Index: compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.330 retrieving revision 2.331 diff -u -d -r2.330 -r2.331 --- compile.c 29 Sep 2004 23:54:08 -0000 2.330 +++ compile.c 24 Oct 2004 00:10:05 -0000 2.331 @@ -261,6 +261,8 @@ if (cmp) return (cmp<0)?-1:1; cmp = co->co_flags - cp->co_flags; if (cmp) return (cmp<0)?-1:1; + cmp = co->co_firstlineno - cp->co_firstlineno; + if (cmp) return (cmp<0)?-1:1; cmp = PyObject_Compare(co->co_code, cp->co_code); if (cmp) return cmp; cmp = PyObject_Compare(co->co_consts, cp->co_consts); From rhettinger at users.sourceforge.net Sun Oct 24 02:10:09 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun Oct 24 02:10:18 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_compile.py, 1.23, 1.24 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30133/Lib/test Modified Files: test_compile.py Log Message: SF bug #1048870: call arg of lambda not updating Index: test_compile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_compile.py,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- test_compile.py 31 Aug 2004 10:07:09 -0000 1.23 +++ test_compile.py 24 Oct 2004 00:10:06 -0000 1.24 @@ -252,6 +252,15 @@ for stmt in fail: self.assertRaises(SyntaxError, compile, stmt, 'tmp', 'exec') + def test_for_distinct_code_objects(self): + # SF bug 1048870 + def f(): + f1 = lambda x=1: x + f2 = lambda x=2: x + return f1, f2 + f1, f2 = f() + self.assertNotEqual(id(f1.func_code), id(f2.func_code)) + def test_main(): test_support.run_unittest(TestSpecifics) From rhettinger at users.sourceforge.net Sun Oct 24 02:32:27 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun Oct 24 02:32:29 2004 Subject: [Python-checkins] python/dist/src/Lib pdb.py, 1.71, 1.72 bdb.py, 1.45, 1.46 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3279/Lib Modified Files: pdb.py bdb.py Log Message: SF bug #1052503: pdb runcall should accept keyword arguments Index: pdb.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/pdb.py,v retrieving revision 1.71 retrieving revision 1.72 diff -u -d -r1.71 -r1.72 --- pdb.py 12 Oct 2004 21:51:32 -0000 1.71 +++ pdb.py 24 Oct 2004 00:32:24 -0000 1.72 @@ -993,8 +993,8 @@ # B/W compatibility run(statement, globals, locals) -def runcall(*args): - return Pdb().runcall(*args) +def runcall(*args, **kwds): + return Pdb().runcall(*args, **kwds) def set_trace(): Pdb().set_trace() Index: bdb.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/bdb.py,v retrieving revision 1.45 retrieving revision 1.46 diff -u -d -r1.45 -r1.46 --- bdb.py 30 Aug 2004 13:29:44 -0000 1.45 +++ bdb.py 24 Oct 2004 00:32:24 -0000 1.46 @@ -391,13 +391,13 @@ # This method is more useful to debug a single function call. - def runcall(self, func, *args): + def runcall(self, func, *args, **kwds): self.reset() sys.settrace(self.trace_dispatch) res = None try: try: - res = func(*args) + res = func(*args, **kwds) except BdbQuit: pass finally: From rhettinger at users.sourceforge.net Sun Oct 24 02:32:27 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun Oct 24 02:32:30 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1174,1.1175 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3279/Misc Modified Files: NEWS Log Message: SF bug #1052503: pdb runcall should accept keyword arguments Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1174 retrieving revision 1.1175 diff -u -d -r1.1174 -r1.1175 --- NEWS 24 Oct 2004 00:10:03 -0000 1.1174 +++ NEWS 24 Oct 2004 00:32:24 -0000 1.1175 @@ -45,6 +45,8 @@ Library ------- +- Bug #1052503 pdb.runcall() was not passing along keyword arguments. + - Bug #902037: XML.sax.saxutils.prepare_input_source() now combines relative paths with a base path before checking os.path.isfile(). From tim_one at users.sourceforge.net Mon Oct 25 01:45:44 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Mon Oct 25 01:45:47 2004 Subject: [Python-checkins] python/dist/src/Lib/idlelib FormatParagraph.py, 1.6, 1.7 NEWS.txt, 1.41, 1.42 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/idlelib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30465/Lib/idlelib Modified Files: FormatParagraph.py NEWS.txt Log Message: format_paragraph_event(): Patch 961387 introduced a bug here, causing the indentation of a comment block to be ignored when reformatting the block, leading to overly long reformatted lines (too wide by an amount equal to the indentation width). Looks like a typo in the original patch, a 1-character repair. Index: FormatParagraph.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/FormatParagraph.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- FormatParagraph.py 4 Jun 2004 06:31:08 -0000 1.6 +++ FormatParagraph.py 24 Oct 2004 23:45:41 -0000 1.7 @@ -47,7 +47,7 @@ lines = map(lambda st, l=len(comment_header): st[l:], lines) data = "\n".join(lines) # Reformat to maxformatwidth chars or a 20 char width, whichever is greater. - format_width = max(maxformatwidth, len(comment_header), 20) + format_width = max(maxformatwidth - len(comment_header), 20) newdata = reformat_paragraph(data, format_width) # re-split and re-insert the comment header. newdata = newdata.split("\n") Index: NEWS.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/NEWS.txt,v retrieving revision 1.41 retrieving revision 1.42 diff -u -d -r1.41 -r1.42 --- NEWS.txt 15 Oct 2004 08:07:21 -0000 1.41 +++ NEWS.txt 24 Oct 2004 23:45:42 -0000 1.42 @@ -1,3 +1,14 @@ +What's New in IDLE 1.1b2? +========================= + +*Release date: DD-MMM-2004* + +- When paragraph reformat width was made configurable, a bug was + introduced that caused reformatting of comment blocks to ignore how + far the block was indented, effectively adding the indentation width + to the reformat width. This has been repaired, and the reformat + width is again a bound on the total width of reformatted lines. + What's New in IDLE 1.1b1? ========================= @@ -52,7 +63,7 @@ - If nulls somehow got into the strings in recent-files.lst EditorWindow.update_recent_files_list() was failing. Python Bug 931336. -- If the normal background is changed via Configure/Highlighting, it will update +- If the normal background is changed via Configure/Highlighting, it will update immediately, thanks to the previously mentioned patch by Nigel Rowe. - Add a highlight theme for builtin keywords. Python Patch 805830 Nigel Rowe @@ -73,7 +84,7 @@ the port or connect to the subprocess. Clean up error handling during connection initiation phase. This is an update of Python Patch 778323. -- Print correct exception even if source file changed since shell was +- Print correct exception even if source file changed since shell was restarted. IDLEfork Patch 869012 Noam Raphael - Keybindings with the Shift modifier now work correctly. So do bindings which @@ -81,7 +92,7 @@ Python Bug 775353, IDLEfork Bugs 755647, 761557 - After an exception, run.py was not setting the exception vector. Noam - Raphael suggested correcting this so pdb's postmortem pm() would work. + Raphael suggested correcting this so pdb's postmortem pm() would work. IDLEfork Patch 844675 - IDLE now does not fail to save the file anymore if the Tk buffer is not a @@ -179,7 +190,7 @@ *Release date: 02-Jun-2003* - The current working directory of the execution environment (and shell - following completion of execution) is now that of the module being run. + following completion of execution) is now that of the module being run. - Added the delete-exitfunc option to config-main.def. (This option is not included in the Options dialog.) Setting this to True (the default) will @@ -247,7 +258,7 @@ - Improved I/O response by tweaking the wait parameter in various calls to signal.signal(). -- Implemented a threaded subprocess which allows interrupting a pass +- Implemented a threaded subprocess which allows interrupting a pass loop in user code using the 'interrupt' extension. User code runs in MainThread, while the RPCServer is handled by SockThread. This is necessary because Windows doesn't support signals. @@ -269,11 +280,11 @@ - Exit IDLE cleanly even when doing subprocess I/O -- Handle subprocess interrupt with an RPC message. +- Handle subprocess interrupt with an RPC message. - Restart the subprocess if it terminates itself. (VPython programs do that) -- Support subclassing of exceptions, including in the shell, by moving the +- Support subclassing of exceptions, including in the shell, by moving the exception formatting to the subprocess. @@ -312,15 +323,15 @@ - Removed the File Path from the Additional Help Sources scrolled list. -- Add capability to access Additional Help Sources on the web if the +- Add capability to access Additional Help Sources on the web if the Help File Path begins with //http or www. (Otherwise local path is validated, as before.) - Additional Help Sources were not being posted on the Help menu in the - order entered. Implement sorting the list by [HelpFiles] 'option' + order entered. Implement sorting the list by [HelpFiles] 'option' number. -- Add Browse button to New Help Source dialog. Arrange to start in +- Add Browse button to New Help Source dialog. Arrange to start in Python/Doc if platform is Windows, otherwise start in current directory. - Put the Additional Help Sources directly on the Help menu instead of in @@ -348,7 +359,7 @@ accessing python.org. - Make the methods for finding the Python help docs more robust, and make - them work in the installed configuration, also. + them work in the installed configuration, also. - On the Save Before Run dialog, make the OK button the default. One less mouse action! @@ -385,7 +396,7 @@ What's New in IDLEfork 0.9 Alpha 1? =================================== -*Release date: 31-Dec-2002* +*Release date: 31-Dec-2002* - First release of major new functionality. For further details refer to Idle-dev and/or the Sourceforge CVS. From tim_one at users.sourceforge.net Mon Oct 25 05:19:44 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Mon Oct 25 05:19:47 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_tarfile.py, 1.15, 1.16 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17982/Lib/test Modified Files: test_tarfile.py Log Message: Whitespace normalization. Index: test_tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_tarfile.py,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- test_tarfile.py 20 Oct 2004 11:47:01 -0000 1.15 +++ test_tarfile.py 25 Oct 2004 03:19:41 -0000 1.16 @@ -334,7 +334,7 @@ self.assertEqual(tarfile.filemode(0755), '-rwxr-xr-x') self.assertEqual(tarfile.filemode(07111), '---s--s--t') - + if bz2: # Bzip2 TestCases class ReadTestBzip2(ReadTestGzip): From jvr at users.sourceforge.net Mon Oct 25 17:10:45 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Mon Oct 25 17:10:50 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py,1.6,1.7 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7517 Modified Files: plistlib.py Log Message: Patch from Bob Ippolito, slighly edited: [ 1052399 ] plistlib: add plst resource functionality, fix bugs Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- plistlib.py 2 Oct 2004 14:06:56 -0000 1.6 +++ plistlib.py 25 Oct 2004 15:10:42 -0000 1.7 @@ -57,9 +57,15 @@ """ -__all__ = ["readPlist", "writePlist", "Plist", "Data", "Date", "Dict"] +__all__ = [ + "readPlist", "writePlist", + "readPlistFromResource", "writePlistToResource", + "Plist", "Data", "Date", "Dict" +] # Note: the Plist class has been deprecated. +import base64, datetime + def readPlist(pathOrFile): """Read a .plist file. 'pathOrFile' may either be a file name or a @@ -93,6 +99,44 @@ pathOrFile.close() +def readPlistFromResource(path, restype='plst', resid=0): + """Read plst resource from the resource fork of path. + """ + from Carbon.File import FSRef, FSGetResourceForkName + from Carbon.Files import fsRdPerm + from Carbon import Res + from cStringIO import StringIO + fsRef = FSRef(path) + resNum = Res.FSOpenResourceFile(fsRef, FSGetResourceForkName(), fsRdPerm) + Res.UseResFile(resNum) + plistData = StringIO(Res.Get1Resource(restype, resid).data) + Res.CloseResFile(resNum) + return readPlist(plistData) + + +def writePlistToResource(rootObject, path, restype='plst', resid=0): + """Write 'rootObject' as a plst resource to the resource fork of path. + """ + from Carbon.File import FSRef, FSGetResourceForkName + from Carbon.Files import fsRdWrPerm + from Carbon import Res + from cStringIO import StringIO + plistData = StringIO() + writePlist(rootObject, plistData) + plistData = plistData.getvalue() + fsRef = FSRef(path) + resNum = Res.FSOpenResourceFile(fsRef, FSGetResourceForkName(), fsRdWrPerm) + Res.UseResFile(resNum) + try: + Res.Get1Resource(restype, resid).RemoveResource() + except Res.Error: + pass + res = Res.Resource(plistData) + res.AddResource(restype, resid, '') + res.WriteResource() + Res.CloseResFile(resNum) + + class DumbXMLWriter: def __init__(self, file, indentLevel=0, indent="\t"): @@ -131,6 +175,11 @@ _controlStripper = re.compile(r"[\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0e\x0f" "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]") +# Contents should conform to a subset of ISO 8601 +# (in particular, YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'. Smaller units may be omitted with +# a loss of precision) +_dateParser = re.compile(r"(?P\d\d\d\d)(?:-(?P\d\d)(?:-(?P\d\d)(?:T(?P\d\d)(?::(?P\d\d)(?::(?P\d\d))?)?)?)?)?Z") + def _escapeAndEncode(text): text = text.replace("\r\n", "\n") # convert DOS line endings text = text.replace("\r", "\n") # convert Mac line endings @@ -165,8 +214,7 @@ elif isinstance(value, int): self.simpleElement("integer", str(value)) elif isinstance(value, float): - # should perhaps use repr() for better precision? - self.simpleElement("real", str(value)) + self.simpleElement("real", repr(value)) elif isinstance(value, dict): self.writeDict(value) elif isinstance(value, Data): @@ -262,12 +310,10 @@ self.data = data def fromBase64(cls, data): - import base64 return cls(base64.decodestring(data)) fromBase64 = classmethod(fromBase64) def asBase64(self): - import base64 return base64.encodestring(self.data) def __cmp__(self, other): @@ -284,25 +330,40 @@ class Date: - """Primitive date wrapper, uses time floats internally, is agnostic - about time zones. + """Primitive date wrapper, uses UTC datetime instances internally. """ def __init__(self, date): - if isinstance(date, str): - from xml.utils.iso8601 import parse - date = parse(date) + if isinstance(date, datetime.datetime): + pass + elif isinstance(date, (float, int)): + date = datetime.datetime.fromtimestamp(date) + elif isinstance(date, basestring): + order = ('year', 'month', 'day', 'hour', 'minute', 'second') + gd = _dateParser.match(date).groupdict() + lst = [] + for key in order: + val = gd[key] + if val is None: + break + lst.append(int(val)) + date = datetime.datetime(*lst) + else: + raise ValueError, "Can't convert %r to datetime" % (date,) self.date = date def toString(self): - from xml.utils.iso8601 import tostring - return tostring(self.date) + d = self.date + return '%04d-%02d-%02dT%02d:%02d:%02dZ' % ( + d.year, d.month, d.day, + d.second, d.minute, d.hour, + ) def __cmp__(self, other): if isinstance(other, self.__class__): return cmp(self.date, other.date) - elif isinstance(other, (int, float)): - return cmp(self.date, other) + elif isinstance(other, (datetime.datetime, float, int, basestring)): + return cmp(self.date, Date(other).date) else: return cmp(id(self), id(other)) @@ -317,13 +378,13 @@ self.currentKey = None self.root = None - def parse(self, file): + def parse(self, fileobj): from xml.parsers.expat import ParserCreate parser = ParserCreate() parser.StartElementHandler = self.handleBeginElement parser.EndElementHandler = self.handleEndElement parser.CharacterDataHandler = self.handleData - parser.ParseFile(file) + parser.ParseFile(fileobj) return self.root def handleBeginElement(self, element, attrs): From fdrake at users.sourceforge.net Mon Oct 25 18:03:53 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Mon Oct 25 18:03:56 2004 Subject: [Python-checkins] python/dist/src/Doc/tut tut.tex,1.254,1.255 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20744 Modified Files: tut.tex Log Message: - improve the explanation of the -*- coding: ... -*- marker - fix a minor formatting nit that affected the typeset version Index: tut.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/tut.tex,v retrieving revision 1.254 retrieving revision 1.255 diff -u -d -r1.254 -r1.255 --- tut.tex 7 Oct 2004 06:46:22 -0000 1.254 +++ tut.tex 25 Oct 2004 16:03:49 -0000 1.255 @@ -1,5 +1,6 @@ \documentclass{manual} \usepackage[T1]{fontenc} +\usepackage{textcomp} % Things to do: % Should really move the Python startup file info to an appendix @@ -326,28 +327,41 @@ files. The best way to do it is to put one more special comment line right after the \code{\#!} line to define the source file encoding: -\begin{verbatim} -# -*- coding: iso-8859-1 -*- -\end{verbatim} +\begin{alltt} +# -*- coding: \var{encoding} -*- +\end{alltt} With that declaration, all characters in the source file will be treated as -{}\code{iso-8859-1}, and it will be +having the encoding \var{encoding}, and it will be possible to directly write Unicode string literals in the selected encoding. The list of possible encodings can be found in the \citetitle[../lib/lib.html]{Python Library Reference}, in the section on \ulink{\module{codecs}}{../lib/module-codecs.html}. +For example, to write Unicode literals including the Euro currency +symbol, the ISO-8859-15 encoding can be used, with the Euro symbol +having the ordinal value 164. This script will print the value 8364 +(the Unicode codepoint corresponding to the Euro symbol) and then +exit: + +\begin{alltt} +# -*- coding: iso-8859-15 -*- + +currency = u"\texteuro" +print ord(currency) +\end{alltt} + If your editor supports saving files as \code{UTF-8} with a UTF-8 \emph{byte order mark} (aka BOM), you can use that instead of an encoding declaration. IDLE supports this capability if \code{Options/General/Default Source Encoding/UTF-8} is set. Notice that this signature is not understood in older Python releases (2.2 and earlier), and also not understood by the operating system for -\code{\#!} files. +script files with \code{\#!} lines (only used on \UNIX{} systems). By using UTF-8 (either through the signature or an encoding declaration), characters of most languages in the world can be used -simultaneously in string literals and comments. Using non-\ASCII +simultaneously in string literals and comments. Using non-\ASCII{} characters in identifiers is not supported. To display all these characters properly, your editor must recognize that the file is UTF-8, and it must use a font that supports all the characters in the From jvr at users.sourceforge.net Mon Oct 25 18:04:29 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Mon Oct 25 18:04:32 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py,1.7,1.8 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20675 Modified Files: plistlib.py Log Message: Removed superfluous **kwargs constructor cruft: this class predates the dict(**kwargs) feature. Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- plistlib.py 25 Oct 2004 15:10:42 -0000 1.7 +++ plistlib.py 25 Oct 2004 16:04:20 -0000 1.8 @@ -258,14 +258,6 @@ to retrieve values, making d.foo equivalent to d["foo"]. """ - def __new__(cls, **kwargs): - self = dict.__new__(cls) - self.update(kwargs) - return self - - def __init__(self, **kwargs): - self.update(kwargs) - def __getattr__(self, attr): try: value = self[attr] From jvr at users.sourceforge.net Mon Oct 25 18:09:13 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Mon Oct 25 18:09:16 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py,1.8,1.9 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22077 Modified Files: plistlib.py Log Message: Deprecate Plist class Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- plistlib.py 25 Oct 2004 16:04:20 -0000 1.8 +++ plistlib.py 25 Oct 2004 16:09:10 -0000 1.9 @@ -281,8 +281,14 @@ writePlist() functions instead. """ + def __init__(self, **kwargs): + from warnings import warn + warn("The Plist class is deprecated, use the readPlist() and " + "writePlist() functions instead", PendingDeprecationWarning) + super(Plist, self).__init__(**kwargs) + def fromFile(cls, pathOrFile): - """Deprecated! Use the readPlist() function instead.""" + """Deprecated. Use the readPlist() function instead.""" rootObject = readPlist(pathOrFile) plist = cls() plist.update(rootObject) @@ -290,7 +296,7 @@ fromFile = classmethod(fromFile) def write(self, pathOrFile): - """Deprecated! Use the writePlist() function instead.""" + """Deprecated. Use the writePlist() function instead.""" writePlist(self, pathOrFile) From jvr at users.sourceforge.net Mon Oct 25 18:10:57 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Mon Oct 25 18:11:08 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py, 1.9, 1.10 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22724 Modified Files: plistlib.py Log Message: Updated doc strings. Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- plistlib.py 25 Oct 2004 16:09:10 -0000 1.9 +++ plistlib.py 25 Oct 2004 16:10:53 -0000 1.10 @@ -253,8 +253,7 @@ class Dict(dict): - """Convenience dictionary subclass: it allows dict construction using - keyword arguments (just like dict() in 2.3) as well as attribute notation + """Convenience dictionary subclass: it allows attribute notation to retrieve values, making d.foo equivalent to d["foo"]. """ @@ -277,7 +276,7 @@ class Plist(Dict): - """This class has been deprecated! Use the Dict with readPlist() and + """This class has been deprecated. Use the Dict with readPlist() and writePlist() functions instead. """ From fdrake at users.sourceforge.net Mon Oct 25 23:35:20 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Mon Oct 25 23:35:23 2004 Subject: [Python-checkins] python/dist/src/Doc/lib xmlsaxhandler.tex, 1.11, 1.12 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1174 Modified Files: xmlsaxhandler.tex Log Message: add missing line break Index: xmlsaxhandler.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/xmlsaxhandler.tex,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- xmlsaxhandler.tex 6 May 2004 03:47:48 -0000 1.11 +++ xmlsaxhandler.tex 25 Oct 2004 21:35:17 -0000 1.12 @@ -65,7 +65,7 @@ \end{datadesc} \begin{datadesc}{feature_string_interning} - Value: \code{"http://xml.org/sax/features/string-interning"} + Value: \code{"http://xml.org/sax/features/string-interning"}\\ true: All element names, prefixes, attribute names, Namespace URIs, and local names are interned using the built-in intern function.\\ false: Names are not necessarily interned, although they may be (default).\\ From fdrake at users.sourceforge.net Mon Oct 25 23:42:00 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Mon Oct 25 23:42:02 2004 Subject: [Python-checkins] python/dist/src/Doc/lib xmlsaxhandler.tex, 1.10.12.1, 1.10.12.2 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2279 Modified Files: Tag: release23-maint xmlsaxhandler.tex Log Message: add missing line break Index: xmlsaxhandler.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/xmlsaxhandler.tex,v retrieving revision 1.10.12.1 retrieving revision 1.10.12.2 diff -u -d -r1.10.12.1 -r1.10.12.2 --- xmlsaxhandler.tex 6 May 2004 03:48:32 -0000 1.10.12.1 +++ xmlsaxhandler.tex 25 Oct 2004 21:41:57 -0000 1.10.12.2 @@ -65,7 +65,7 @@ \end{datadesc} \begin{datadesc}{feature_string_interning} - Value: \code{"http://xml.org/sax/features/string-interning"} + Value: \code{"http://xml.org/sax/features/string-interning"}\\ true: All element names, prefixes, attribute names, Namespace URIs, and local names are interned using the built-in intern function.\\ false: Names are not necessarily interned, although they may be (default).\\ From rhettinger at users.sourceforge.net Tue Oct 26 03:52:38 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue Oct 26 03:52:42 2004 Subject: [Python-checkins] python/dist/src/Lib/test string_tests.py, 1.41, 1.42 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26552/Lib/test Modified Files: string_tests.py Log Message: SF bug #1054139: serious string hashing error in 2.4b1 _PyString_Resize() readied strings for mutation but did not invalidate the cached hash value. Index: string_tests.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/string_tests.py,v retrieving revision 1.41 retrieving revision 1.42 diff -u -d -r1.41 -r1.42 --- string_tests.py 27 Aug 2004 05:36:07 -0000 1.41 +++ string_tests.py 26 Oct 2004 01:52:36 -0000 1.42 @@ -80,6 +80,15 @@ args = self.fixtype(args) getattr(object, methodname)(*args) + def test_hash(self): + # SF bug 1054139: += optimization was not invalidating cached hash value + a = self.type2test('DNSSEC') + b = self.type2test('') + for c in a: + b += c + hash(b) + self.assertEqual(hash(a), hash(b)) + def test_capitalize(self): self.checkequal(' hello ', ' hello ', 'capitalize') self.checkequal('Hello ', 'Hello ','capitalize') From rhettinger at users.sourceforge.net Tue Oct 26 03:52:39 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue Oct 26 03:52:43 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1175,1.1176 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26552/Misc Modified Files: NEWS Log Message: SF bug #1054139: serious string hashing error in 2.4b1 _PyString_Resize() readied strings for mutation but did not invalidate the cached hash value. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1175 retrieving revision 1.1176 diff -u -d -r1.1175 -r1.1176 --- NEWS 24 Oct 2004 00:32:24 -0000 1.1175 +++ NEWS 26 Oct 2004 01:52:36 -0000 1.1176 @@ -32,7 +32,7 @@ Core and builtins ----------------- -... +- Bug #1054139 _PyString_Resize() now invalidates its cached hash value. Extension Modules ----------------- From rhettinger at users.sourceforge.net Tue Oct 26 03:52:40 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue Oct 26 03:52:44 2004 Subject: [Python-checkins] python/dist/src/Objects stringobject.c, 2.225, 2.226 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26552/Objects Modified Files: stringobject.c Log Message: SF bug #1054139: serious string hashing error in 2.4b1 _PyString_Resize() readied strings for mutation but did not invalidate the cached hash value. Index: stringobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/stringobject.c,v retrieving revision 2.225 retrieving revision 2.226 diff -u -d -r2.225 -r2.226 --- stringobject.c 23 Aug 2004 23:23:54 -0000 2.225 +++ stringobject.c 26 Oct 2004 01:52:37 -0000 2.226 @@ -3530,6 +3530,7 @@ sv = (PyStringObject *) *pv; sv->ob_size = newsize; sv->ob_sval[newsize] = '\0'; + sv->ob_shash = -1; /* invalidate cached hash value */ return 0; } From rhettinger at users.sourceforge.net Tue Oct 26 05:53:38 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue Oct 26 05:53:42 2004 Subject: [Python-checkins] python/dist/src/Doc/tut tut.tex,1.255,1.256 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20946 Modified Files: tut.tex Log Message: SF 1053956: help() not in tutorial index Index: tut.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/tut.tex,v retrieving revision 1.255 retrieving revision 1.256 diff -u -d -r1.255 -r1.256 --- tut.tex 25 Oct 2004 16:03:49 -0000 1.255 +++ tut.tex 26 Oct 2004 03:53:35 -0000 1.256 @@ -4479,6 +4479,7 @@ shadowing the builtin \function{open()} function which operates much differently. +\bifuncindex{help} The builtin \function{dir()} and \function{help()} functions are useful as interactive aids for working with large modules like \module{os}: From jvr at users.sourceforge.net Tue Oct 26 08:50:52 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Tue Oct 26 08:50:56 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py, 1.10, 1.11 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22137 Modified Files: plistlib.py Log Message: - added two more convenience functions: readPlistFromString() and writePlistToString() - use these two in the resource functions. - Tweaked module doc string. Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- plistlib.py 25 Oct 2004 16:10:53 -0000 1.10 +++ plistlib.py 26 Oct 2004 06:50:50 -0000 1.11 @@ -8,9 +8,12 @@ function. 'rootObject' is the top level object, 'pathOrFile' is a filename or a (writable) file object. -To parse a plist from a file, use the readPlist(pathOrFile) -function, with a file name or a (readable) file object as the only -argument. It returns the top level object (usually a dictionary). +To parse a plist from a file, use the readPlist(pathOrFile) function, +with a file name or a (readable) file object as the only argument. It +returns the top level object (again, usually a dictionary). + +To work with plist data in strings, you can use readPlistFromString() +and writePlistToString(). Values can be strings, integers, floats, booleans, tuples, lists, dictionaries, Data or Date objects. String values (including dictionary @@ -19,13 +22,13 @@ This module exports a class named Dict(), which allows you to easily construct (nested) dicts using keyword arguments as well as accessing values with attribute notation, where d.foo is equivalent to d["foo"]. -Regular dictionaries work, too. +Regular dictionaries work, too. Dictionaries are always represented with +Dict instances when loading plist data. The plist type is supported through the Data class. This is a thin wrapper around a Python string. -The plist data has (limited) support through the Date class. -(Warning: Dates are only supported if the PyXML package is installed.) +The plist data has support through the Date class. Generate Plist example: @@ -58,13 +61,15 @@ __all__ = [ - "readPlist", "writePlist", + "readPlist", "writePlist", "readPlistFromString", "writePlistToString", "readPlistFromResource", "writePlistToResource", "Plist", "Data", "Date", "Dict" ] # Note: the Plist class has been deprecated. -import base64, datetime +import base64 +import datetime +from cStringIO import StringIO def readPlist(pathOrFile): @@ -99,19 +104,32 @@ pathOrFile.close() +def readPlistFromString(data): + """Read a plist data from a string. Return the root object. + """ + return readPlist(StringIO(data)) + + +def writePlistToString(rootObject): + """Return 'rootObject' as a plist-formatted string. + """ + f = StringIO() + writePlist(rootObject, f) + return f.getvalue() + + def readPlistFromResource(path, restype='plst', resid=0): """Read plst resource from the resource fork of path. """ from Carbon.File import FSRef, FSGetResourceForkName from Carbon.Files import fsRdPerm from Carbon import Res - from cStringIO import StringIO fsRef = FSRef(path) resNum = Res.FSOpenResourceFile(fsRef, FSGetResourceForkName(), fsRdPerm) Res.UseResFile(resNum) - plistData = StringIO(Res.Get1Resource(restype, resid).data) + plistData = Res.Get1Resource(restype, resid).data Res.CloseResFile(resNum) - return readPlist(plistData) + return readPlistFromString(plistData) def writePlistToResource(rootObject, path, restype='plst', resid=0): @@ -120,10 +138,7 @@ from Carbon.File import FSRef, FSGetResourceForkName from Carbon.Files import fsRdWrPerm from Carbon import Res - from cStringIO import StringIO - plistData = StringIO() - writePlist(rootObject, plistData) - plistData = plistData.getvalue() + plistData = writePlistToString(rootObject) fsRef = FSRef(path) resNum = Res.FSOpenResourceFile(fsRef, FSGetResourceForkName(), fsRdWrPerm) Res.UseResFile(resNum) From jvr at users.sourceforge.net Tue Oct 26 09:20:29 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Tue Oct 26 09:20:32 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py, 1.11, 1.12 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27764 Modified Files: plistlib.py Log Message: - Removed Date class. We don't really need it for b/w compatibility since a) the functionality depended on PyXML before and b) hardly worked to begin with. - Instead, output and require upon input datetime.datetime objects. Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- plistlib.py 26 Oct 2004 06:50:50 -0000 1.11 +++ plistlib.py 26 Oct 2004 07:20:26 -0000 1.12 @@ -16,8 +16,9 @@ and writePlistToString(). Values can be strings, integers, floats, booleans, tuples, lists, -dictionaries, Data or Date objects. String values (including dictionary -keys) may be unicode strings -- they will be written out as UTF-8. +dictionaries, Data or datetime.datetime objects. String values (including +dictionary keys) may be unicode strings -- they will be written out as +UTF-8. This module exports a class named Dict(), which allows you to easily construct (nested) dicts using keyword arguments as well as accessing @@ -28,8 +29,6 @@ The plist type is supported through the Data class. This is a thin wrapper around a Python string. -The plist data has support through the Date class. - Generate Plist example: pl = Dict( @@ -45,7 +44,7 @@ ), someData = Data(""), someMoreData = Data("" * 10), - aDate = Date(time.mktime(time.gmtime())), + aDate = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())), ) # unicode keys are possible, but a little awkward to use: pl[u'\xc5benraa'] = "That was a unicode key." @@ -63,7 +62,7 @@ __all__ = [ "readPlist", "writePlist", "readPlistFromString", "writePlistToString", "readPlistFromResource", "writePlistToResource", - "Plist", "Data", "Date", "Dict" + "Plist", "Data", "Dict" ] # Note: the Plist class has been deprecated. @@ -195,6 +194,23 @@ # a loss of precision) _dateParser = re.compile(r"(?P\d\d\d\d)(?:-(?P\d\d)(?:-(?P\d\d)(?:T(?P\d\d)(?::(?P\d\d)(?::(?P\d\d))?)?)?)?)?Z") +def _dateFromString(s): + order = ('year', 'month', 'day', 'hour', 'minute', 'second') + gd = _dateParser.match(s).groupdict() + lst = [] + for key in order: + val = gd[key] + if val is None: + break + lst.append(int(val)) + return datetime.datetime(*lst) + +def _dateToString(d): + return '%04d-%02d-%02dT%02d:%02d:%02dZ' % ( + d.year, d.month, d.day, + d.hour, d.minute, d.second + ) + def _escapeAndEncode(text): text = text.replace("\r\n", "\n") # convert DOS line endings text = text.replace("\r", "\n") # convert Mac line endings @@ -234,8 +250,8 @@ self.writeDict(value) elif isinstance(value, Data): self.writeData(value) - elif isinstance(value, Date): - self.simpleElement("date", value.toString()) + elif isinstance(value, datetime.datetime): + self.simpleElement("date", _dateToString(value)) elif isinstance(value, (tuple, list)): self.writeArray(value) else: @@ -340,49 +356,6 @@ return "%s(%s)" % (self.__class__.__name__, repr(self.data)) -class Date: - - """Primitive date wrapper, uses UTC datetime instances internally. - """ - - def __init__(self, date): - if isinstance(date, datetime.datetime): - pass - elif isinstance(date, (float, int)): - date = datetime.datetime.fromtimestamp(date) - elif isinstance(date, basestring): - order = ('year', 'month', 'day', 'hour', 'minute', 'second') - gd = _dateParser.match(date).groupdict() - lst = [] - for key in order: - val = gd[key] - if val is None: - break - lst.append(int(val)) - date = datetime.datetime(*lst) - else: - raise ValueError, "Can't convert %r to datetime" % (date,) - self.date = date - - def toString(self): - d = self.date - return '%04d-%02d-%02dT%02d:%02d:%02dZ' % ( - d.year, d.month, d.day, - d.second, d.minute, d.hour, - ) - - def __cmp__(self, other): - if isinstance(other, self.__class__): - return cmp(self.date, other.date) - elif isinstance(other, (datetime.datetime, float, int, basestring)): - return cmp(self.date, Date(other).date) - else: - return cmp(id(self), id(other)) - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, repr(self.toString())) - - class PlistParser: def __init__(self): @@ -464,4 +437,4 @@ def end_data(self): self.addObject(Data.fromBase64(self.getData())) def end_date(self): - self.addObject(Date(self.getData())) + self.addObject(_dateFromString(self.getData())) From jvr at users.sourceforge.net Tue Oct 26 09:38:19 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Tue Oct 26 09:38:22 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py, 1.12, 1.13 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32063 Modified Files: plistlib.py Log Message: Deprecating Dict class; going through a few hoops to get the warnings right. Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- plistlib.py 26 Oct 2004 07:20:26 -0000 1.12 +++ plistlib.py 26 Oct 2004 07:38:16 -0000 1.13 @@ -20,23 +20,17 @@ dictionary keys) may be unicode strings -- they will be written out as UTF-8. -This module exports a class named Dict(), which allows you to easily -construct (nested) dicts using keyword arguments as well as accessing -values with attribute notation, where d.foo is equivalent to d["foo"]. -Regular dictionaries work, too. Dictionaries are always represented with -Dict instances when loading plist data. - The plist type is supported through the Data class. This is a thin wrapper around a Python string. Generate Plist example: - pl = Dict( + pl = dict( aString="Doodah", aList=["A", "B", 12, 32.1, [1, 2, 3]], aFloat = 0.1, anInt = 728, - aDict=Dict( + aDict=dict( anotherString="", aUnicodeValue=u'M\xe4ssig, Ma\xdf', aTrueValue=True, @@ -53,9 +47,7 @@ Parse Plist example: pl = readPlist(pathOrFile) - print pl.aKey # same as pl["aKey"] - - + print pl["aKey"] """ @@ -64,7 +56,7 @@ "readPlistFromResource", "writePlistToResource", "Plist", "Data", "Dict" ] -# Note: the Plist class has been deprecated. +# Note: the Plist and Dict classes have been deprecated. import base64 import datetime @@ -282,20 +274,26 @@ self.endElement("array") -class Dict(dict): +class _InternalDict(dict): - """Convenience dictionary subclass: it allows attribute notation - to retrieve values, making d.foo equivalent to d["foo"]. - """ + # This class is needed while Dict is scheduled for deprecation: + # we only need to warn when a *user* instantiates Dict or when + # the "attribute notation for dict keys" is used. def __getattr__(self, attr): try: value = self[attr] except KeyError: raise AttributeError, attr + from warnings import warn + warn("Attribute access from plist dicts is deprecated, use d[key] " + "notation instead", PendingDeprecationWarning) return value def __setattr__(self, attr, value): + from warnings import warn + warn("Attribute access from plist dicts is deprecated, use d[key] " + "notation instead", PendingDeprecationWarning) self[attr] = value def __delattr__(self, attr): @@ -303,12 +301,23 @@ del self[attr] except KeyError: raise AttributeError, attr + from warnings import warn + warn("Attribute access from plist dicts is deprecated, use d[key] " + "notation instead", PendingDeprecationWarning) +class Dict(_InternalDict): -class Plist(Dict): + def __init__(self, **kwargs): + from warnings import warn + warn("The plistlib.Dict class is deprecated, use builtin dict instead", + PendingDeprecationWarning) + super(Dict, self).__init__(**kwargs) - """This class has been deprecated. Use the Dict with readPlist() and - writePlist() functions instead. + +class Plist(_InternalDict): + + """This class has been deprecated. Use readPlist() and writePlist() + functions instead, together with regular dict objects. """ def __init__(self, **kwargs): @@ -408,7 +417,7 @@ # element handlers def begin_dict(self, attrs): - d = Dict() + d = _InternalDict() self.addObject(d) self.stack.append(d) def end_dict(self): From rhettinger at users.sourceforge.net Tue Oct 26 10:59:16 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue Oct 26 10:59:19 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_peepholer.py, 1.3, 1.4 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15896/Lib/test Modified Files: test_peepholer.py Log Message: SF bug #1053819: Segfault in tuple_of_constants Peepholer could be fooled into misidentifying a tuple_of_constants. Added code to count consecutive occurrences of LOAD_CONST. Use the count to weed out the misidentified cases. Added a unittest. Index: test_peepholer.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_peepholer.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- test_peepholer.py 22 Sep 2004 18:44:08 -0000 1.3 +++ test_peepholer.py 26 Oct 2004 08:59:14 -0000 1.4 @@ -83,6 +83,23 @@ self.assert_(elem in asm) self.assert_('BUILD_TUPLE' not in asm) + # Bug 1053819: Tuple of constants misidentified when presented with: + # . . . opcode_with_arg 100 unary_opcode BUILD_TUPLE 1 . . . + # The following would segfault upon compilation + def crater(): + (~[ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + ],) + def test_elim_extra_return(self): # RETURN LOAD_CONST None RETURN --> RETURN def f(x): From rhettinger at users.sourceforge.net Tue Oct 26 10:59:16 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue Oct 26 10:59:20 2004 Subject: [Python-checkins] python/dist/src/Python compile.c,2.331,2.332 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15896/Python Modified Files: compile.c Log Message: SF bug #1053819: Segfault in tuple_of_constants Peepholer could be fooled into misidentifying a tuple_of_constants. Added code to count consecutive occurrences of LOAD_CONST. Use the count to weed out the misidentified cases. Added a unittest. Index: compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.331 retrieving revision 2.332 diff -u -d -r2.331 -r2.332 --- compile.c 24 Oct 2004 00:10:05 -0000 2.331 +++ compile.c 26 Oct 2004 08:59:13 -0000 2.332 @@ -419,15 +419,16 @@ newconst = PyTuple_New(n); if (newconst == NULL) return 0; + len_consts = PyList_GET_SIZE(consts); for (i=0 ; i= 0 && + j == lastlc && codestr[h] == LOAD_CONST && ISBASICBLOCK(blocks, h, 3*(j+1)) && tuple_of_constants(&codestr[h], j, consts)) { From perky at users.sourceforge.net Tue Oct 26 11:16:43 2004 From: perky at users.sourceforge.net (perky@users.sourceforge.net) Date: Tue Oct 26 11:16:46 2004 Subject: [Python-checkins] python/dist/src/Doc/lib liblinecache.tex,1.5,1.6 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19767/Doc/lib Modified Files: liblinecache.tex Log Message: SF #737473: Show up-to-date source code in tracebacks always. And add an optional argument 'filename' to linecache.checkcache() to enable checking caches per-file. Index: liblinecache.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liblinecache.tex,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- liblinecache.tex 24 Jan 2001 17:19:05 -0000 1.5 +++ liblinecache.tex 26 Oct 2004 09:16:41 -0000 1.6 @@ -31,9 +31,10 @@ files previously read using \function{getline()}. \end{funcdesc} -\begin{funcdesc}{checkcache}{} +\begin{funcdesc}{checkcache}{\optional{filename}} Check the cache for validity. Use this function if files in the cache -may have changed on disk, and you require the updated version. +may have changed on disk, and you require the updated version. If +\var{filename} is omitted, it will check the whole cache entries. \end{funcdesc} Example: From perky at users.sourceforge.net Tue Oct 26 11:16:44 2004 From: perky at users.sourceforge.net (perky@users.sourceforge.net) Date: Tue Oct 26 11:16:49 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_traceback.py, 1.7, 1.8 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19767/Lib/test Modified Files: test_traceback.py Log Message: SF #737473: Show up-to-date source code in tracebacks always. And add an optional argument 'filename' to linecache.checkcache() to enable checking caches per-file. Index: test_traceback.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_traceback.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- test_traceback.py 6 Nov 2002 11:45:15 -0000 1.7 +++ test_traceback.py 26 Oct 2004 09:16:41 -0000 1.8 @@ -40,6 +40,47 @@ self.assert_(len(err) == 3) self.assert_(err[1].strip() == "[x for x in x] = x") + def test_bug737473(self): + import sys, os, tempfile + savedpath = sys.path[:] + testdir = tempfile.mkdtemp() + try: + sys.path.insert(0, testdir) + testfile = os.path.join(testdir, 'test_bug737473.py') + print >> open(testfile, 'w'), """\ +def test(): + raise ValueError""" + + if hasattr(os, 'utime'): + os.utime(testfile, (0, 0)) + else: + import time + time.sleep(3) # not to stay in same mtime. + + if 'test_bug737473' in sys.modules: + del sys.modules['test_bug737473'] + import test_bug737473 + + try: + test_bug737473.test() + except ValueError: + # this loads source code to linecache + traceback.extract_tb(sys.exc_traceback) + + print >> open(testfile, 'w'), """\ +def test(): + raise NotImplementedError""" + reload(test_bug737473) + try: + test_bug737473.test() + except NotImplementedError: + src = traceback.extract_tb(sys.exc_traceback)[-1][-1] + self.failUnlessEqual(src, 'raise NotImplementedError') + finally: + sys.path[:] = savedpath + for f in os.listdir(testdir): + os.unlink(os.path.join(testdir, f)) + os.rmdir(testdir) def test_main(): run_unittest(TracebackCases) From perky at users.sourceforge.net Tue Oct 26 11:16:44 2004 From: perky at users.sourceforge.net (perky@users.sourceforge.net) Date: Tue Oct 26 11:16:50 2004 Subject: [Python-checkins] python/dist/src/Lib linecache.py, 1.12, 1.13 traceback.py, 1.30, 1.31 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19767/Lib Modified Files: linecache.py traceback.py Log Message: SF #737473: Show up-to-date source code in tracebacks always. And add an optional argument 'filename' to linecache.checkcache() to enable checking caches per-file. Index: linecache.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/linecache.py,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- linecache.py 29 Jun 2003 16:59:43 -0000 1.12 +++ linecache.py 26 Oct 2004 09:16:41 -0000 1.13 @@ -40,11 +40,19 @@ return updatecache(filename) -def checkcache(): +def checkcache(filename=None): """Discard cache entries that are out of date. (This is not checked upon each call!)""" - for filename in cache.keys(): + if filename is None: + filenames = cache.keys() + else: + if filename in cache: + filenames = [filename] + else: + return + + for filename in filenames: size, mtime, lines, fullname = cache[filename] try: stat = os.stat(fullname) Index: traceback.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/traceback.py,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- traceback.py 18 Jan 2004 20:29:54 -0000 1.30 +++ traceback.py 26 Oct 2004 09:16:41 -0000 1.31 @@ -65,6 +65,7 @@ name = co.co_name _print(file, ' File "%s", line %d, in %s' % (filename,lineno,name)) + linecache.checkcache(filename) line = linecache.getline(filename, lineno) if line: _print(file, ' ' + line.strip()) tb = tb.tb_next @@ -96,6 +97,7 @@ co = f.f_code filename = co.co_filename name = co.co_name + linecache.checkcache(filename) line = linecache.getline(filename, lineno) if line: line = line.strip() else: line = None @@ -277,6 +279,7 @@ co = f.f_code filename = co.co_filename name = co.co_name + linecache.checkcache(filename) line = linecache.getline(filename, lineno) if line: line = line.strip() else: line = None From perky at users.sourceforge.net Tue Oct 26 11:16:46 2004 From: perky at users.sourceforge.net (perky@users.sourceforge.net) Date: Tue Oct 26 11:16:52 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1176,1.1177 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19767/Misc Modified Files: NEWS Log Message: SF #737473: Show up-to-date source code in tracebacks always. And add an optional argument 'filename' to linecache.checkcache() to enable checking caches per-file. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1176 retrieving revision 1.1177 diff -u -d -r1.1176 -r1.1177 --- NEWS 26 Oct 2004 01:52:36 -0000 1.1176 +++ NEWS 26 Oct 2004 09:16:42 -0000 1.1177 @@ -59,6 +59,9 @@ - Bug #1017553: fix bug in tarfile.filemode() +- Bug #737473: fix bug that old source code is shown in tracebacks even if + the source code is updated and reloaded. + Build ----- From perky at users.sourceforge.net Tue Oct 26 11:53:49 2004 From: perky at users.sourceforge.net (perky@users.sourceforge.net) Date: Tue Oct 26 11:53:52 2004 Subject: [Python-checkins] python/dist/src configure.in, 1.472, 1.473 configure, 1.459, 1.460 Message-ID: Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27686 Modified Files: configure.in configure Log Message: Patch #1044395: Allow configure option --enable-shared in FreeBSD. (Submitted by James William Pye, Patch revised by Jiwon Seo) Index: configure.in =================================================================== RCS file: /cvsroot/python/python/dist/src/configure.in,v retrieving revision 1.472 retrieving revision 1.473 diff -u -d -r1.472 -r1.473 --- configure.in 13 Oct 2004 15:30:55 -0000 1.472 +++ configure.in 26 Oct 2004 09:53:40 -0000 1.473 @@ -557,10 +557,15 @@ RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} INSTSONAME="$LDLIBRARY".$SOVERSION ;; - Linux*|GNU*|NetBSD*) + Linux*|GNU*|NetBSD*|FreeBSD*) LDLIBRARY='libpython$(VERSION).so' BLDLIBRARY='-L. -lpython$(VERSION)' RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} + case $ac_sys_system in + FreeBSD*) + SOVERSION=`echo $SOVERSION|cut -d "." -f 1` + ;; + esac INSTSONAME="$LDLIBRARY".$SOVERSION ;; hp*|HP*) @@ -1345,7 +1350,7 @@ OpenBSD*|FreeBSD*) if [[ "`$CC -dM -E - Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27686/Misc Modified Files: NEWS Log Message: Patch #1044395: Allow configure option --enable-shared in FreeBSD. (Submitted by James William Pye, Patch revised by Jiwon Seo) Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1177 retrieving revision 1.1178 diff -u -d -r1.1177 -r1.1178 --- NEWS 26 Oct 2004 09:16:42 -0000 1.1177 +++ NEWS 26 Oct 2004 09:53:46 -0000 1.1178 @@ -59,13 +59,13 @@ - Bug #1017553: fix bug in tarfile.filemode() -- Bug #737473: fix bug that old source code is shown in tracebacks even if +- Patch #737473: fix bug that old source code is shown in tracebacks even if the source code is updated and reloaded. Build ----- -... +- Patch #1044395: --enable-shared is allowed in FreeBSD also. C API ----- From jvr at users.sourceforge.net Tue Oct 26 12:11:09 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Tue Oct 26 12:11:11 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py, 1.13, 1.14 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30919 Modified Files: plistlib.py Log Message: also escape '>', to closer match Apple's plist output Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- plistlib.py 26 Oct 2004 07:38:16 -0000 1.13 +++ plistlib.py 26 Oct 2004 10:11:00 -0000 1.14 @@ -208,6 +208,7 @@ text = text.replace("\r", "\n") # convert Mac line endings text = text.replace("&", "&") # escape '&' text = text.replace("<", "<") # escape '<' + text = text.replace(">", ">") # escape '>' text = _controlStripper.sub("?", text) # replace control chars with '?' return text.encode("utf-8") # encode as UTF-8 From jvr at users.sourceforge.net Tue Oct 26 12:30:58 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Tue Oct 26 12:31:01 2004 Subject: [Python-checkins] python/dist/src/Lib/plat-mac plistlib.py, 1.14, 1.15 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-mac In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3138 Modified Files: plistlib.py Log Message: Made output match Apple's exactly. To do that I had to add a custom version of base64.encodestring() so I could control the line length of the base64 output. Index: plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-mac/plistlib.py,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- plistlib.py 26 Oct 2004 10:11:00 -0000 1.14 +++ plistlib.py 26 Oct 2004 10:30:55 -0000 1.15 @@ -58,7 +58,7 @@ ] # Note: the Plist and Dict classes have been deprecated. -import base64 +import binascii import datetime from cStringIO import StringIO @@ -252,9 +252,13 @@ def writeData(self, data): self.beginElement("data") - for line in data.asBase64().split("\n"): + self.indentLevel -= 1 + maxlinelength = 76 - len(self.indent.replace("\t", " " * 8) * + self.indentLevel) + for line in data.asBase64(maxlinelength).split("\n"): if line: self.writeln(line) + self.indentLevel += 1 self.endElement("data") def writeDict(self, d): @@ -317,7 +321,7 @@ class Plist(_InternalDict): - """This class has been deprecated. Use readPlist() and writePlist() + """This class has been deprecated. Use readPlist() and writePlist() functions instead, together with regular dict objects. """ @@ -340,6 +344,15 @@ writePlist(self, pathOrFile) +def _encodeBase64(s, maxlinelength=76): + # copied from base64.encodestring(), with added maxlinelength argument + maxbinsize = (maxlinelength//4)*3 + pieces = [] + for i in range(0, len(s), maxbinsize): + chunk = s[i : i + maxbinsize] + pieces.append(binascii.b2a_base64(chunk)) + return "".join(pieces) + class Data: """Wrapper for binary data.""" @@ -348,11 +361,13 @@ self.data = data def fromBase64(cls, data): - return cls(base64.decodestring(data)) + # base64.decodestring just calls binascii.a2b_base64; + # it seems overkill to use both base64 and binascii. + return cls(binascii.a2b_base64(data)) fromBase64 = classmethod(fromBase64) - def asBase64(self): - return base64.encodestring(self.data) + def asBase64(self, maxlinelength=76): + return _encodeBase64(self.data, maxlinelength) def __cmp__(self, other): if isinstance(other, self.__class__): From jvr at users.sourceforge.net Tue Oct 26 13:02:11 2004 From: jvr at users.sourceforge.net (jvr@users.sourceforge.net) Date: Tue Oct 26 13:02:20 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_plistlib.py, 1.4, 1.5 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9073 Modified Files: test_plistlib.py Log Message: - Added tests for the string load/dump function. - Added a chunk of plist data as generated by Cocoa's NSDictionary and verify we output the same (including formatting) - Changed the "literal" plist code to match the raw test data Index: test_plistlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_plistlib.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- test_plistlib.py 2 Oct 2004 14:06:18 -0000 1.4 +++ test_plistlib.py 26 Oct 2004 11:02:08 -0000 1.5 @@ -3,8 +3,91 @@ import unittest import plistlib import os +import time +import datetime from test import test_support + +# This test data was generated through Cocoa's NSDictionary class +TESTDATA = """ + + + + aDate + 2004-10-26T10:33:33Z + aDict + + aFalseValue + + aTrueValue + + aUnicodeValue + M\xc3\xa4ssig, Ma\xc3\x9f + anotherString + <hello & 'hi' there!> + deeperDict + + a + 17 + b + 32.5 + c + + 1 + 2 + text + + + + aFloat + 0.5 + aList + + A + B + 12 + 32.5 + + 1 + 2 + 3 + + + aString + Doodah + anInt + 728 + nestedData + + + PGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5r + PgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5 + IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBi + aW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3Rz + IG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQID + PGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAw== + + + someData + + PGJpbmFyeSBndW5rPg== + + someMoreData + + PGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8 + bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAzxs + b3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxv + dHMgb2YgYmluYXJ5IGd1bms+AAECAzxsb3RzIG9mIGJpbmFyeSBndW5rPgABAgM8bG90 + cyBvZiBiaW5hcnkgZ3Vuaz4AAQIDPGxvdHMgb2YgYmluYXJ5IGd1bms+AAECAw== + + \xc3\x85benraa + That was a unicode key. + + +""".replace(" " * 8, "\t") # Apple as well as plistlib.py output hard tabs + + class TestPlistlib(unittest.TestCase): def tearDown(self): @@ -14,28 +97,24 @@ pass def _create(self): - pl = plistlib.Dict( + pl = dict( aString="Doodah", - aList=["A", "B", 12, 32.1, [1, 2, 3]], - aFloat = 0.1, + aList=["A", "B", 12, 32.5, [1, 2, 3]], + aFloat = 0.5, anInt = 728, - aDict=plistlib.Dict( - anotherString="", + aDict=dict( + anotherString="", aUnicodeValue=u'M\xe4ssig, Ma\xdf', aTrueValue=True, aFalseValue=False, + deeperDict=dict(a=17, b=32.5, c=[1, 2, "text"]), ), someData = plistlib.Data(""), - someMoreData = plistlib.Data("" * 10), + someMoreData = plistlib.Data("\0\1\2\3" * 10), + nestedData = [plistlib.Data("\0\1\2\3" * 10)], + aDate = datetime.datetime(2004, 10, 26, 10, 33, 33), ) - pl['anotherInt'] = 42 - try: - from xml.utils.iso8601 import parse - import time - except ImportError: - pass - else: - pl['aDate'] = plistlib.Date(time.mktime(time.gmtime())) + pl[u'\xc5benraa'] = "That was a unicode key." return pl def test_create(self): @@ -49,6 +128,26 @@ pl2 = plistlib.readPlist(test_support.TESTFN) self.assertEqual(dict(pl), dict(pl2)) + def test_string(self): + pl = self._create() + data = plistlib.writePlistToString(pl) + pl2 = plistlib.readPlistFromString(data) + self.assertEqual(dict(pl), dict(pl2)) + data2 = plistlib.writePlistToString(pl2) + self.assertEqual(data, data2) + + def test_appleformatting(self): + pl = plistlib.readPlistFromString(TESTDATA) + data = plistlib.writePlistToString(pl) + self.assertEqual(data, TESTDATA, + "generated data was not identical to Apple's output") + + def test_appleformattingfromliteral(self): + pl = self._create() + pl2 = plistlib.readPlistFromString(TESTDATA) + self.assertEqual(dict(pl), dict(pl2), + "generated data was not identical to Apple's output") + def test_stringio(self): from StringIO import StringIO f = StringIO() From tim_one at users.sourceforge.net Tue Oct 26 16:38:50 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Tue Oct 26 16:38:53 2004 Subject: [Python-checkins] python/dist/src LICENSE,1.32,1.33 Message-ID: Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1160 Modified Files: LICENSE Log Message: In paragraph 1, changed Python software to this software ("Python") Index: LICENSE =================================================================== RCS file: /cvsroot/python/python/dist/src/LICENSE,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- LICENSE 23 Oct 2004 03:48:57 -0000 1.32 +++ LICENSE 26 Oct 2004 14:38:48 -0000 1.33 @@ -74,8 +74,8 @@ 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and -otherwise using Python software in source or binary form and its -associated documentation. +otherwise using this software ("Python") in source or binary form and +its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide From facundobatista at users.sourceforge.net Wed Oct 27 01:38:49 2004 From: facundobatista at users.sourceforge.net (facundobatista@users.sourceforge.net) Date: Wed Oct 27 01:38:53 2004 Subject: [Python-checkins] python/dist/src/Lib decimal.py,1.28,1.29 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4996 Modified Files: decimal.py Log Message: Very few little improvements. Index: decimal.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/decimal.py,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- decimal.py 20 Oct 2004 06:58:28 -0000 1.28 +++ decimal.py 26 Oct 2004 23:38:46 -0000 1.29 @@ -938,15 +938,13 @@ sign = 1 return Decimal( (sign, (0,), exp)) if not self: - if exp < other._exp - context.prec-1: - exp = other._exp - context.prec-1 + exp = max(exp, other._exp - context.prec-1) ans = other._rescale(exp, watchexp=0, context=context) if shouldround: ans = ans._fix(context) return ans if not other: - if exp < self._exp - context.prec-1: - exp = self._exp - context.prec-1 + exp = max(exp, self._exp - context.prec-1) ans = self._rescale(exp, watchexp=0, context=context) if shouldround: ans = ans._fix(context) @@ -1228,7 +1226,6 @@ if divmod and res.exp > context.prec + 1: return context._raise_error(DivisionImpossible) - ans = None prec_limit = 10 ** context.prec while 1: while op2.int <= op1.int: @@ -1454,24 +1451,25 @@ if context is None: context = getcontext() prec = context.prec - ans = self._fixexponents(prec, context) + ans = self._fixexponents(context) if len(ans._int) > prec: ans = ans._round(prec, context=context) - ans = ans._fixexponents(prec, context) + ans = ans._fixexponents(context) return ans - def _fixexponents(self, prec, context): + def _fixexponents(self, context): """Fix the exponents and return a copy with the exponent in bounds. Only call if known to not be a special value. """ folddown = context._clamp Emin = context.Emin - ans = Decimal(self) + ans = self ans_adjusted = ans.adjusted() if ans_adjusted < Emin: Etiny = context.Etiny() if ans._exp < Etiny: if not ans: + ans = Decimal(self) ans._exp = Etiny context._raise_error(Clamped) return ans @@ -1493,6 +1491,7 @@ Emax = context.Emax if ans_adjusted > Emax: if not ans: + ans = Decimal(self) ans._exp = Emax context._raise_error(Clamped) return ans @@ -1508,7 +1507,6 @@ context determines it. """ - if self._is_special: ans = self._check_nans(context=context) if ans: From gward at users.sourceforge.net Wed Oct 27 04:20:06 2004 From: gward at users.sourceforge.net (gward@users.sourceforge.net) Date: Wed Oct 27 04:20:09 2004 Subject: [Python-checkins] python/dist/src/Lib optparse.py,1.10,1.11 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12564/Lib Modified Files: optparse.py Log Message: Update optparse module and test suite to Optik 1.5a2. Index: optparse.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/optparse.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- optparse.py 17 Oct 2004 16:24:25 -0000 1.10 +++ optparse.py 27 Oct 2004 02:20:04 -0000 1.11 @@ -16,7 +16,7 @@ # Python developers: please do not make changes to this file, since # it is automatically generated from the Optik source code. -__version__ = "1.5a1" +__version__ = "1.5a2" __all__ = ['Option', 'SUPPRESS_HELP', @@ -76,10 +76,10 @@ # This file was generated from: -# Id: option_parser.py,v 1.67 2004/07/24 23:21:21 gward Exp -# Id: option.py,v 1.33 2004/07/24 23:21:21 gward Exp -# Id: help.py,v 1.15 2004/07/24 23:21:21 gward Exp -# Id: errors.py,v 1.9 2004/07/24 23:21:21 gward Exp +# Id: option_parser.py 421 2004-10-26 00:45:16Z greg +# Id: option.py 422 2004-10-26 00:53:47Z greg +# Id: help.py 367 2004-07-24 23:21:21Z gward +# Id: errors.py 367 2004-07-24 23:21:21Z gward class OptParseError (Exception): def __init__(self, msg): @@ -436,11 +436,16 @@ "count") # The set of actions for which it makes sense to supply a value - # type, ie. where we expect an argument to this option. + # type, ie. which may consume an argument from the command line. TYPED_ACTIONS = ("store", "append", "callback") + # The set of actions which *require* a value type, ie. that + # always consume an argument from the command line. + ALWAYS_TYPED_ACTIONS = ("store", + "append") + # The set of known types for option parsers. Again, listed here for # constructor argument validation. TYPES = ("string", "int", "long", "float", "complex", "choice") @@ -557,9 +562,7 @@ def _check_type(self): if self.type is None: - # XXX should factor out another class attr here: list of - # actions that *require* a type - if self.action in ("store", "append"): + if self.action in self.ALWAYS_TYPED_ACTIONS: if self.choices is not None: # The "choices" attribute implies "choice" type. self.type = "choice" @@ -723,10 +726,10 @@ self.callback(self, opt, value, parser, *args, **kwargs) elif action == "help": parser.print_help() - sys.exit(0) + parser.exit() elif action == "version": parser.print_version() - sys.exit(0) + parser.exit() else: raise RuntimeError, "unknown action %r" % self.action @@ -877,7 +880,7 @@ self.defaults = parser.defaults def set_conflict_handler(self, handler): - if handler not in ("ignore", "error", "resolve"): + if handler not in ("error", "resolve"): raise ValueError, "invalid conflict_resolution value %r" % handler self.conflict_handler = handler @@ -901,14 +904,12 @@ if conflict_opts: handler = self.conflict_handler - if handler == "ignore": # behaviour for Optik 1.0, 1.1 - pass - elif handler == "error": # new in 1.2 + if handler == "error": raise OptionConflictError( "conflicting option string(s): %s" % ", ".join([co[0] for co in conflict_opts]), option) - elif handler == "resolve": # new in 1.2 + elif handler == "resolve": for (opt, c_option) in conflict_opts: if opt.startswith("--"): c_option._long_opts.remove(opt) @@ -1442,6 +1443,11 @@ def get_description(self): return self.expand_prog_name(self.description) + def exit(self, status=0, msg=None): + if msg: + sys.stderr.write(msg) + sys.exit(status) + def error(self, msg): """error(msg : string) @@ -1450,8 +1456,7 @@ should either exit or raise an exception. """ self.print_usage(sys.stderr) - sys.stderr.write("%s: error: %s\n" % (self.get_prog_name(), msg)) - sys.exit(2) # command-line usage error + self.exit(2, "%s: error: %s\n" % (self.get_prog_name(), msg)) def get_usage(self): if self.usage: From gward at users.sourceforge.net Wed Oct 27 04:20:06 2004 From: gward at users.sourceforge.net (gward@users.sourceforge.net) Date: Wed Oct 27 04:20:12 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_optparse.py, 1.8, 1.9 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12564/Lib/test Modified Files: test_optparse.py Log Message: Update optparse module and test suite to Optik 1.5a2. Index: test_optparse.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_optparse.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- test_optparse.py 1 Sep 2004 13:10:32 -0000 1.8 +++ test_optparse.py 27 Oct 2004 02:20:04 -0000 1.9 @@ -17,10 +17,37 @@ from pprint import pprint from test import test_support -from optparse import (make_option, Option, IndentedHelpFormatter, - TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, - SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, - BadOptionError, OptionValueError, _match_abbrev) +from optparse import make_option, Option, IndentedHelpFormatter, \ + TitledHelpFormatter, OptionParser, OptionContainer, OptionGroup, \ + SUPPRESS_HELP, SUPPRESS_USAGE, OptionError, OptionConflictError, \ + BadOptionError, OptionValueError, Values, _match_abbrev + +# Do the right thing with boolean values for all known Python versions. +try: + True, False +except NameError: + (True, False) = (1, 0) + + +class InterceptedError(Exception): + def __init__(self, + error_message=None, + exit_status=None, + exit_message=None): + self.error_message = error_message + self.exit_status = exit_status + self.exit_message = exit_message + + def __str__(self): + return self.error_message or self.exit_message or "intercepted error" + +class InterceptingOptionParser(OptionParser): + def exit(self, status=0, msg=None): + raise InterceptedError(exit_status=status, exit_message=msg) + + def error(self, msg): + raise InterceptedError(error_message=msg) + class BaseTest(unittest.TestCase): def assertParseOK(self, args, expected_opts, expected_positional_args): @@ -58,12 +85,11 @@ args, kwargs, expected_exception, - expected_output, - get_output=None, - exact_match=False): - """Assert the expected exception is raised when calling a function. - - Also check whether the right error message is given for a given error. + expected_message): + """ + Assert that the expected exception is raised when calling a + function, and that the right error message is included with + that exception. Arguments: func -- the function to call @@ -71,9 +97,6 @@ kwargs -- keyword arguments to `func` expected_exception -- exception that should be raised expected_output -- output we expect to see - get_output -- function to call to get the output - exact_match -- whether output must exactly match expected output, - or merely contain it Returns the exception raised for further testing. """ @@ -81,25 +104,18 @@ args = () if kwargs is None: kwargs = {} - if get_output is None: - get_output = self.exception try: - out = func(*args, **kwargs) + func(*args, **kwargs) except expected_exception, err: - actual_output = get_output(err) - - if exact_match: - match = actual_output == expected_exception - else: - match = actual_output.find(expected_output) != -1 - - self.assert_(match, - """mismatched output -expected output: -'''%(expected_output)s''' -actual output: -'''%(actual_output)s''' + actual_message = str(err) + self.assertEqual(actual_message, + expected_message, + """\ +expected exception message: +'''%(expected_message)s''' +actual exception message: +'''%(actual_message)s''' """ % locals()) return err @@ -110,44 +126,46 @@ and kwargs %(kwargs)r """ % locals ()) - # -- Functions to be used as the get_output argument to assertRaises ------ - - def exception(self, err): - return str(err) - - def redirected_stdout(self, err): - return sys.stdout.getvalue() - - def redirected_stderr(self, err): - return sys.stderr.getvalue() # -- Assertions used in more than one class -------------------- def assertParseFail(self, cmdline_args, expected_output): - """Assert the parser fails with the expected message.""" - save_stderr = sys.stderr + """ + Assert the parser fails with the expected message. Caller + must ensure that self.parser is an InterceptingOptionParser. + """ try: - sys.stderr = StringIO() - self.assertRaises(self.parser.parse_args, (cmdline_args,), None, - SystemExit, expected_output, - self.redirected_stderr) - finally: - sys.stderr = save_stderr + self.parser.parse_args(cmdline_args) + except InterceptedError, err: + self.assertEqual(err.error_message, expected_output) + else: + self.assertFalse("expected parse failure") - def assertStdoutEquals(self, cmdline_args, expected_output): + def assertOutput(self, + cmdline_args, + expected_output, + expected_status=0, + expected_error=None): """Assert the parser prints the expected output on stdout.""" save_stdout = sys.stdout try: - sys.stdout = StringIO() - self.assertRaises(self.parser.parse_args, (cmdline_args,), None, - SystemExit, expected_output, - self.redirected_stdout) - finally: - sys.stdout = save_stdout + try: + sys.stdout = StringIO() + self.parser.parse_args(cmdline_args) + finally: + output = sys.stdout.getvalue() + sys.stdout = save_stdout - def assertTypeError(self, func, expected_output, *args): - """Assert a TypeError is raised when executing func.""" - self.assertRaises(func, args, None, TypeError, expected_output) + except InterceptedError, err: + self.assertEqual(output, expected_output) + self.assertEqual(err.exit_status, expected_status) + self.assertEqual(err.exit_message, expected_error) + else: + self.assertFalse("expected parser.exit()") + + def assertTypeError(self, func, expected_message, *args): + """Assert that TypeError is raised when executing func.""" + self.assertRaises(func, args, None, TypeError, expected_message) def assertHelp(self, parser, expected_help): actual_help = parser.format_help() @@ -159,120 +177,133 @@ # -- Test make_option() aka Option ------------------------------------- -# It's not necessary to test correct options here. All the tests in the +# It's not necessary to test correct options here. All the tests in the # parser.parse_args() section deal with those, because they're needed -# there. Duplication makes no sense to me. +# there. class TestOptionChecks(BaseTest): def setUp(self): self.parser = OptionParser(usage=SUPPRESS_USAGE) - def assertOptionError(self, expected_output, args=[], kwargs={}): + def assertOptionError(self, expected_message, args=[], kwargs={}): self.assertRaises(make_option, args, kwargs, - OptionError, expected_output) + OptionError, expected_message) def test_opt_string_empty(self): self.assertTypeError(make_option, "at least one option string must be supplied") def test_opt_string_too_short(self): - self.assertOptionError("invalid option string 'b': " - "must be at least two characters long", - ["b"]) + self.assertOptionError( + "invalid option string 'b': must be at least two characters long", + ["b"]) def test_opt_string_short_invalid(self): - self.assertOptionError("invalid short option string '--': must be " - "of the form -x, (x any non-dash char)", - ["--"]) + self.assertOptionError( + "invalid short option string '--': must be " + "of the form -x, (x any non-dash char)", + ["--"]) def test_opt_string_long_invalid(self): - self.assertOptionError("invalid long option string '---': " - "must start with --, followed by non-dash", - ["---"]) + self.assertOptionError( + "invalid long option string '---': " + "must start with --, followed by non-dash", + ["---"]) def test_attr_invalid(self): - self.assertOptionError("invalid keyword arguments: foo, bar", - ["-b"], {'foo': None, 'bar': None}) + self.assertOptionError( + "option -b: invalid keyword arguments: foo, bar", + ["-b"], {'foo': None, 'bar': None}) def test_action_invalid(self): - self.assertOptionError("invalid action: 'foo'", - ["-b"], {'action': 'foo'}) + self.assertOptionError( + "option -b: invalid action: 'foo'", + ["-b"], {'action': 'foo'}) def test_type_invalid(self): - self.assertOptionError("invalid option type: 'foo'", - ["-b"], {'type': 'foo'}) - self.assertOptionError("invalid option type: 'tuple'", - ["-b"], {'type': tuple}) + self.assertOptionError( + "option -b: invalid option type: 'foo'", + ["-b"], {'type': 'foo'}) + self.assertOptionError( + "option -b: invalid option type: 'tuple'", + ["-b"], {'type': tuple}) def test_no_type_for_action(self): - self.assertOptionError("must not supply a type for action 'count'", - ["-b"], {'action': 'count', 'type': 'int'}) + self.assertOptionError( + "option -b: must not supply a type for action 'count'", + ["-b"], {'action': 'count', 'type': 'int'}) def test_no_choices_list(self): - self.assertOptionError("must supply a list of " - "choices for type 'choice'", - ["-b", "--bad"], {'type': "choice"}) + self.assertOptionError( + "option -b/--bad: must supply a list of " + "choices for type 'choice'", + ["-b", "--bad"], {'type': "choice"}) def test_bad_choices_list(self): typename = type('').__name__ - self.assertOptionError("choices must be a list of " - "strings ('%s' supplied)" % typename, - ["-b", "--bad"], - {'type': "choice", 'choices':"bad choices"}) + self.assertOptionError( + "option -b/--bad: choices must be a list of " + "strings ('%s' supplied)" % typename, + ["-b", "--bad"], + {'type': "choice", 'choices':"bad choices"}) def test_no_choices_for_type(self): - self.assertOptionError("must not supply choices for type 'int'", - ["-b"], {'type': 'int', 'choices':"bad"}) + self.assertOptionError( + "option -b: must not supply choices for type 'int'", + ["-b"], {'type': 'int', 'choices':"bad"}) def test_no_const_for_action(self): - self.assertOptionError("'const' must not be supplied for action " - "'store'", - ["-b"], {'action': 'store', 'const': 1}) + self.assertOptionError( + "option -b: 'const' must not be supplied for action 'store'", + ["-b"], {'action': 'store', 'const': 1}) def test_no_nargs_for_action(self): - self.assertOptionError("'nargs' must not be supplied for action " - "'count'", - ["-b"], {'action': 'count', 'nargs': 2}) + self.assertOptionError( + "option -b: 'nargs' must not be supplied for action 'count'", + ["-b"], {'action': 'count', 'nargs': 2}) def test_callback_not_callable(self): - self.assertOptionError("callback not callable: 'foo'", - ["-b"], {'action': 'callback', - 'callback': 'foo'}) + self.assertOptionError( + "option -b: callback not callable: 'foo'", + ["-b"], {'action': 'callback', + 'callback': 'foo'}) def dummy(self): pass def test_callback_args_no_tuple(self): - self.assertOptionError("callback_args, if supplied, must be a tuple: " - "not 'foo'", - ["-b"], {'action': 'callback', - 'callback': self.dummy, - 'callback_args': 'foo'}) + self.assertOptionError( + "option -b: callback_args, if supplied, " + "must be a tuple: not 'foo'", + ["-b"], {'action': 'callback', + 'callback': self.dummy, + 'callback_args': 'foo'}) def test_callback_kwargs_no_dict(self): - self.assertOptionError("callback_kwargs, if supplied, must be a dict: " - "not 'foo'", - ["-b"], {'action': 'callback', - 'callback': self.dummy, - 'callback_kwargs': 'foo'}) + self.assertOptionError( + "option -b: callback_kwargs, if supplied, " + "must be a dict: not 'foo'", + ["-b"], {'action': 'callback', + 'callback': self.dummy, + 'callback_kwargs': 'foo'}) def test_no_callback_for_action(self): - self.assertOptionError("callback supplied ('foo') for " - "non-callback option", - ["-b"], {'action': 'store', - 'callback': 'foo'}) + self.assertOptionError( + "option -b: callback supplied ('foo') for non-callback option", + ["-b"], {'action': 'store', + 'callback': 'foo'}) def test_no_callback_args_for_action(self): - self.assertOptionError("callback_args supplied for non-callback " - "option", - ["-b"], {'action': 'store', - 'callback_args': 'foo'}) + self.assertOptionError( + "option -b: callback_args supplied for non-callback option", + ["-b"], {'action': 'store', + 'callback_args': 'foo'}) def test_no_callback_kwargs_for_action(self): - self.assertOptionError("callback_kwargs supplied for non-callback " - "option", - ["-b"], {'action': 'store', - 'callback_kwargs': 'foo'}) + self.assertOptionError( + "option -b: callback_kwargs supplied for non-callback option", + ["-b"], {'action': 'store', + 'callback_kwargs': 'foo'}) class TestOptionParser(BaseTest): def setUp(self): @@ -335,6 +366,27 @@ self.assertRaises(self.parser.remove_option, ('foo',), None, ValueError, "no such option 'foo'") +class TestOptionValues(BaseTest): + def setUp(self): + pass + + def test_basics(self): + values = Values() + self.assertEqual(vars(values), {}) + self.assertEqual(values, {}) + self.assertNotEqual(values, {"foo": "bar"}) + self.assertNotEqual(values, "") + + dict = {"foo": "bar", "baz": 42} + values = Values(defaults=dict) + self.assertEqual(vars(values), dict) + self.assertEqual(values, dict) + self.assertNotEqual(values, {"foo": "bar"}) + self.assertNotEqual(values, {}) + self.assertNotEqual(values, "") + self.assertNotEqual(values, []) + + class TestTypeAliases(BaseTest): def setUp(self): self.parser = OptionParser() @@ -346,7 +398,7 @@ self.assertEquals(self.parser.get_option("-x").type, "int") self.assertEquals(self.parser.get_option("-s").type, "string") self.assertEquals(self.parser.get_option("-t").type, "string") - + # Custom type for testing processing of default values. _time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 } @@ -434,17 +486,16 @@ # Make sure that program name taken from sys.argv[0] by default. save_argv = sys.argv[:] try: - # XXX Should the path be hard-coding forward-slashes? - sys.argv[0] = "/foo/bar/baz.py" + sys.argv[0] = os.path.join("foo", "bar", "baz.py") parser = OptionParser("usage: %prog ...", version="%prog 1.2") expected_usage = "usage: baz.py ...\n" self.assertUsage(parser, expected_usage) self.assertVersion(parser, "baz.py 1.2") self.assertHelp(parser, - expected_usage + "\n" + - "options:\n" - " --version show program's version number and exit\n" - " -h, --help show this help message and exit\n") + expected_usage + "\n" + + "options:\n" + " --version show program's version number and exit\n" + " -h, --help show this help message and exit\n") finally: sys.argv[:] = save_argv @@ -503,7 +554,7 @@ default=None, help=self.file_help) self.assertHelp(self.parser, self.expected_help_none) - + def test_default_none_2(self): self.parser.add_option("-f", "--file", help=self.file_help) @@ -544,7 +595,8 @@ make_option("-b", "--boo", type="int", dest='boo'), make_option("--foo", action="append")] - self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + option_list=options) def test_required_value(self): self.assertParseFail(["-a"], "-a option requires an argument") @@ -707,7 +759,7 @@ class TestChoice(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.parser.add_option("-c", action="store", type="choice", dest="choice", choices=["one", "two", "three"]) @@ -730,7 +782,7 @@ class TestCount(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.v_opt = make_option("-v", action="count", dest="verbose") self.parser.add_option(self.v_opt) self.parser.add_option("--verbose", type="int", dest="verbose") @@ -786,9 +838,9 @@ self.assertParseOK(["-vvv", "--verbose=2", "-q", "-v"], {'verbose': 1}, []) -class TestNArgs(BaseTest): +class TestMultipleArgs(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.parser.add_option("-p", "--point", action="store", nargs=3, type="float", dest="point") @@ -811,9 +863,9 @@ self.assertParseFail(["--point", "1.0", "3.5"], "--point option requires 3 arguments") -class TestNArgsAppend(BaseTest): +class TestMultipleArgsAppend(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.parser.add_option("-p", "--point", action="store", nargs=3, type="float", dest="point") self.parser.add_option("-f", "--foo", action="append", nargs=2, @@ -835,14 +887,17 @@ class TestVersion(BaseTest): def test_version(self): - oldargv = sys.argv[0] - sys.argv[0] = "./foo/bar" - self.parser = OptionParser(usage=SUPPRESS_USAGE, version="%prog 0.1") - self.assertStdoutEquals(["--version"], "bar 0.1\n") - sys.argv[0] = oldargv + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + version="%prog 0.1") + save_argv = sys.argv[:] + try: + sys.argv[0] = os.path.join(os.curdir, "foo", "bar") + self.assertOutput(["--version"], "bar 0.1\n") + finally: + sys.argv[:] = save_argv def test_no_version(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.assertParseFail(["--version"], "no such option: --version") @@ -900,8 +955,8 @@ class TestExtendAddTypes(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE, - option_class=self.MyOption) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + option_class=self.MyOption) self.parser.add_option("-a", None, type="string", dest="a") self.parser.add_option("-f", "--file", type="file", dest="file") @@ -1119,7 +1174,8 @@ make_option("-b", action="store_true", dest="b"), make_option("-c", "--callback", action="callback", callback=self.variable_args, dest="c")] - self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + option_list=options) def variable_args (self, option, opt, value, parser): self.assert_(value is None) @@ -1170,7 +1226,8 @@ def setUp(self): options = [make_option("-v", "--verbose", action="count", dest="verbose", help="increment verbosity")] - self.parser = OptionParser(usage=SUPPRESS_USAGE, option_list=options) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE, + option_list=options) def show_version (self, option, opt, value, parser): parser.values.show_version = 1 @@ -1201,41 +1258,6 @@ ValueError, "invalid conflict_resolution value 'foo'") -class TestConflictIgnore(ConflictBase): - """Test the old (Optik <= 1.1 behaviour) -- arguably broken, but - still available so should be tested. - """ - - def setUp(self): - ConflictBase.setUp(self) - self.parser.set_conflict_handler("ignore") - self.parser.add_option("-v", "--version", action="callback", - callback=self.show_version, help="show version") - - def test_conflict_ignore(self): - v_opt = self.parser.get_option("-v") - verbose_opt = self.parser.get_option("--verbose") - version_opt = self.parser.get_option("--version") - - self.assert_(v_opt is version_opt) - self.assert_(v_opt is not verbose_opt) - self.assertEqual(v_opt._long_opts, ["--version"]) - self.assertEqual(version_opt._short_opts, ["-v"]) - self.assertEqual(verbose_opt._short_opts, ["-v"]) - - def test_conflict_ignore_help(self): - self.assertStdoutEquals(["-h"], """\ -options: - -v, --verbose increment verbosity - -h, --help show this help message and exit - -v, --version show version -""") - - def test_conflict_ignore_short_opt(self): - self.assertParseOK(["-v"], - {'show_version': 1, 'verbose': None}, - []) - class TestConflictResolve(ConflictBase): def setUp(self): ConflictBase.setUp(self) @@ -1257,7 +1279,7 @@ self.assertEqual(verbose_opt._long_opts, ["--verbose"]) def test_conflict_resolve_help(self): - self.assertStdoutEquals(["-h"], """\ + self.assertOutput(["-h"], """\ options: --verbose increment verbosity -h, --help show this help message and exit @@ -1281,7 +1303,7 @@ class TestConflictOverride(BaseTest): def setUp(self): - self.parser = OptionParser(usage=SUPPRESS_USAGE) + self.parser = InterceptingOptionParser(usage=SUPPRESS_USAGE) self.parser.set_conflict_handler("resolve") self.parser.add_option("-n", "--dry-run", action="store_true", dest="dry_run", @@ -1296,7 +1318,7 @@ self.assertEqual(opt._long_opts, ["--dry-run"]) def test_conflict_override_help(self): - self.assertStdoutEquals(["-h"], """\ + self.assertOutput(["-h"], """\ options: -h, --help show this help message and exit -n, --dry-run dry run mode @@ -1375,16 +1397,16 @@ help="store FOO in the foo list for later fooing"), ] os.environ['COLUMNS'] = str(columns) - return OptionParser(option_list=options) + return InterceptingOptionParser(option_list=options) def assertHelpEquals(self, expected_output): - # This trick is used to make optparse believe bar.py is being executed. - oldargv = sys.argv[0] - sys.argv[0] = "./foo/bar.py" - - self.assertStdoutEquals(["-h"], expected_output) - - sys.argv[0] = oldargv + save_argv = sys.argv[:] + try: + # Make optparse believe bar.py is being executed. + sys.argv[0] = os.path.join("foo", "bar.py") + self.assertOutput(["-h"], expected_output) + finally: + sys.argv[:] = save_argv def test_help(self): self.assertHelpEquals(_expected_help_basic) @@ -1441,7 +1463,7 @@ """) - + class TestMatchAbbrev(BaseTest): def test_match_abbrev(self): From tim_one at users.sourceforge.net Wed Oct 27 04:33:18 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 27 04:33:21 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_traceback.py, 1.8, 1.9 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15020/Lib/test Modified Files: test_traceback.py Log Message: Paper over bug 1054615 by passing sane values to os.utime(). The underlying bug still exists, but also existed in 2.3.4: import.c's load_source_module() returns NULL if PyOS_GetLastModificationTime() returns -1, but PyOS_GetLastModificationTime() doesn't set any exception when it returns -1, and neither does load_source_module() when it gets back -1. This leads to "SystemError: NULL result without error in PyObject_Call" on an import that fails in this way. Index: test_traceback.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_traceback.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- test_traceback.py 26 Oct 2004 09:16:41 -0000 1.8 +++ test_traceback.py 27 Oct 2004 02:33:15 -0000 1.9 @@ -41,7 +41,8 @@ self.assert_(err[1].strip() == "[x for x in x] = x") def test_bug737473(self): - import sys, os, tempfile + import sys, os, tempfile, time + savedpath = sys.path[:] testdir = tempfile.mkdtemp() try: @@ -51,8 +52,10 @@ def test(): raise ValueError""" + # XXX Unclear why we're doing this next bit. if hasattr(os, 'utime'): - os.utime(testfile, (0, 0)) + past = time.time() - 3 + os.utime(testfile, (past, past)) else: import time time.sleep(3) # not to stay in same mtime. From tim_one at users.sourceforge.net Wed Oct 27 04:43:27 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 27 04:43:30 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_optparse.py, 1.9, 1.10 test_traceback.py, 1.9, 1.10 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17603/Lib/test Modified Files: test_optparse.py test_traceback.py Log Message: Whitespace normalization. Index: test_optparse.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_optparse.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- test_optparse.py 27 Oct 2004 02:20:04 -0000 1.9 +++ test_optparse.py 27 Oct 2004 02:43:25 -0000 1.10 @@ -398,7 +398,7 @@ self.assertEquals(self.parser.get_option("-x").type, "int") self.assertEquals(self.parser.get_option("-s").type, "string") self.assertEquals(self.parser.get_option("-t").type, "string") - + # Custom type for testing processing of default values. _time_units = { 's' : 1, 'm' : 60, 'h' : 60*60, 'd' : 60*60*24 } @@ -554,7 +554,7 @@ default=None, help=self.file_help) self.assertHelp(self.parser, self.expected_help_none) - + def test_default_none_2(self): self.parser.add_option("-f", "--file", help=self.file_help) @@ -1397,7 +1397,7 @@ help="store FOO in the foo list for later fooing"), ] os.environ['COLUMNS'] = str(columns) - return InterceptingOptionParser(option_list=options) + return InterceptingOptionParser(option_list=options) def assertHelpEquals(self, expected_output): save_argv = sys.argv[:] @@ -1463,7 +1463,7 @@ """) - + class TestMatchAbbrev(BaseTest): def test_match_abbrev(self): Index: test_traceback.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_traceback.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- test_traceback.py 27 Oct 2004 02:33:15 -0000 1.9 +++ test_traceback.py 27 Oct 2004 02:43:25 -0000 1.10 @@ -67,7 +67,7 @@ try: test_bug737473.test() except ValueError: - # this loads source code to linecache + # this loads source code to linecache traceback.extract_tb(sys.exc_traceback) print >> open(testfile, 'w'), """\ From tim_one at users.sourceforge.net Wed Oct 27 04:44:12 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed Oct 27 04:44:15 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_traceback.py, 1.10, 1.11 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17755/Lib/test Modified Files: test_traceback.py Log Message: Removed newly redundant embedded import. Index: test_traceback.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_traceback.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- test_traceback.py 27 Oct 2004 02:43:25 -0000 1.10 +++ test_traceback.py 27 Oct 2004 02:44:10 -0000 1.11 @@ -57,7 +57,6 @@ past = time.time() - 3 os.utime(testfile, (past, past)) else: - import time time.sleep(3) # not to stay in same mtime. if 'test_bug737473' in sys.modules: From perky at users.sourceforge.net Wed Oct 27 05:12:08 2004 From: perky at users.sourceforge.net (perky@users.sourceforge.net) Date: Wed Oct 27 05:12:10 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_traceback.py, 1.11, 1.12 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23936/Lib/test Modified Files: test_traceback.py Log Message: Add a comment explains why we should modify mtime here. Index: test_traceback.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_traceback.py,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- test_traceback.py 27 Oct 2004 02:44:10 -0000 1.11 +++ test_traceback.py 27 Oct 2004 03:12:05 -0000 1.12 @@ -52,12 +52,14 @@ def test(): raise ValueError""" - # XXX Unclear why we're doing this next bit. + # if this test runs fast, test_bug737473.py will have same mtime + # even if it's rewrited and it'll not reloaded. so adjust mtime + # of original to past. if hasattr(os, 'utime'): past = time.time() - 3 os.utime(testfile, (past, past)) else: - time.sleep(3) # not to stay in same mtime. + time.sleep(3) if 'test_bug737473' in sys.modules: del sys.modules['test_bug737473'] From rhettinger at users.sourceforge.net Wed Oct 27 08:21:49 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed Oct 27 08:21:52 2004 Subject: [Python-checkins] python/dist/src/Lib decimal.py,1.29,1.30 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27107 Modified Files: decimal.py Log Message: SF patch #1053375. (Contributed by Facundo Batista.) Code simplification by eliminating the unnecessary and error-prone convolutions for the previously weird sign convention in _WorkRep(). Makes the code more understandable, more reliable, and a bit faster. Index: decimal.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/decimal.py,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- decimal.py 26 Oct 2004 23:38:46 -0000 1.29 +++ decimal.py 27 Oct 2004 06:21:46 -0000 1.30 @@ -477,10 +477,7 @@ # From an internal working value if isinstance(value, _WorkRep): - if value.sign == 1: - self._sign = 0 - else: - self._sign = 1 + self._sign = value.sign self._int = tuple(map(int, str(value.int))) self._exp = int(value.exp) return self @@ -955,32 +952,30 @@ op1, op2 = _normalize(op1, op2, shouldround, context.prec) result = _WorkRep() - if op1.sign != op2.sign: - diff = cmp(abs(op1), abs(op2)) # Equal and opposite - if diff == 0: + if op1.int == op2.int: if exp < context.Etiny(): exp = context.Etiny() context._raise_error(Clamped) return Decimal((negativezero, (0,), exp)) - if diff < 0: + if op1.int < op2.int: op1, op2 = op2, op1 #OK, now abs(op1) > abs(op2) - if op1.sign == -1: - result.sign = -1 + if op1.sign == 1: + result.sign = 1 op1.sign, op2.sign = op2.sign, op1.sign else: - result.sign = 1 + result.sign = 0 #So we know the sign, and op1 > 0. - elif op1.sign == -1: - result.sign = -1 - op1.sign, op2.sign = (1, 1) - else: + elif op1.sign == 1: result.sign = 1 + op1.sign, op2.sign = (0, 0) + else: + result.sign = 0 #Now, op1 > abs(op2) > 0 - if op2.sign == 1: + if op2.sign == 0: result.int = op1.int + op2.int else: result.int = op1.int - op2.int @@ -1214,11 +1209,6 @@ #Don't round the mod part, if we don't need it. return (Decimal( (sign, (0,), 0) ), Decimal(self)) - if sign: - sign = -1 - else: - sign = 1 - adjust = 0 op1 = _WorkRep(self) op2 = _WorkRep(other) op1, op2, adjust = _adjust_coefficients(op1, op2) @@ -1238,8 +1228,7 @@ frozen = context._ignore_all_flags() exp = min(self._exp, other._exp) - otherside = otherside._rescale(exp, context=context, - watchexp=0) + otherside = otherside._rescale(exp, context=context, watchexp=0) context._regard_flags(*frozen) if shouldround: otherside = otherside._fix(context) @@ -2769,7 +2758,7 @@ class _WorkRep(object): __slots__ = ('sign','int','exp') - # sign: -1 None 1 + # sign: 0 or 1 # int: int or long # exp: None, int, or string @@ -2778,17 +2767,15 @@ self.sign = None self.int = 0 self.exp = None - if isinstance(value, Decimal): - if value._sign: - self.sign = -1 - else: - self.sign = 1 + elif isinstance(value, Decimal): + self.sign = value._sign cum = 0 - for digit in value._int: + for digit in value._int: cum = cum * 10 + digit self.int = cum self.exp = value._exp - if isinstance(value, tuple): + else: + # assert isinstance(value, tuple) self.sign = value[0] self.int = value[1] self.exp = value[2] @@ -2798,38 +2785,6 @@ __str__ = __repr__ - def __neg__(self): - if self.sign == 1: - return _WorkRep( (-1, self.int, self.exp) ) - else: - return _WorkRep( (1, self.int, self.exp) ) - - def __abs__(self): - if self.sign == -1: - return -self - else: - return self - - def __cmp__(self, other): - if self.exp != other.exp: - raise ValueError("Operands not normalized: %r, %r" % (self, other)) - if self.sign != other.sign: - if self.sign == -1: - return -1 - else: - return 1 - if self.sign == -1: - direction = -1 - else: - direction = 1 - int1 = self.int - int2 = other.int - if int1 > int2: - return direction * 1 - if int1 < int2: - return direction * -1 - return 0 - def _normalize(op1, op2, shouldround = 0, prec = 0): From vsajip at users.sourceforge.net Wed Oct 27 12:09:57 2004 From: vsajip at users.sourceforge.net (vsajip@users.sourceforge.net) Date: Wed Oct 27 12:10:00 2004 Subject: [Python-checkins] python/nondist/peps pep-0000.txt,1.292,1.293 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8267 Modified Files: pep-0000.txt Log Message: Updated PEP282 status in numerical list Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.292 retrieving revision 1.293 diff -u -d -r1.292 -r1.293 --- pep-0000.txt 8 Oct 2004 13:03:22 -0000 1.292 +++ pep-0000.txt 27 Oct 2004 10:09:55 -0000 1.293 @@ -313,7 +313,7 @@ SF 279 The enumerate() built-in function Hettinger S 280 Optimizing access to globals GvR S 281 Loop Counter Iteration with range and xrange Hetland - S 282 A Logging System Sajip, Mick + SF 282 A Logging System Sajip, Mick IF 283 Python 2.3 Release Schedule GvR S 284 Integer for-loops Eppstein, Ewing SF 285 Adding a bool type GvR From anthonybaxter at users.sourceforge.net Wed Oct 27 13:53:07 2004 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Wed Oct 27 13:53:11 2004 Subject: [Python-checkins] python/nondist/peps pep-0320.txt,1.18,1.19 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2375 Modified Files: pep-0320.txt Log Message: updates post beta1 Index: pep-0320.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0320.txt,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- pep-0320.txt 16 Sep 2004 16:04:53 -0000 1.18 +++ pep-0320.txt 27 Oct 2004 11:53:05 -0000 1.19 @@ -33,7 +33,13 @@ Sept 3: alpha 3 [completed] - October 11/12: beta 1 [scheduled] + October 15: beta 1 [completed] + + November 3: beta 2 [scheduled] + + November 18: release candidate 1 [scheduled] + + November 30: final [scheduled] Completed features for 2.4 @@ -64,27 +70,22 @@ to the heapq module. Python's windows installer now uses MSI - -Planned features for 2.4 - - These features are all planned for 2.4b1, but have not yet landed. - - Deprecate and/or remove the modules listed in PEP 4 (posixfile, - gopherlib, pre, others) +Deferred until 2.5: - Remove support for platforms as described in PEP 11. + - Deprecate and/or remove the modules listed in PEP 4 (posixfile, + gopherlib, pre, others) - Finish implementing the Distutils bdist_dpkg command. (AMK) + - Remove support for platforms as described in PEP 11. - Add support for reading shadow passwords (www.python.org/sf/579435) + - Finish implementing the Distutils bdist_dpkg command. (AMK) - It would be nice if the built-in SSL socket type could be used - for non-blocking SSL I/O. Currently packages such as Twisted - which implement async servers using SSL have to require third-party - packages such as pyopenssl. + - Add support for reading shadow passwords (www.python.org/sf/579435) -Deferred until 2.5: + - It would be nice if the built-in SSL socket type could be used + for non-blocking SSL I/O. Currently packages such as Twisted + which implement async servers using SSL have to require third-party + packages such as pyopenssl. - AST-based compiler: this branch was not completed in time for 2.4, but will land on the trunk some time after 2.4 final is From mhammond at users.sourceforge.net Wed Oct 27 23:54:38 2004 From: mhammond at users.sourceforge.net (mhammond@users.sourceforge.net) Date: Wed Oct 27 23:54:42 2004 Subject: [Python-checkins] python/dist/src/Lib/distutils/command bdist_wininst.py, 1.54, 1.55 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/distutils/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27700 Modified Files: bdist_wininst.py Log Message: Fix [1055540 ] bdist_wininst broken for pure Python distributions Index: bdist_wininst.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/command/bdist_wininst.py,v retrieving revision 1.54 retrieving revision 1.55 diff -u -d -r1.54 -r1.55 --- bdist_wininst.py 17 Aug 2004 10:15:07 -0000 1.54 +++ bdist_wininst.py 27 Oct 2004 21:54:33 -0000 1.55 @@ -116,20 +116,21 @@ install_lib.compile = 0 install_lib.optimize = 0 - # If we are building an installer for a Python version other - # than the one we are currently running, then we need to ensure - # our build_lib reflects the other Python version rather than ours. - # Note that for target_version!=sys.version, we must have skipped the - # build step, so there is no issue with enforcing the build of this - # version. - target_version = self.target_version - if not target_version: - assert self.skip_build, "Should have already checked this" - target_version = sys.version[0:3] - plat_specifier = ".%s-%s" % (get_platform(), target_version) - build = self.get_finalized_command('build') - build.build_lib = os.path.join(build.build_base, - 'lib' + plat_specifier) + if self.distribution.has_ext_modules(): + # If we are building an installer for a Python version other + # than the one we are currently running, then we need to ensure + # our build_lib reflects the other Python version rather than ours. + # Note that for target_version!=sys.version, we must have skipped the + # build step, so there is no issue with enforcing the build of this + # version. + target_version = self.target_version + if not target_version: + assert self.skip_build, "Should have already checked this" + target_version = sys.version[0:3] + plat_specifier = ".%s-%s" % (get_platform(), target_version) + build = self.get_finalized_command('build') + build.build_lib = os.path.join(build.build_base, + 'lib' + plat_specifier) # Use a custom scheme for the zip-file, because we have to decide # at installation time which scheme to use. From bcannon at users.sourceforge.net Thu Oct 28 06:49:23 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Thu Oct 28 06:49:27 2004 Subject: [Python-checkins] python/dist/src/Lib _strptime.py,1.37,1.38 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31683/Lib Modified Files: _strptime.py Log Message: Fix bug of implementation of algorithm for calculating the date from year, week of the year, and day of the week. Was not taking into consideration properly the issue of when %U is used for the week of the year but the year starts on Monday. Closes bug #1045381 again. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.37 retrieving revision 1.38 diff -u -d -r1.37 -r1.38 --- _strptime.py 18 Oct 2004 01:47:46 -0000 1.37 +++ _strptime.py 28 Oct 2004 04:49:19 -0000 1.38 @@ -391,25 +391,27 @@ # If we know the week of the year and what day of that week, we can figure # out the Julian day of the year # Calculations below assume 0 is a Monday - if julian == -1 and week_of_year != -1 and weekday != -1 and year != -1: - # Adjust for U directive so that calculations are not dependent on - # directive used to figure out week of year - if weekday == 6 and week_of_year_start == 6: - week_of_year -= 1 - # For some reason when Dec 31 falls on a Monday the week of the year is - # off by a week; verified on both OS X and Solaris. - elif weekday == 0 and week_of_year_start == 6 and week_of_year >= 52: - week_of_year += 1 + if julian == -1 and week_of_year != -1 and weekday != -1: # Calculate how many days in week 0 first_weekday = datetime_date(year, 1, 1).weekday() preceeding_days = 7 - first_weekday if preceeding_days == 7: preceeding_days = 0 + # Adjust for U directive so that calculations are not dependent on + # directive used to figure out week of year + if weekday == 6 and week_of_year_start == 6: + week_of_year -= 1 + # If a year starts and ends on a Monday but a week is specified to + # start on a Sunday we need to up the week to counter-balance the fact + # that with %W that first Monday starts week 1 while with %U that is + # week 0 and thus shifts everything by a week + if weekday == 0 and first_weekday == 0 and week_of_year_start == 6: + week_of_year += 1 # If in week 0, then just figure out how many days from Jan 1 to day of # week specified, else calculate by multiplying week of year by 7, # adding in days in week 0, and the number of days from Monday to the # day of the week - if not week_of_year: + if week_of_year == 0: julian = 1 + weekday - first_weekday else: days_to_week = preceeding_days + (7 * (week_of_year - 1)) From bcannon at users.sourceforge.net Thu Oct 28 06:49:24 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Thu Oct 28 06:49:28 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_strptime.py, 1.28, 1.29 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31683/Lib/test Modified Files: test_strptime.py Log Message: Fix bug of implementation of algorithm for calculating the date from year, week of the year, and day of the week. Was not taking into consideration properly the issue of when %U is used for the week of the year but the year starts on Monday. Closes bug #1045381 again. Index: test_strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_strptime.py,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- test_strptime.py 18 Oct 2004 01:37:57 -0000 1.28 +++ test_strptime.py 28 Oct 2004 04:49:21 -0000 1.29 @@ -424,20 +424,35 @@ def test_helper(ymd_tuple, test_reason): for directive in ('W', 'U'): format_string = "%%Y %%%s %%w" % directive - strp_input = datetime_date(*ymd_tuple).strftime(format_string) + dt_date = datetime_date(*ymd_tuple) + strp_input = dt_date.strftime(format_string) strp_output = _strptime.strptime(strp_input, format_string) self.failUnless(strp_output[:3] == ymd_tuple, - "%s(%s) test failed w/ '%s': %s != %s" % + "%s(%s) test failed w/ '%s': %s != %s (%s != %s)" % (test_reason, directive, strp_input, - strp_output[:3], ymd_tuple[:3])) + strp_output[:3], ymd_tuple, + strp_output[7], dt_date.timetuple()[7])) test_helper((1901, 1, 3), "week 0") test_helper((1901, 1, 8), "common case") test_helper((1901, 1, 13), "day on Sunday") test_helper((1901, 1, 14), "day on Monday") test_helper((1905, 1, 1), "Jan 1 on Sunday") test_helper((1906, 1, 1), "Jan 1 on Monday") + test_helper((1906, 1, 7), "first Sunday in a year starting on Monday") test_helper((1905, 12, 31), "Dec 31 on Sunday") test_helper((1906, 12, 31), "Dec 31 on Monday") + test_helper((2008, 12, 29), "Monday in the last week of the year") + test_helper((2008, 12, 22), "Monday in the second-to-last week of the " + "year") + test_helper((1978, 10, 23), "randomly chosen date") + test_helper((2004, 12, 18), "randomly chosen date") + test_helper((1978, 10, 23), "year starting and ending on Monday while " + "date not on Sunday or Monday") + test_helper((1917, 12, 17), "year starting and ending on Monday with " + "a Monday not at the beginning or end " + "of the year") + test_helper((1917, 12, 31), "Dec 31 on Monday with year starting and " + "ending on Monday") class CacheTests(unittest.TestCase): From bcannon at users.sourceforge.net Thu Oct 28 06:50:30 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Thu Oct 28 06:50:33 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_strptime.py, 1.19.4.5, 1.19.4.6 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32106/Lib/test Modified Files: Tag: release23-maint test_strptime.py Log Message: Backport of fix for bug of year// calculation that didn't handle %U for years starting on Monday. Index: test_strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_strptime.py,v retrieving revision 1.19.4.5 retrieving revision 1.19.4.6 diff -u -d -r1.19.4.5 -r1.19.4.6 --- test_strptime.py 18 Oct 2004 01:56:16 -0000 1.19.4.5 +++ test_strptime.py 28 Oct 2004 04:50:28 -0000 1.19.4.6 @@ -457,21 +457,35 @@ def test_helper(ymd_tuple, test_reason): for directive in ('W', 'U'): format_string = "%%Y %%%s %%w" % directive - strp_input = datetime_date(*ymd_tuple).strftime(format_string) + dt_date = datetime_date(*ymd_tuple) + strp_input = dt_date.strftime(format_string) strp_output = _strptime.strptime(strp_input, format_string) self.failUnless(strp_output[:3] == ymd_tuple, - "%s(%s) test failed w/ '%s': %s != %s" % + "%s(%s) test failed w/ '%s': %s != %s (%s != %s)" % (test_reason, directive, strp_input, - strp_output[:3], ymd_tuple[:3])) + strp_output[:3], ymd_tuple, + strp_output[7], dt_date.timetuple()[7])) test_helper((1901, 1, 3), "week 0") test_helper((1901, 1, 8), "common case") test_helper((1901, 1, 13), "day on Sunday") test_helper((1901, 1, 14), "day on Monday") test_helper((1905, 1, 1), "Jan 1 on Sunday") test_helper((1906, 1, 1), "Jan 1 on Monday") + test_helper((1906, 1, 7), "first Sunday in a year starting on Monday") test_helper((1905, 12, 31), "Dec 31 on Sunday") test_helper((1906, 12, 31), "Dec 31 on Monday") - + test_helper((2008, 12, 29), "Monday in the last week of the year") + test_helper((2008, 12, 22), "Monday in the second-to-last week of the " + "year") + test_helper((1978, 10, 23), "randomly chosen date") + test_helper((2004, 12, 18), "randomly chosen date") + test_helper((1978, 10, 23), "year starting and ending on Monday while " + "date not on Sunday or Monday") + test_helper((1917, 12, 17), "year starting and ending on Monday with " + "a Monday not at the beginning or end " + "of the year") + test_helper((1917, 12, 31), "Dec 31 on Monday with year starting and " + "ending on Monday") class CacheTests(unittest.TestCase): From bcannon at users.sourceforge.net Thu Oct 28 06:50:30 2004 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Thu Oct 28 06:50:35 2004 Subject: [Python-checkins] python/dist/src/Lib _strptime.py, 1.23.4.6, 1.23.4.7 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32106/Lib Modified Files: Tag: release23-maint _strptime.py Log Message: Backport of fix for bug of year// calculation that didn't handle %U for years starting on Monday. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.23.4.6 retrieving revision 1.23.4.7 diff -u -d -r1.23.4.6 -r1.23.4.7 --- _strptime.py 18 Oct 2004 01:56:16 -0000 1.23.4.6 +++ _strptime.py 28 Oct 2004 04:50:28 -0000 1.23.4.7 @@ -518,25 +518,27 @@ # If we know the week of the year and what day of that week, we can figure # out the Julian day of the year # Calculations below assume 0 is a Monday - if julian == -1 and week_of_year != -1 and weekday != -1 and year != -1: - # Adjust for U directive so that calculations are not dependent on - # directive used to figure out week of year - if weekday == 6 and week_of_year_start == 6: - week_of_year -= 1 - # For some reason when Dec 31 falls on a Monday the week of the year is - # off by a week; verified on both OS X and Solaris. - elif weekday == 0 and week_of_year_start == 6 and week_of_year >= 52: - week_of_year += 1 + if julian == -1 and week_of_year != -1 and weekday != -1: # Calculate how many days in week 0 first_weekday = datetime_date(year, 1, 1).weekday() preceeding_days = 7 - first_weekday if preceeding_days == 7: preceeding_days = 0 + # Adjust for U directive so that calculations are not dependent on + # directive used to figure out week of year + if weekday == 6 and week_of_year_start == 6: + week_of_year -= 1 + # If a year starts and ends on a Monday but a week is specified to + # start on a Sunday we need to up the week to counter-balance the fact + # that with %W that first Monday starts week 1 while with %U that is + # week 0 and thus shifts everything by a week + if weekday == 0 and first_weekday == 0 and week_of_year_start == 6: + week_of_year += 1 # If in week 0, then just figure out how many days from Jan 1 to day of # week specified, else calculate by multiplying week of year by 7, # adding in days in week 0, and the number of days from Monday to the # day of the week - if not week_of_year: + if week_of_year == 0: julian = 1 + weekday - first_weekday else: days_to_week = preceeding_days + (7 * (week_of_year - 1)) From doerwalter at users.sourceforge.net Thu Oct 28 15:04:30 2004 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Thu Oct 28 15:04:31 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_codecs.py, 1.14, 1.15 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3004/Lib/test Modified Files: test_codecs.py Log Message: Trigger a few error cases in Modules/_codecsmodule.c. Index: test_codecs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_codecs.py,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- test_codecs.py 17 Oct 2004 23:51:21 -0000 1.14 +++ test_codecs.py 28 Oct 2004 13:04:26 -0000 1.15 @@ -454,9 +454,23 @@ def test_decode(self): self.assertEquals(codecs.decode('\xe4\xf6\xfc', 'latin-1'), u'\xe4\xf6\xfc') + self.assertRaises(TypeError, codecs.decode) + self.assertEquals(codecs.decode('abc'), u'abc') + self.assertRaises(UnicodeDecodeError, codecs.decode, '\xff', 'ascii') + def test_encode(self): self.assertEquals(codecs.encode(u'\xe4\xf6\xfc', 'latin-1'), '\xe4\xf6\xfc') + self.assertRaises(TypeError, codecs.encode) + self.assertEquals(codecs.encode(u'abc'), 'abc') + self.assertRaises(UnicodeEncodeError, codecs.encode, u'\xffff', 'ascii') + + def test_register(self): + self.assertRaises(TypeError, codecs.register) + + def test_lookup(self): + self.assertRaises(TypeError, codecs.lookup) + self.assertRaises(LookupError, codecs.lookup, "__spam__") class StreamReaderTest(unittest.TestCase): From arigo at users.sourceforge.net Thu Oct 28 18:32:11 2004 From: arigo at users.sourceforge.net (arigo@users.sourceforge.net) Date: Thu Oct 28 18:32:13 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_funcattrs.py, 1.15, 1.16 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19812/Lib/test Modified Files: test_funcattrs.py Log Message: Wrote down the invariants of some common objects whose structure is exposed in header files. Fixed a few comments in these headers. As we might have expected, writing down invariants systematically exposed a (minor) bug. In this case, function objects have a writeable func_code attribute, which could be set to code objects with the wrong number of free variables. Calling the resulting function segfaulted the interpreter. Added a corresponding test. Index: test_funcattrs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_funcattrs.py,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- test_funcattrs.py 13 Aug 2004 03:57:22 -0000 1.15 +++ test_funcattrs.py 28 Oct 2004 16:31:59 -0000 1.16 @@ -218,11 +218,11 @@ # Test all predefined function attributes systematically -def cantset(obj, name, value): +def cantset(obj, name, value, exception=(AttributeError, TypeError)): verify(hasattr(obj, name)) # Otherwise it's probably a typo try: setattr(obj, name, value) - except (AttributeError, TypeError): + except exception: pass else: raise TestFailed, "shouldn't be able to set %s to %r" % (name, value) @@ -279,11 +279,20 @@ def test_func_code(): + a = b = 24 def f(): pass def g(): print 12 + def f1(): print a + def g1(): print b + def f2(): print a, b verify(type(f.func_code) is types.CodeType) f.func_code = g.func_code cantset(f, "func_code", None) + # can't change the number of free vars + cantset(f, "func_code", f1.func_code, exception=ValueError) + cantset(f1, "func_code", f.func_code, exception=ValueError) + cantset(f1, "func_code", f2.func_code, exception=ValueError) + f1.func_code = g1.func_code def test_func_defaults(): def f(a, b): return (a, b) From arigo at users.sourceforge.net Thu Oct 28 18:32:10 2004 From: arigo at users.sourceforge.net (arigo@users.sourceforge.net) Date: Thu Oct 28 18:32:14 2004 Subject: [Python-checkins] python/dist/src/Objects funcobject.c,2.66,2.67 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19812/Objects Modified Files: funcobject.c Log Message: Wrote down the invariants of some common objects whose structure is exposed in header files. Fixed a few comments in these headers. As we might have expected, writing down invariants systematically exposed a (minor) bug. In this case, function objects have a writeable func_code attribute, which could be set to code objects with the wrong number of free variables. Calling the resulting function segfaulted the interpreter. Added a corresponding test. Index: funcobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/funcobject.c,v retrieving revision 2.66 retrieving revision 2.67 diff -u -d -r2.66 -r2.67 --- funcobject.c 12 Aug 2004 18:12:44 -0000 2.66 +++ funcobject.c 28 Oct 2004 16:32:00 -0000 2.67 @@ -230,6 +230,7 @@ func_set_code(PyFunctionObject *op, PyObject *value) { PyObject *tmp; + int nfree, nclosure; if (restricted()) return -1; @@ -240,6 +241,17 @@ "func_code must be set to a code object"); return -1; } + nfree = PyCode_GetNumFree((PyCodeObject *)value); + nclosure = (op->func_closure == NULL ? 0 : + PyTuple_GET_SIZE(op->func_closure)); + if (nclosure != nfree) { + PyErr_Format(PyExc_ValueError, + "%s() requires a code object with %d free vars," + " not %d", + PyString_AsString(op->func_name), + nclosure, nfree); + return -1; + } tmp = op->func_code; Py_INCREF(value); op->func_code = value; From arigo at users.sourceforge.net Thu Oct 28 18:32:13 2004 From: arigo at users.sourceforge.net (arigo@users.sourceforge.net) Date: Thu Oct 28 18:32:17 2004 Subject: [Python-checkins] python/dist/src/Include cellobject.h, 2.3, 2.4 funcobject.h, 2.26, 2.27 intobject.h, 2.30, 2.31 listobject.h, 2.32, 2.33 methodobject.h, 2.27, 2.28 rangeobject.h, 2.19, 2.20 setobject.h, 2.4, 2.5 sliceobject.h, 2.7, 2.8 stringobject.h, 2.39, 2.40 tupleobject.h, 2.29, 2.30 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19812/Include Modified Files: cellobject.h funcobject.h intobject.h listobject.h methodobject.h rangeobject.h setobject.h sliceobject.h stringobject.h tupleobject.h Log Message: Wrote down the invariants of some common objects whose structure is exposed in header files. Fixed a few comments in these headers. As we might have expected, writing down invariants systematically exposed a (minor) bug. In this case, function objects have a writeable func_code attribute, which could be set to code objects with the wrong number of free variables. Calling the resulting function segfaulted the interpreter. Added a corresponding test. Index: cellobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/cellobject.h,v retrieving revision 2.3 retrieving revision 2.4 diff -u -d -r2.3 -r2.4 --- cellobject.h 12 Aug 2002 07:21:56 -0000 2.3 +++ cellobject.h 28 Oct 2004 16:31:57 -0000 2.4 @@ -8,7 +8,7 @@ typedef struct { PyObject_HEAD - PyObject *ob_ref; + PyObject *ob_ref; /* Content of the cell or NULL when empty */ } PyCellObject; PyAPI_DATA(PyTypeObject) PyCell_Type; Index: funcobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/funcobject.h,v retrieving revision 2.26 retrieving revision 2.27 diff -u -d -r2.26 -r2.27 --- funcobject.h 31 Jan 2003 18:33:15 -0000 2.26 +++ funcobject.h 28 Oct 2004 16:31:57 -0000 2.27 @@ -7,17 +7,34 @@ extern "C" { #endif +/* Function objects and code objects should not be confused with each other: + * + * Function objects are created by the execution of the 'def' statement. + * They reference a code object in their func_code attribute, which is a + * purely syntactic object, i.e. nothing more than a compiled version of some + * source code lines. There is one code object per source code "fragment", + * but each code object can be referenced by zero or many function objects + * depending only on how many times the 'def' statement in the source was + * executed so far. + */ + typedef struct { PyObject_HEAD - PyObject *func_code; - PyObject *func_globals; - PyObject *func_defaults; - PyObject *func_closure; - PyObject *func_doc; - PyObject *func_name; - PyObject *func_dict; - PyObject *func_weakreflist; - PyObject *func_module; + PyObject *func_code; /* A code object */ + PyObject *func_globals; /* A dictionary (other mappings won't do) */ + PyObject *func_defaults; /* NULL or a tuple */ + PyObject *func_closure; /* NULL or a tuple of cell objects */ + PyObject *func_doc; /* The __doc__ attribute, can be anything */ + PyObject *func_name; /* The __name__ attribute, a string object */ + PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */ + PyObject *func_weakreflist; /* List of weak references */ + PyObject *func_module; /* The __module__ attribute, can be anything */ + + /* Invariant: + * func_closure contains the bindings for func_code->co_freevars, so + * PyTuple_Size(func_closure) == PyCode_GetNumFree(func_code) + * (func_closure may be NULL if PyCode_GetNumFree(func_code) == 0). + */ } PyFunctionObject; PyAPI_DATA(PyTypeObject) PyFunction_Type; Index: intobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/intobject.h,v retrieving revision 2.30 retrieving revision 2.31 diff -u -d -r2.30 -r2.31 --- intobject.h 17 Apr 2003 18:55:11 -0000 2.30 +++ intobject.h 28 Oct 2004 16:31:58 -0000 2.31 @@ -11,7 +11,7 @@ None of the functions should be applied to nil objects. The type PyIntObject is (unfortunately) exposed here so we can declare -_Py_TrueStruct and _Py_ZeroStruct below; don't use this. +_Py_TrueStruct and _Py_ZeroStruct in boolobject.h; don't use this. */ #ifndef Py_INTOBJECT_H Index: listobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/listobject.h,v retrieving revision 2.32 retrieving revision 2.33 diff -u -d -r2.32 -r2.33 --- listobject.h 1 Aug 2004 22:45:27 -0000 2.32 +++ listobject.h 28 Oct 2004 16:31:58 -0000 2.33 @@ -31,6 +31,9 @@ * len(list) == ob_size * ob_item == NULL implies ob_size == allocated == 0 * list.sort() temporarily sets allocated to -1 to detect mutations. + * + * Items must normally not be NULL, except during construction when + * the list is not yet visible outside the function that builds it. */ int allocated; } PyListObject; Index: methodobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/methodobject.h,v retrieving revision 2.27 retrieving revision 2.28 diff -u -d -r2.27 -r2.28 --- methodobject.h 13 Dec 2003 11:26:10 -0000 2.27 +++ methodobject.h 28 Oct 2004 16:31:58 -0000 2.28 @@ -7,6 +7,10 @@ extern "C" { #endif +/* This is about the type 'builtin_function_or_method', + not Python methods in user-defined classes. See classobject.h + for the latter. */ + PyAPI_DATA(PyTypeObject) PyCFunction_Type; #define PyCFunction_Check(op) ((op)->ob_type == &PyCFunction_Type) @@ -31,10 +35,11 @@ PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *); struct PyMethodDef { - char *ml_name; - PyCFunction ml_meth; - int ml_flags; - char *ml_doc; + char *ml_name; /* The name of the built-in function/method */ + PyCFunction ml_meth; /* The C function that implements it */ + int ml_flags; /* Combination of METH_xxx flags, which mostly + describe the args expected by the C func */ + char *ml_doc; /* The __doc__ attribute, or NULL */ }; typedef struct PyMethodDef PyMethodDef; @@ -75,9 +80,9 @@ typedef struct { PyObject_HEAD - PyMethodDef *m_ml; - PyObject *m_self; - PyObject *m_module; + PyMethodDef *m_ml; /* Description of the C function to call */ + PyObject *m_self; /* Passed as 'self' arg to the C func, can be NULL */ + PyObject *m_module; /* The __module__ attribute, can be anything */ } PyCFunctionObject; #ifdef __cplusplus Index: rangeobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/rangeobject.h,v retrieving revision 2.19 retrieving revision 2.20 diff -u -d -r2.19 -r2.20 --- rangeobject.h 12 Aug 2002 07:21:57 -0000 2.19 +++ rangeobject.h 28 Oct 2004 16:31:58 -0000 2.20 @@ -7,6 +7,9 @@ extern "C" { #endif +/* This is about the type 'xrange', not the built-in function range(), which + returns regular lists. */ + /* A range object represents an integer range. This is an immutable object; a range cannot change its value after creation. Index: setobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/setobject.h,v retrieving revision 2.4 retrieving revision 2.5 diff -u -d -r2.4 -r2.5 --- setobject.h 30 May 2004 07:26:45 -0000 2.4 +++ setobject.h 28 Oct 2004 16:31:59 -0000 2.5 @@ -16,6 +16,14 @@ PyObject *data; long hash; /* only used by frozenset objects */ PyObject *weakreflist; /* List of weak references */ + + /* Invariants: + * data is a dictionary whose values are all True. + * data points to the same dict for the whole life of the set. + * For frozensets only: + * data is immutable. + * hash is the hash of the frozenset or -1 if not computed yet. + */ } PySetObject; PyAPI_DATA(PyTypeObject) PySet_Type; Index: sliceobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/sliceobject.h,v retrieving revision 2.7 retrieving revision 2.8 diff -u -d -r2.7 -r2.8 --- sliceobject.h 12 Aug 2002 07:21:57 -0000 2.7 +++ sliceobject.h 28 Oct 2004 16:31:59 -0000 2.8 @@ -16,12 +16,12 @@ A slice object containing start, stop, and step data members (the names are from range). After much talk with Guido, it was decided to -let these be any arbitrary python type. +let these be any arbitrary python type. Py_None stands for omitted values. */ typedef struct { PyObject_HEAD - PyObject *start, *stop, *step; + PyObject *start, *stop, *step; /* not NULL */ } PySliceObject; PyAPI_DATA(PyTypeObject) PySlice_Type; Index: stringobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/stringobject.h,v retrieving revision 2.39 retrieving revision 2.40 diff -u -d -r2.39 -r2.40 --- stringobject.h 1 Jul 2003 20:15:21 -0000 2.39 +++ stringobject.h 28 Oct 2004 16:31:59 -0000 2.40 @@ -37,6 +37,15 @@ long ob_shash; int ob_sstate; char ob_sval[1]; + + /* Invariants: + * ob_sval contains space for 'ob_size+1' elements. + * ob_sval[ob_size] == 0. + * ob_shash is the hash of the string or -1 if not computed yet. + * ob_sstate != 0 iff the string object is in stringobject.c's + * 'interned' dictionary; in this case the two references + * from 'interned' to this object are *not counted* in ob_refcnt. + */ } PyStringObject; #define SSTATE_NOT_INTERNED 0 Index: tupleobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/tupleobject.h,v retrieving revision 2.29 retrieving revision 2.30 diff -u -d -r2.29 -r2.30 --- tupleobject.h 12 Oct 2003 18:24:33 -0000 2.29 +++ tupleobject.h 28 Oct 2004 16:31:59 -0000 2.30 @@ -8,9 +8,11 @@ #endif /* -Another generally useful object type is an tuple of object pointers. -This is a mutable type: the tuple items can be changed (but not their -number). Out-of-range indices or non-tuple objects are ignored. +Another generally useful object type is a tuple of object pointers. +For Python, this is an immutable type. C code can change the tuple items +(but not their number), and even use tuples are general-purpose arrays of +object references, but in general only brand new tuples should be mutated, +not ones that might already have been exposed to Python code. *** WARNING *** PyTuple_SetItem does not increment the new item's reference count, but does decrement the reference count of the item it replaces, @@ -22,6 +24,11 @@ typedef struct { PyObject_VAR_HEAD PyObject *ob_item[1]; + + /* ob_item contains space for 'ob_size' elements. + * Items must normally not be NULL, except during construction when + * the tuple is not yet visible outside the function that builds it. + */ } PyTupleObject; PyAPI_DATA(PyTypeObject) PyTuple_Type; From vsajip at users.sourceforge.net Fri Oct 29 14:30:30 2004 From: vsajip at users.sourceforge.net (vsajip@users.sourceforge.net) Date: Fri Oct 29 14:30:33 2004 Subject: [Python-checkins] python/dist/src/Doc/lib liblogging.tex,1.28,1.29 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29962/lib Modified Files: liblogging.tex Log Message: Added network logging example Index: liblogging.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liblogging.tex,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- liblogging.tex 22 Oct 2004 21:43:15 -0000 1.28 +++ liblogging.tex 29 Oct 2004 12:30:28 -0000 1.29 @@ -580,6 +580,143 @@ As you can see, the DEBUG message only shows up in the file. The other messages are sent to both destinations. +This example uses console and file handlers, but you can use any number and +combination of handlers you choose. + +\subsection{Sending and receiving logging events across a network +\label{network-logging}} + +Let's say you want to send logging events across a network, and handle them +at the receiving end. A simple way of doing this is attaching a +\class{SocketHandler} instance to the root logger at the sending end: + +\begin{verbatim} +import logging, logging.handlers + +rootLogger = logging.getLogger('') +rootLogger.setLevel(logging.DEBUG) +socketHandler = logging.handlers.SocketHandler('localhost', + logging.handlers.DEFAULT_TCP_LOGGING_PORT) +# don't bother with a formatter, since a socket handler sends the event as +# an unformatted pickle +rootLogger.addHandler(socketHandler) + +#Now, we can log to the root logger, or any other logger. First the root... +logging.info('Jackdaws love my big sphinx of quartz.') + +#Now, define a couple of other loggers which might represent areas in your +#application: + +logger1 = logging.getLogger('myapp.area1') +logger2 = logging.getLogger('myapp.area2') + +logger1.debug('Quick zephyrs blow, vexing daft Jim.') +logger1.info('How quickly daft jumping zebras vex.') +logger2.warning('Jail zesty vixen who grabbed pay from quack.') +logger2.error('The five boxing wizards jump quickly.') +\end{verbatim} + +At the receiving end, you can set up a receiver using the +\module{SocketServer} module. Here is a basic working example: + +\begin{verbatim} +import struct, cPickle, logging, logging.handlers + +from SocketServer import ThreadingTCPServer, StreamRequestHandler + +class LogRecordStreamHandler(StreamRequestHandler): + """ + Handler for a streaming logging request. It basically logs the record + using whatever logging policy is configured locally. + """ + + def handle(self): + """ + Handle multiple requests - each expected to be a 4-byte length, + followed by the LogRecord in pickle format. Logs the record + according to whatever policy is configured locally. + """ + while 1: + chunk = self.connection.recv(4) + if len(chunk) < 4: + break + slen = struct.unpack(">L", chunk)[0] + chunk = self.connection.recv(slen) + while len(chunk) < slen: + chunk = chunk + self.connection.recv(slen - len(chunk)) + obj = self.unPickle(chunk) + record = logging.makeLogRecord(obj) + self.handleLogRecord(record) + + def unPickle(self, data): + return cPickle.loads(data) + + def handleLogRecord(self, record): + #if a name is specified, we use the named logger rather than the one + #implied by the record. + if self.server.logname is not None: + name = self.server.logname + else: + name = record.name + logger = logging.getLogger(name) + #N.B. EVERY record gets logged. This is because Logger.handle + #is normally called AFTER logger-level filtering. If you want + #to do filtering, do it at the client end to save wasting + #cycles and network bandwidth! + logger.handle(record) + +class LogRecordSocketReceiver(ThreadingTCPServer): + """ + A simple-minded TCP socket-based logging receiver suitable for test + purposes. + """ + + allow_reuse_address = 1 + + def __init__(self, host='localhost', + port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, + handler=LogRecordStreamHandler): + ThreadingTCPServer.__init__(self, (host, port), handler) + self.abort = 0 + self.timeout = 1 + self.logname = None + + def serve_until_stopped(self): + import select + abort = 0 + while not abort: + rd, wr, ex = select.select([self.socket.fileno()], + [], [], + self.timeout) + if rd: + self.handle_request() + abort = self.abort + +def main(): + logging.basicConfig( + format="%(relativeCreated)5d %(name)-15s %(levelname)-8s %(message)s", + datefmt="%H:%M:%S") + tcpserver = LogRecordSocketReceiver() + print "About to start TCP server..." + tcpserver.serve_until_stopped() + +if __name__ == "__main__": + main() +\end{verbatim} + +If you first run the server, and then the client. On the client side, nothing +is printed on the client console; on the server side, you should see something +like this: + +\begin{verbatim} +About to start TCP server... + 59 root INFO Jackdaws love my big sphinx of quartz. + 59 myapp.area1 DEBUG Quick zephyrs blow, vexing daft Jim. + 69 myapp.area1 INFO How quickly daft jumping zebras vex. + 69 myapp.area2 WARNING Jail zesty vixen who grabbed pay from quack. + 69 myapp.area2 ERROR The five boxing wizards jump quickly. +\end{verbatim} + \subsection{Handler Objects} Handlers have the following attributes and methods. Note that From fdrake at users.sourceforge.net Fri Oct 29 16:35:44 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Fri Oct 29 16:35:48 2004 Subject: [Python-checkins] python/dist/src/Doc/lib liblogging.tex,1.29,1.30 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27682 Modified Files: liblogging.tex Log Message: style consistency: - always include a space after the "#" that starts a comment - easier to read imports Index: liblogging.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liblogging.tex,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- liblogging.tex 29 Oct 2004 12:30:28 -0000 1.29 +++ liblogging.tex 29 Oct 2004 14:35:42 -0000 1.30 @@ -527,27 +527,27 @@ \begin{verbatim} import logging -#set up logging to file - see previous section for more details +# set up logging to file - see previous section for more details logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', datefmt='%m-%d %H:%M', filename='/temp/myapp.log', filemode='w') -#define a Handler which writes INFO messages or higher to the sys.stderr +# define a Handler which writes INFO messages or higher to the sys.stderr console = logging.StreamHandler() console.setLevel(logging.INFO) -#set a format which is simpler for console use +# set a format which is simpler for console use formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') -#tell the handler to use this format +# tell the handler to use this format console.setFormatter(formatter) -#add the handler to the root logger +# add the handler to the root logger logging.getLogger('').addHandler(console) -#Now, we can log to the root logger, or any other logger. First the root... +# Now, we can log to the root logger, or any other logger. First the root... logging.info('Jackdaws love my big sphinx of quartz.') -#Now, define a couple of other loggers which might represent areas in your -#application: +# Now, define a couple of other loggers which might represent areas in your +# application: logger1 = logging.getLogger('myapp.area1') logger2 = logging.getLogger('myapp.area2') @@ -601,11 +601,11 @@ # an unformatted pickle rootLogger.addHandler(socketHandler) -#Now, we can log to the root logger, or any other logger. First the root... +# Now, we can log to the root logger, or any other logger. First the root... logging.info('Jackdaws love my big sphinx of quartz.') -#Now, define a couple of other loggers which might represent areas in your -#application: +# Now, define a couple of other loggers which might represent areas in your +# application: logger1 = logging.getLogger('myapp.area1') logger2 = logging.getLogger('myapp.area2') @@ -620,14 +620,18 @@ \module{SocketServer} module. Here is a basic working example: \begin{verbatim} -import struct, cPickle, logging, logging.handlers +import cPickle +import logging +import logging.handlers +import SocketServer +import struct -from SocketServer import ThreadingTCPServer, StreamRequestHandler -class LogRecordStreamHandler(StreamRequestHandler): - """ - Handler for a streaming logging request. It basically logs the record - using whatever logging policy is configured locally. +class LogRecordStreamHandler(SocketServer.StreamRequestHandler): + """Handler for a streaming logging request. + + This basically logs the record using whatever logging policy is + configured locally. """ def handle(self): @@ -652,31 +656,29 @@ return cPickle.loads(data) def handleLogRecord(self, record): - #if a name is specified, we use the named logger rather than the one - #implied by the record. + # if a name is specified, we use the named logger rather than the one + # implied by the record. if self.server.logname is not None: name = self.server.logname else: name = record.name logger = logging.getLogger(name) - #N.B. EVERY record gets logged. This is because Logger.handle - #is normally called AFTER logger-level filtering. If you want - #to do filtering, do it at the client end to save wasting - #cycles and network bandwidth! + # N.B. EVERY record gets logged. This is because Logger.handle + # is normally called AFTER logger-level filtering. If you want + # to do filtering, do it at the client end to save wasting + # cycles and network bandwidth! logger.handle(record) -class LogRecordSocketReceiver(ThreadingTCPServer): - """ - A simple-minded TCP socket-based logging receiver suitable for test - purposes. +class LogRecordSocketReceiver(SocketServer.ThreadingTCPServer): + """simple TCP socket-based logging receiver suitable for testing. """ allow_reuse_address = 1 def __init__(self, host='localhost', - port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, - handler=LogRecordStreamHandler): - ThreadingTCPServer.__init__(self, (host, port), handler) + port=logging.handlers.DEFAULT_TCP_LOGGING_PORT, + handler=LogRecordStreamHandler): + SocketServer.ThreadingTCPServer.__init__(self, (host, port), handler) self.abort = 0 self.timeout = 1 self.logname = None From fdrake at users.sourceforge.net Fri Oct 29 21:47:55 2004 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Fri Oct 29 21:47:58 2004 Subject: [Python-checkins] python/dist/src/Doc/perl l2hinit.perl, 1.83, 1.84 python.perl, 1.149, 1.150 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/perl In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv380/perl Modified Files: l2hinit.perl python.perl Log Message: add xml:id attributes wherever we generate the IDs (old patch saved up) Index: l2hinit.perl =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/perl/l2hinit.perl,v retrieving revision 1.83 retrieving revision 1.84 diff -u -d -r1.83 -r1.84 --- l2hinit.perl 9 Sep 2004 05:13:52 -0000 1.83 +++ l2hinit.perl 29 Oct 2004 19:47:52 -0000 1.84 @@ -246,7 +246,7 @@ sub top_navigation_panel() { - return "\n
\n" + return "\n
\n" . make_nav_panel() . "
\n"; } Index: python.perl =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/perl/python.perl,v retrieving revision 1.149 retrieving revision 1.150 diff -u -d -r1.149 -r1.150 --- python.perl 8 Apr 2004 15:30:12 -0000 1.149 +++ python.perl 29 Oct 2004 19:47:52 -0000 1.150 @@ -358,7 +358,7 @@ # Save the reference my $nstr = gen_index_id("Python Enhancement Proposals!PEP $rfcnumber", ''); $index{$nstr} .= make_half_href("$CURRENT_FILE#$id"); - return ("PEP $rfcnumber$icon" . $_); } @@ -371,7 +371,7 @@ # Save the reference my $nstr = gen_index_id("RFC!RFC $rfcnumber", ''); $index{$nstr} .= make_half_href("$CURRENT_FILE#$id"); - return ("" + return ("" . "RFC $rfcnumber$icon" . $_); } @@ -525,14 +525,14 @@ sub new_link_name_info(){ my $name = "l2h-" . ++$globals{'max_id'}; - my $aname = ""; + my $aname = ""; my $ahref = gen_link($CURRENT_FILE, $name); return ($name, $ahref); } sub new_link_info(){ my($name, $ahref) = new_link_name_info(); - my $aname = ""; + my $aname = ""; return ($name, $aname, $ahref); } @@ -762,11 +762,11 @@ add_index_entry($str, $ahref); if ($str =~ /^<[a-z]+\b/) { my $s = "$str"; - $s =~ s/^<([a-z]+)\b/<$1 id='$name'/; + $s =~ s/^<([a-z]+)\b/<$1 id='$name' xml:id='$name'/; return $s; } else { - return "$str"; + return "$str"; } } @@ -844,7 +844,7 @@ } $TokenToTargetMapping{"$CURRENT_GRAMMAR:$token"} = $target; return ("\n" - . " " + . " " . "$token\n" . "  ::= \n" . " " From rhettinger at users.sourceforge.net Sat Oct 30 10:55:11 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat Oct 30 10:55:15 2004 Subject: [Python-checkins] python/dist/src/Python compile.c,2.332,2.333 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15285 Modified Files: compile.c Log Message: Adopt some peepholer suggestions from Armin Rigo: * Use simpler, faster two pass algorithm for markblocks(). * Free the blocks variable if not NULL and exiting without change. * Verify that the rest of the compiler has not set an exception. * Make the test for tuple of constants less restrictive. * Embellish the comment for chained conditional jumps. Index: compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.332 retrieving revision 2.333 diff -u -d -r2.332 -r2.333 --- compile.c 26 Oct 2004 08:59:13 -0000 2.332 +++ compile.c 30 Oct 2004 08:55:08 -0000 2.333 @@ -406,14 +406,10 @@ /* Pre-conditions */ assert(PyList_CheckExact(consts)); - assert(codestr[0] == LOAD_CONST); assert(codestr[n*3] == BUILD_TUPLE); assert(GETARG(codestr, (n*3)) == n); - - /* Verify chain of n load_constants */ for (i=0 ; i= 0 && - j == lastlc && + j <= lastlc && codestr[h] == LOAD_CONST && ISBASICBLOCK(blocks, h, 3*(j+1)) && tuple_of_constants(&codestr[h], j, consts)) { @@ -647,6 +648,8 @@ result of the first test implies the success of a similar test or the failure of the opposite test. Arises in code like: + "if a and b:" + "if a or b:" "a and b or c" "a and b and c" x:JUMP_IF_FALSE y y:JUMP_IF_FALSE z --> x:JUMP_IF_FALSE z @@ -755,6 +758,8 @@ return code; exitUnchanged: + if (blocks != NULL) + PyMem_Free(blocks); if (addrmap != NULL) PyMem_Free(addrmap); if (codestr != NULL) From arigo at users.sourceforge.net Sat Oct 30 23:09:03 2004 From: arigo at users.sourceforge.net (arigo@users.sourceforge.net) Date: Sat Oct 30 23:09:07 2004 Subject: [Python-checkins] python/dist/src/Python compile.c,2.333,2.334 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29422 Modified Files: compile.c Log Message: Fixed a comment and added another one. Index: compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.333 retrieving revision 2.334 diff -u -d -r2.333 -r2.334 --- compile.c 30 Oct 2004 08:55:08 -0000 2.333 +++ compile.c 30 Oct 2004 21:08:59 -0000 2.334 @@ -651,7 +651,7 @@ "if a and b:" "if a or b:" "a and b or c" - "a and b and c" + "(a and b) and c" x:JUMP_IF_FALSE y y:JUMP_IF_FALSE z --> x:JUMP_IF_FALSE z x:JUMP_IF_FALSE y y:JUMP_IF_TRUE z --> x:JUMP_IF_FALSE y+3 where y+3 is the instruction following the second test. @@ -749,6 +749,9 @@ while (adj--) codestr[h++] = codestr[i++]; } + /* The following assertion detects the presence of NOPs in the input + bytecode. The compiler never produces NOPs so far; if one day it + does, the way 'nops' is counted above must be changed. */ assert(h + nops == codelen); code = PyString_FromStringAndSize((char *)codestr, h); From tim_one at users.sourceforge.net Sun Oct 31 01:09:24 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 01:09:28 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1178,1.1179 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22636/Misc Modified Files: NEWS Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. I'll backport to 2.3. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1178 retrieving revision 1.1179 diff -u -d -r1.1178 -r1.1179 --- NEWS 26 Oct 2004 09:53:46 -0000 1.1178 +++ NEWS 30 Oct 2004 23:09:20 -0000 1.1179 @@ -32,6 +32,17 @@ Core and builtins ----------------- +- Bug #1055820 Cyclic garbage collection was not protecting against that + calling a live weakref to a piece of cyclic trash could resurrect an + insane mutation of the trash if any Python code ran during gc (via + running a dead object's __del__ method, running another callback on a + weakref to a dead object, or via any Python code run in any other thread + that managed to obtain the GIL while a __del__ or callback was running + in the thread doing gc). The most likely symptom was "impossible" + ``AttributeEror`` exceptions, appearing seemingly at random, on weakly + referenced objects. The cure was to clear all weakrefs to unreachable + objects before allowing any callbacks to run. + - Bug #1054139 _PyString_Resize() now invalidates its cached hash value. Extension Modules From tim_one at users.sourceforge.net Sun Oct 31 01:09:25 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 01:09:29 2004 Subject: [Python-checkins] python/dist/src/Objects weakrefobject.c, 1.19, 1.20 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22636/Objects Modified Files: weakrefobject.c Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. I'll backport to 2.3. Index: weakrefobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/weakrefobject.c,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- weakrefobject.c 3 Aug 2004 14:47:25 -0000 1.19 +++ weakrefobject.c 30 Oct 2004 23:09:22 -0000 1.20 @@ -850,7 +850,9 @@ return PyWeakref_GET_OBJECT(ref); } - +/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's + * handle_weakrefs(). + */ static void handle_callback(PyWeakReference *ref, PyObject *callback) { From tim_one at users.sourceforge.net Sun Oct 31 01:09:25 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 01:09:31 2004 Subject: [Python-checkins] python/dist/src/Modules gc_weakref.txt, 2.1, 2.2 gcmodule.c, 2.76, 2.77 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22636/Modules Modified Files: gc_weakref.txt gcmodule.c Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. I'll backport to 2.3. Index: gc_weakref.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/gc_weakref.txt,v retrieving revision 2.1 retrieving revision 2.2 diff -u -d -r2.1 -r2.2 --- gc_weakref.txt 20 Nov 2003 21:21:46 -0000 2.1 +++ gc_weakref.txt 30 Oct 2004 23:09:22 -0000 2.2 @@ -1,3 +1,79 @@ +Intro +===== + +The basic rule for dealing with weakref callbacks (and __del__ methods too, +for that matter) during cyclic gc: + + Once gc has computed the set of unreachable objects, no Python-level + code can be allowed to access an unreachable object. + +If that can happen, then the Python code can resurrect unreachable objects +too, and gc can't detect that without starting over. Since gc eventually +runs tp_clear on all unreachable objects, if an unreachable object is +resurrected then tp_clear will eventually be called on it (or may already +have been called before resurrection). At best (and this has been an +historically common bug), tp_clear empties an instance's __dict__, and +"impossible" AttributeErrors result. At worst, tp_clear leaves behind an +insane object at the C level, and segfaults result (historically, most +often by setting a new-style class's mro pointer to NULL, after which +attribute lookups performed by the class can segfault). + +OTOH, it's OK to run Python-level code that can't access unreachable +objects, and sometimes that's necessary. The chief example is the callback +attached to a reachable weakref W to an unreachable object O. Since O is +going away, and W is still alive, the callback must be invoked. Because W +is still alive, everything reachable from its callback is also reachable, +so it's also safe to invoke the callback (although that's trickier than it +sounds, since other reachable weakrefs to other unreachable objects may +still exist, and be accessible to the callback -- there are lots of painful +details like this covered in the rest of this file). + +Python 2.4/2.3.5 +================ + +The "Before 2.3.3" section below turned out to be wrong in some ways, but +I'm leaving it as-is because it's more right than wrong, and serves as a +wonderful example of how painful analysis can miss not only the forest for +the trees, but also miss the trees for the aphids sucking the trees +dry . + +The primary thing it missed is that when a weakref to a piece of cyclic +trash (CT) exists, then any call to any Python code whatsoever can end up +materializing a strong reference to that weakref's CT referent, and so +possibly resurrect an insane object (one for which cyclic gc has called-- or +will call before it's done --tp_clear()). It's not even necessarily that a +weakref callback or __del__ method does something nasty on purpose: as +soon as we execute Python code, threads other than the gc thread can run +too, and they can do ordinary things with weakrefs that end up resurrecting +CT while gc is running. + + http://www.python.org/sf/1055820 + +shows how innocent it can be, and also how nasty. Variants of the three +focussed test cases attached to that bug report are now part of Python's +standard Lib/test/test_gc.py. + +Jim Fulton gave the best nutshell summary of the new (in 2.4 and 2.3.5) +approach: + + Clearing cyclic trash can call Python code. If there are weakrefs to + any of the cyclic trash, then those weakrefs can be used to resurrect + the objects. Therefore, *before* clearing cyclic trash, we need to + remove any weakrefs. If any of the weakrefs being removed have + callbacks, then we need to save the callbacks and call them *after* all + of the weakrefs have been cleared. + +Alas, doing just that much doesn't work, because it overlooks what turned +out to be the much subtler problems that were fixed earlier, and described +below. We do clear all weakrefs to CT now before breaking cycles, but not +all callbacks encountered can be run later. That's explained in horrid +detail below. + +Older text follows, with a some later comments in [] brackets: + +Before 2.3.3 +============ + Before 2.3.3, Python's cyclic gc didn't pay any attention to weakrefs. Segfaults in Zope3 resulted. @@ -19,12 +95,19 @@ happen at any later time if the callback manages to resurrect an insane object. +[That missed that, in addition, a weakref to CT can exist outside CT, and + any callback into Python can use such a non-CT weakref to resurrect its CT + referent. The same bad kinds of things can happen then.] + Note that if it's possible for the callback to get at objects in the trash cycles, it must also be the case that the callback itself is part of the trash cycles. Else the callback would have acted as an external root to the current collection, and nothing reachable from it would be in cyclic trash either. +[Except that a non-CT callback can also use a non-CT weakref to get at + CT objects.] + More, if the callback itself is in cyclic trash, then the weakref to which the callback is attached must also be trash, and for the same kind of reason: if the weakref acted as an external root, then the callback could @@ -47,6 +130,13 @@ a feature of Python's weakrefs too that when a weakref goes away, the callback (if any) associated with it is thrown away too, unexecuted. +[In 2.4/2.3.5, we first clear all weakrefs to CT objects, whether or not + those weakrefs are themselves CT, and whether or not they have callbacks. + The callbacks (if any) on non-CT weakrefs (if any) are invoked later, + after all weakrefs-to-CT have been cleared. The callbacks (if any) on CT + weakrefs (if any) are never invoked, for the excruciating reasons + explained here.] + Just that much is almost enough to prevent problems, by throwing away *almost* all the weakref callbacks that could get triggered by gc. The problem remaining is that clearing a weakref with a callback decrefs the @@ -56,7 +146,15 @@ latter weakrefs may or may not be part of cyclic trash. So, to prevent any Python code from running while gc is invoking tp_clear() -on all the objects in cyclic trash, it's not quite enough just to invoke +on all the objects in cyclic trash, + +[That was always wrong: we can't stop Python code from running when gc + is breaking cycles. If an object with a __del__ method is not itself in + a cycle, but is reachable only from CT, then breaking cycles will, as a + matter of course, drop the refcount on that object to 0, and its __del__ + will run right then. What we can and must stop is running any Python + code that could access CT.] + it's not quite enough just to invoke tp_clear() on weakrefs with callbacks first. Instead the weakref module grew a new private function (_PyWeakref_ClearRef) that does only part of tp_clear(): it removes the weakref from the weakly-referenced object's list @@ -65,9 +163,13 @@ trigger, and (unlike weakref's tp_clear()) also prevents any callback associated *with* wr's callback object from triggering. +[Although we may trigger such callbacks later, as explained below.] + Then we can call tp_clear on all the cyclic objects and never trigger Python code. +[As above, not so: it means never trigger Python code that can access CT.] + After we do that, the callback objects still need to be decref'ed. Callbacks (if any) *on* the callback objects that were also part of cyclic trash won't get invoked, because we cleared all trash weakrefs with callbacks at the @@ -76,6 +178,10 @@ reachable from them was part of cyclic trash, so gc didn't do any damage to objects reachable from them, and it's safe to call them at the end of gc. +[That's so. In addition, now we also invoke (if any) the callbacks on + non-CT weakrefs to CT objects, during the same pass that decrefs the + callback objects.] + An alternative would have been to treat objects with callbacks like objects with __del__ methods, refusing to collect them, appending them to gc.garbage instead. That would have been much easier. Jim Fulton gave a strong @@ -105,3 +211,9 @@ However, a weakref callback on a weakref callback has got to be rare. It's possible to do such a thing, so gc has to be robust against it, but I doubt anyone has done it outside the test case I wrote for it. + +[The callbacks (if any) on non-CT weakrefs to CT objects are also executed + in an arbitrary order now. But they were before too, depending on the + vagaries of when tp_clear() happened to break enough cycles to trigger + them. People simply shouldn't try to use __del__ or weakref callbacks to + do fancy stuff.] Index: gcmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/gcmodule.c,v retrieving revision 2.76 retrieving revision 2.77 diff -u -d -r2.76 -r2.77 --- gcmodule.c 4 Jan 2004 04:00:13 -0000 2.76 +++ gcmodule.c 30 Oct 2004 23:09:22 -0000 2.77 @@ -396,38 +396,30 @@ return 0; } -/* Move the objects in unreachable with __del__ methods into finalizers, - * and weakrefs with callbacks into wr_callbacks. - * The objects remaining in unreachable do not have __del__ methods, and are - * not weakrefs with callbacks. - * The objects moved have gc_refs changed to GC_REACHABLE; the objects - * remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE. +/* Move the objects in unreachable with __del__ methods into `finalizers`. + * Objects moved into `finalizers` have gc_refs set to GC_REACHABLE; the + * objects remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE. */ static void -move_troublemakers(PyGC_Head *unreachable, - PyGC_Head *finalizers, - PyGC_Head *wr_callbacks) +move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) { - PyGC_Head *gc = unreachable->gc.gc_next; + PyGC_Head *gc; + PyGC_Head *next; - while (gc != unreachable) { + /* March over unreachable. Move objects with finalizers into + * `finalizers`. + */ + for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { PyObject *op = FROM_GC(gc); - PyGC_Head *next = gc->gc.gc_next; assert(IS_TENTATIVELY_UNREACHABLE(op)); + next = gc->gc.gc_next; if (has_finalizer(op)) { gc_list_remove(gc); gc_list_append(gc, finalizers); gc->gc.gc_refs = GC_REACHABLE; } - else if (PyWeakref_Check(op) && - ((PyWeakReference *)op)->wr_callback) { - gc_list_remove(gc); - gc_list_append(gc, wr_callbacks); - gc->gc.gc_refs = GC_REACHABLE; - } - gc = next; } } @@ -463,82 +455,180 @@ } } -/* Clear all trash weakrefs with callbacks. This clears weakrefs first, - * which has the happy result of disabling the callbacks without executing - * them. A nasty technical complication: a weakref callback can itself be - * the target of a weakref, in which case decrefing the callback can cause - * another callback to trigger. But we can't allow arbitrary Python code to - * get executed at this point (the callback on the callback may try to muck - * with other cyclic trash we're trying to collect, even resurrecting it - * while we're in the middle of doing tp_clear() on the trash). - * - * The private _PyWeakref_ClearRef() function exists so that we can clear - * the reference in a weakref without triggering a callback on the callback. - * - * We have to save the callback objects and decref them later. But we can't - * allocate new memory to save them (if we can't get new memory, we're dead). - * So we grab a new reference on the clear'ed weakref, which prevents the - * rest of gc from reclaiming it. _PyWeakref_ClearRef() leaves the - * weakref's wr_callback member intact. - * - * In the end, then, wr_callbacks consists of cleared weakrefs that are - * immune from collection. Near the end of gc, after collecting all the - * cyclic trash, we call release_weakrefs(). That releases our references - * to the cleared weakrefs, which in turn may trigger callbacks on their - * callbacks. +/* Clear all weakrefs to unreachable objects, and if such a weakref has a + * callback, invoke it if necessary. Note that it's possible for such + * weakrefs to be outside the unreachable set -- indeed, those are precisely + * the weakrefs whose callbacks must be invoked. See gc_weakref.txt for + * overview & some details. Some weakrefs with callbacks may be reclaimed + * directly by this routine; the number reclaimed is the return value. Other + * weakrefs with callbacks may be moved into the `old` generation. Objects + * moved into `old` have gc_refs set to GC_REACHABLE; the objects remaining in + * unreachable are left at GC_TENTATIVELY_UNREACHABLE. When this returns, + * no object in `unreachable` is weakly referenced anymore. */ -static void -clear_weakrefs(PyGC_Head *wr_callbacks) +static int +handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) { - PyGC_Head *gc = wr_callbacks->gc.gc_next; + PyGC_Head *gc; + PyObject *op; /* generally FROM_GC(gc) */ + PyWeakReference *wr; /* generally a cast of op */ - for (; gc != wr_callbacks; gc = gc->gc.gc_next) { - PyObject *op = FROM_GC(gc); - PyWeakReference *wr; + PyGC_Head wrcb_to_call; /* weakrefs with callbacks to call */ + PyGC_Head wrcb_to_kill; /* weakrefs with callbacks to ignore */ + + PyGC_Head *next; + int num_freed = 0; + + gc_list_init(&wrcb_to_call); + gc_list_init(&wrcb_to_kill); + + /* Clear all weakrefs to the objects in unreachable. If such a weakref + * also has a callback, move it into `wrcb_to_call` if the callback + * needs to be invoked, or into `wrcb_to_kill` if the callback should + * be ignored. Note that we cannot invoke any callbacks until all + * weakrefs to unreachable objects are cleared, lest the callback + * resurrect an unreachable object via a still-active weakref. That's + * why the weakrefs with callbacks are moved into different lists -- we + * make another pass over those lists after this pass completes. + */ + for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { + PyWeakReference **wrlist; + + op = FROM_GC(gc); + assert(IS_TENTATIVELY_UNREACHABLE(op)); + next = gc->gc.gc_next; + + if (! PyType_SUPPORTS_WEAKREFS(op->ob_type)) + continue; + + /* It supports weakrefs. Does it have any? */ + wrlist = (PyWeakReference **) + PyObject_GET_WEAKREFS_LISTPTR(op); + + /* `op` may have some weakrefs. March over the list, clear + * all the weakrefs, and move the weakrefs with callbacks + * into one of the wrcb_to_{call,kill} lists. + */ + for (wr = *wrlist; wr != NULL; wr = *wrlist) { + PyGC_Head *wrasgc; /* AS_GC(wr) */ + + /* _PyWeakref_ClearRef clears the weakref but leaves + * the callback pointer intact. Obscure: it also + * changes *wrlist. + */ + assert(wr->wr_object == op); + _PyWeakref_ClearRef(wr); + assert(wr->wr_object == Py_None); + if (wr->wr_callback == NULL) + continue; /* no callback */ + /* Headache time. `op` is going away, and is weakly referenced by + * `wr`, which has a callback. Should the callback be invoked? If wr + * is also trash, no: + * + * 1. There's no need to call it. The object and the weakref are + * both going away, so it's legitimate to pretend the weakref is + * going away first. The user has to ensure a weakref outlives its + * referent if they want a guarantee that the wr callback will get + * invoked. + * + * 2. It may be catastrophic to call it. If the callback is also in + * cyclic trash (CT), then although the CT is unreachable from + * outside the current generation, CT may be reachable from the + * callback. Then the callback could resurrect insane objects. + * + * Since the callback is never needed and may be unsafe in this case, + * wr is moved to wrcb_to_kill. + * + * OTOH, if wr isn't part of CT, we should invoke the callback: the + * weakref outlived the trash. Note that since wr isn't CT in this + * case, its callback can't be CT either -- wr acted as an external + * root to this generation, and therefore its callback did too. So + * nothing in CT is reachable from the callback either, so it's hard + * to imagine how calling it later could create a problem for us. wr + * is moved to wrcb_to_call in this case. + * + * Obscure: why do we move weakrefs with ignored callbacks to a list + * we crawl over later, instead of getting rid of the callback right + * now? It's because the obvious way doesn't work: setting + * wr->wr_callback to NULL requires that we decref the current + * wr->wr_callback. But callbacks are also weakly referenceable, so + * wr->wr_callback may *itself* be referenced by another weakref with + * another callback. The latter callback could get triggered now if + * we decref'ed now, but as explained before it's potentially unsafe to + * invoke any callback before all weakrefs to CT are cleared. + */ + /* Create a new reference so that wr can't go away + * before we can process it again. + */ + Py_INCREF(wr); + + /* Move wr to the appropriate list. */ + wrasgc = AS_GC(wr); + if (wrasgc == next) + next = wrasgc->gc.gc_next; + gc_list_remove(wrasgc); + gc_list_append(wrasgc, + IS_TENTATIVELY_UNREACHABLE(wr) ? + &wrcb_to_kill : &wrcb_to_call); + wrasgc->gc.gc_refs = GC_REACHABLE; + } + } + + /* Now that all weakrefs to trash have been cleared, it's safe to + * decref the callbacks we decided to ignore. We cannot invoke + * them because they may be able to resurrect unreachable (from + * outside) objects. + */ + while (! gc_list_is_empty(&wrcb_to_kill)) { + gc = wrcb_to_kill.gc.gc_next; + op = FROM_GC(gc); assert(IS_REACHABLE(op)); assert(PyWeakref_Check(op)); - wr = (PyWeakReference *)op; - assert(wr->wr_callback != NULL); - Py_INCREF(op); - _PyWeakref_ClearRef(wr); - } -} + assert(((PyWeakReference *)op)->wr_callback != NULL); -/* Called near the end of gc. This gives up the references we own to - * cleared weakrefs, allowing them to get collected, and in turn decref'ing - * their callbacks. - * - * If a callback object is itself the target of a weakref callback, - * decref'ing the callback object may trigger that other callback. If - * that other callback was part of the cyclic trash in this generation, - * that won't happen, since we cleared *all* trash-weakref callbacks near - * the start of gc. If that other callback was not part of the cyclic trash - * in this generation, then it acted like an external root to this round - * of gc, so all the objects reachable from that callback are still alive. - * - * Giving up the references to the weakref objects will probably make - * them go away too. However, if a weakref is reachable from finalizers, - * it won't go away. We move it to the old generation then. Since a - * weakref object doesn't have a finalizer, that's the right thing to do (it - * doesn't belong in gc.garbage). - * - * We return the number of weakref objects freed (those not appended to old). - */ -static int -release_weakrefs(PyGC_Head *wr_callbacks, PyGC_Head *old) -{ - int num_freed = 0; + /* Give up the reference we created in the first pass. When + * op's refcount hits 0 (which it may or may not do right now), + * op's tp_dealloc will decref op->wr_callback too. + */ + Py_DECREF(op); + if (wrcb_to_kill.gc.gc_next == gc) { + /* object is still alive -- move it */ + gc_list_remove(gc); + gc_list_append(gc, old); + } + else + ++num_freed; + } - while (! gc_list_is_empty(wr_callbacks)) { - PyGC_Head *gc = wr_callbacks->gc.gc_next; - PyObject *op = FROM_GC(gc); + /* Finally, invoke the callbacks we decided to honor. It's safe to + * invoke them because they cannot reference objects in `unreachable`. + */ + while (! gc_list_is_empty(&wrcb_to_call)) { + PyObject *temp; + PyObject *callback; + gc = wrcb_to_call.gc.gc_next; + op = FROM_GC(gc); assert(IS_REACHABLE(op)); assert(PyWeakref_Check(op)); - assert(((PyWeakReference *)op)->wr_callback != NULL); + wr = (PyWeakReference *)op; + callback = wr->wr_callback; + assert(callback != NULL); + + /* copy-paste of weakrefobject.c's handle_callback() */ + temp = PyObject_CallFunction(callback, "O", wr); + if (temp == NULL) + PyErr_WriteUnraisable(callback); + else + Py_DECREF(temp); + + /* Give up the reference we created in the first pass. When + * op's refcount hits 0 (which it may or may not do right now), + * op's tp_dealloc will decref op->wr_callback too. + */ Py_DECREF(op); - if (wr_callbacks->gc.gc_next == gc) { + if (wrcb_to_call.gc.gc_next == gc) { /* object is still alive -- move it */ gc_list_remove(gc); gc_list_append(gc, old); @@ -546,6 +636,7 @@ else ++num_freed; } + return num_freed; } @@ -652,7 +743,6 @@ PyGC_Head *old; /* next older generation */ PyGC_Head unreachable; /* non-problematic unreachable trash */ PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ - PyGC_Head wr_callbacks; /* weakrefs with callbacks */ PyGC_Head *gc; if (delstr == NULL) { @@ -690,9 +780,9 @@ old = young; /* Using ob_refcnt and gc_refs, calculate which objects in the - * container set are reachable from outside the set (ie. have a + * container set are reachable from outside the set (i.e., have a * refcount greater than 0 when all the references within the - * set are taken into account + * set are taken into account). */ update_refs(young); subtract_refs(young); @@ -714,23 +804,11 @@ * finalizers can't safely be deleted. Python programmers should take * care not to create such things. For Python, finalizers means * instance objects with __del__ methods. Weakrefs with callbacks - * can call arbitrary Python code, so those are special-cased too. - * - * Move unreachable objects with finalizers, and weakrefs with - * callbacks, into different lists. + * can also call arbitrary Python code but they will be dealt with by + * handle_weakrefs(). */ gc_list_init(&finalizers); - gc_list_init(&wr_callbacks); - move_troublemakers(&unreachable, &finalizers, &wr_callbacks); - /* Clear the trash weakrefs with callbacks. This prevents their - * callbacks from getting invoked (when a weakref goes away, so does - * its callback). - * We do this even if the weakrefs are reachable from finalizers. - * If we didn't, breaking cycles in unreachable later could trigger - * deallocation of objects in finalizers, which could in turn - * cause callbacks to trigger. This may not be ideal behavior. - */ - clear_weakrefs(&wr_callbacks); + move_finalizers(&unreachable, &finalizers); /* finalizers contains the unreachable objects with a finalizer; * unreachable objects reachable *from* those are also uncollectable, * and we move those into the finalizers list too. @@ -747,17 +825,16 @@ debug_cycle("collectable", FROM_GC(gc)); } } + + /* Clear weakrefs and invoke callbacks as necessary. */ + m += handle_weakrefs(&unreachable, old); + /* Call tp_clear on objects in the unreachable set. This will cause * the reference cycles to be broken. It may also cause some objects * in finalizers to be freed. */ delete_garbage(&unreachable, old); - /* Now that we're done analyzing stuff and breaking cycles, let - * delayed weakref callbacks run. - */ - m += release_weakrefs(&wr_callbacks, old); - /* Collect statistics on uncollectable objects found and print * debugging information. */ for (gc = finalizers.gc.gc_next; From tim_one at users.sourceforge.net Sun Oct 31 01:09:52 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 01:09:55 2004 Subject: [Python-checkins] python/dist/src/Include weakrefobject.h,1.5,1.6 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22636/Include Modified Files: weakrefobject.h Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. I'll backport to 2.3. Index: weakrefobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/weakrefobject.h,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- weakrefobject.h 2 Jul 2004 18:57:42 -0000 1.5 +++ weakrefobject.h 30 Oct 2004 23:09:19 -0000 1.6 @@ -9,11 +9,31 @@ typedef struct _PyWeakReference PyWeakReference; +/* PyWeakReference is the base struct for the Python ReferenceType, ProxyType, + * and CallableProxyType. + */ struct _PyWeakReference { PyObject_HEAD + + /* The object to which this is a weak reference, or Py_None if none. + * Note that this is a stealth reference: wr_object's refcount is + * not incremented to reflect this pointer. + */ PyObject *wr_object; + + /* A callable to invoke when wr_object dies, or NULL if none. */ PyObject *wr_callback; + + /* A cache for wr_object's hash code. As usual for hashes, this is -1 + * if the hash code isn't known yet. + */ long hash; + + /* If wr_object is weakly referenced, wr_object has a doubly-linked NULL- + * terminated list of weak references to it. These are the list pointers. + * If wr_object goes away, wr_object is set to Py_None, and these pointers + * have no meaning then. + */ PyWeakReference *wr_prev; PyWeakReference *wr_next; }; From tim_one at users.sourceforge.net Sun Oct 31 01:09:52 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 01:09:57 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_gc.py,1.30,1.31 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22636/Lib/test Modified Files: test_gc.py Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. I'll backport to 2.3. Index: test_gc.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_gc.py,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- test_gc.py 8 Apr 2003 19:44:13 -0000 1.30 +++ test_gc.py 30 Oct 2004 23:09:20 -0000 1.31 @@ -1,6 +1,7 @@ from test.test_support import verify, verbose, TestFailed, vereq import sys import gc +import weakref def expect(actual, expected, name): if actual != expected: @@ -369,6 +370,191 @@ expect(gc.get_referents(1, 'a', 4j), [], "get_referents") +# Bug 1055820 has several tests of longstanding bugs involving weakrefs and +# cyclic gc. + +# An instance of C1055820 has a self-loop, so becomes cyclic trash when +# unreachable. +class C1055820(object): + def __init__(self, i): + self.i = i + self.loop = self + +class GC_Detector(object): + # Create an instance I. Then gc hasn't happened again so long as + # I.gc_happened is false. + + def __init__(self): + self.gc_happened = False + + def it_happened(ignored): + self.gc_happened = True + + # Create a piece of cyclic trash that triggers it_happened when + # gc collects it. + self.wr = weakref.ref(C1055820(666), it_happened) + +def test_bug1055820b(): + # Corresponds to temp2b.py in the bug report. + + ouch = [] + def callback(ignored): + ouch[:] = [wr() for wr in WRs] + + Cs = [C1055820(i) for i in range(2)] + WRs = [weakref.ref(c, callback) for c in Cs] + c = None + + gc.collect() + expect(len(ouch), 0, "bug1055820b") + # Make the two instances trash, and collect again. The bug was that + # the callback materialized a strong reference to an instance, but gc + # cleared the instance's dict anyway. + Cs = None + gc.collect() + expect(len(ouch), 2, "bug1055820b") # else the callbacks didn't run + for x in ouch: + # If the callback resurrected one of these guys, the instance + # would be damaged, with an empty __dict__. + expect(x, None, "bug1055820b") + +def test_bug1055820c(): + # Corresponds to temp2c.py in the bug report. This is pretty elaborate. + + c0 = C1055820(0) + # Move c0 into generation 2. + gc.collect() + + c1 = C1055820(1) + c1.keep_c0_alive = c0 + del c0.loop # now only c1 keeps c0 alive + + c2 = C1055820(2) + c2wr = weakref.ref(c2) # no callback! + + ouch = [] + def callback(ignored): + ouch[:] = [c2wr()] + + # The callback gets associated with a wr on an object in generation 2. + c0wr = weakref.ref(c0, callback) + + c0 = c1 = c2 = None + + # What we've set up: c0, c1, and c2 are all trash now. c0 is in + # generation 2. The only thing keeping it alive is that c1 points to it. + # c1 and c2 are in generation 0, and are in self-loops. There's a global + # weakref to c2 (c2wr), but that weakref has no callback. There's also + # a global weakref to c0 (c0wr), and that does have a callback, and that + # callback references c2 via c2wr(). + # + # c0 has a wr with callback, which references c2wr + # ^ + # | + # | Generation 2 above dots + #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . + # | Generation 0 below dots + # | + # | + # ^->c1 ^->c2 has a wr but no callback + # | | | | + # <--v <--v + # + # So this is the nightmare: when generation 0 gets collected, we see that + # c2 has a callback-free weakref, and c1 doesn't even have a weakref. + # Collecting generation 0 doesn't see c0 at all, and c0 is the only object + # that has a weakref with a callback. gc clears c1 and c2. Clearing c1 + # has the side effect of dropping the refcount on c0 to 0, so c0 goes + # away (despite that it's in an older generation) and c0's wr callback + # triggers. That in turn materializes a reference to c2 via c2wr(), but + # c2 gets cleared anyway by gc. + + # We want to let gc happen "naturally", to preserve the distinction + # between generations. + junk = [] + i = 0 + detector = GC_Detector() + while not detector.gc_happened: + i += 1 + if i > 10000: + raise TestFailed("gc didn't happen after 10000 iterations") + expect(len(ouch), 0, "bug1055820c") + junk.append([]) # this will eventually trigger gc + + expect(len(ouch), 1, "bug1055820c") # else the callback wasn't invoked + for x in ouch: + # If the callback resurrected c2, the instance would be damaged, + # with an empty __dict__. + expect(x, None, "bug1055820c") + +def test_bug1055820d(): + # Corresponds to temp2d.py in the bug report. This is very much like + # test_bug1055820c, but uses a __del__ method instead of a weakref + # callback to sneak in a resurrection of cyclic trash. + + ouch = [] + class D(C1055820): + def __del__(self): + ouch[:] = [c2wr()] + + d0 = D(0) + # Move all the above into generation 2. + gc.collect() + + c1 = C1055820(1) + c1.keep_d0_alive = d0 + del d0.loop # now only c1 keeps d0 alive + + c2 = C1055820(2) + c2wr = weakref.ref(c2) # no callback! + + d0 = c1 = c2 = None + + # What we've set up: d0, c1, and c2 are all trash now. d0 is in + # generation 2. The only thing keeping it alive is that c1 points to it. + # c1 and c2 are in generation 0, and are in self-loops. There's a global + # weakref to c2 (c2wr), but that weakref has no callback. There are no + # other weakrefs. + # + # d0 has a __del__ method that references c2wr + # ^ + # | + # | Generation 2 above dots + #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . + # | Generation 0 below dots + # | + # | + # ^->c1 ^->c2 has a wr but no callback + # | | | | + # <--v <--v + # + # So this is the nightmare: when generation 0 gets collected, we see that + # c2 has a callback-free weakref, and c1 doesn't even have a weakref. + # Collecting generation 0 doesn't see d0 at all. gc clears c1 and c2. + # Clearing c1 has the side effect of dropping the refcount on d0 to 0, so + # d0 goes away (despite that it's in an older generation) and d0's __del__ + # triggers. That in turn materializes a reference to c2 via c2wr(), but + # c2 gets cleared anyway by gc. + + # We want to let gc happen "naturally", to preserve the distinction + # between generations. + detector = GC_Detector() + junk = [] + i = 0 + while not detector.gc_happened: + i += 1 + if i > 10000: + raise TestFailed("gc didn't happen after 10000 iterations") + expect(len(ouch), 0, "bug1055820d") + junk.append([]) # this will eventually trigger gc + + expect(len(ouch), 1, "bug1055820d") # else __del__ wasn't invoked + for x in ouch: + # If __del__ resurrected c2, the instance would be damaged, with an + # empty __dict__. + expect(x, None, "bug1055820d") + + def test_all(): gc.collect() # Delete 2nd generation garbage run_test("lists", test_list) @@ -392,6 +578,19 @@ run_test("boom_new", test_boom_new) run_test("boom2_new", test_boom2_new) run_test("get_referents", test_get_referents) + run_test("bug1055820b", test_bug1055820b) + + gc.enable() + try: + run_test("bug1055820c", test_bug1055820c) + finally: + gc.disable() + + gc.enable() + try: + run_test("bug1055820d", test_bug1055820d) + finally: + gc.disable() def test(): if verbose: From tim_one at users.sourceforge.net Sun Oct 31 02:13:34 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 02:13:38 2004 Subject: [Python-checkins] python/dist/src/Objects weakrefobject.c, 1.13.6.4, 1.13.6.5 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2582/Objects Modified Files: Tag: release23-maint weakrefobject.c Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear all weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. Index: weakrefobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/weakrefobject.c,v retrieving revision 1.13.6.4 retrieving revision 1.13.6.5 diff -u -d -r1.13.6.4 -r1.13.6.5 --- weakrefobject.c 3 Aug 2004 14:46:57 -0000 1.13.6.4 +++ weakrefobject.c 31 Oct 2004 00:13:07 -0000 1.13.6.5 @@ -742,7 +742,9 @@ return PyWeakref_GET_OBJECT(ref); } - +/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's + * handle_weakrefs(). + */ static void handle_callback(PyWeakReference *ref, PyObject *callback) { From tim_one at users.sourceforge.net Sun Oct 31 02:13:37 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 02:13:41 2004 Subject: [Python-checkins] python/dist/src/Include weakrefobject.h, 1.3.14.1, 1.3.14.2 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2582/Include Modified Files: Tag: release23-maint weakrefobject.h Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear all weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. Index: weakrefobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/weakrefobject.h,v retrieving revision 1.3.14.1 retrieving revision 1.3.14.2 diff -u -d -r1.3.14.1 -r1.3.14.2 --- weakrefobject.h 20 Nov 2003 22:13:50 -0000 1.3.14.1 +++ weakrefobject.h 31 Oct 2004 00:13:04 -0000 1.3.14.2 @@ -9,11 +9,31 @@ typedef struct _PyWeakReference PyWeakReference; +/* PyWeakReference is the base struct for the Python ReferenceType, ProxyType, + * and CallableProxyType. + */ struct _PyWeakReference { PyObject_HEAD + + /* The object to which this is a weak reference, or Py_None if none. + * Note that this is a stealth reference: wr_object's refcount is + * not incremented to reflect this pointer. + */ PyObject *wr_object; + + /* A callable to invoke when wr_object dies, or NULL if none. */ PyObject *wr_callback; + + /* A cache for wr_object's hash code. As usual for hashes, this is -1 + * if the hash code isn't known yet. + */ long hash; + + /* If wr_object is weakly referenced, wr_object has a doubly-linked NULL- + * terminated list of weak references to it. These are the list pointers. + * If wr_object goes away, wr_object is set to Py_None, and these pointers + * have no meaning then. + */ PyWeakReference *wr_prev; PyWeakReference *wr_next; }; From tim_one at users.sourceforge.net Sun Oct 31 02:13:38 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 02:13:42 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_gc.py, 1.30, 1.30.10.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2582/Lib/test Modified Files: Tag: release23-maint test_gc.py Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear all weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. Index: test_gc.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_gc.py,v retrieving revision 1.30 retrieving revision 1.30.10.1 diff -u -d -r1.30 -r1.30.10.1 --- test_gc.py 8 Apr 2003 19:44:13 -0000 1.30 +++ test_gc.py 31 Oct 2004 00:13:04 -0000 1.30.10.1 @@ -1,6 +1,7 @@ from test.test_support import verify, verbose, TestFailed, vereq import sys import gc +import weakref def expect(actual, expected, name): if actual != expected: @@ -369,6 +370,191 @@ expect(gc.get_referents(1, 'a', 4j), [], "get_referents") +# Bug 1055820 has several tests of longstanding bugs involving weakrefs and +# cyclic gc. + +# An instance of C1055820 has a self-loop, so becomes cyclic trash when +# unreachable. +class C1055820(object): + def __init__(self, i): + self.i = i + self.loop = self + +class GC_Detector(object): + # Create an instance I. Then gc hasn't happened again so long as + # I.gc_happened is false. + + def __init__(self): + self.gc_happened = False + + def it_happened(ignored): + self.gc_happened = True + + # Create a piece of cyclic trash that triggers it_happened when + # gc collects it. + self.wr = weakref.ref(C1055820(666), it_happened) + +def test_bug1055820b(): + # Corresponds to temp2b.py in the bug report. + + ouch = [] + def callback(ignored): + ouch[:] = [wr() for wr in WRs] + + Cs = [C1055820(i) for i in range(2)] + WRs = [weakref.ref(c, callback) for c in Cs] + c = None + + gc.collect() + expect(len(ouch), 0, "bug1055820b") + # Make the two instances trash, and collect again. The bug was that + # the callback materialized a strong reference to an instance, but gc + # cleared the instance's dict anyway. + Cs = None + gc.collect() + expect(len(ouch), 2, "bug1055820b") # else the callbacks didn't run + for x in ouch: + # If the callback resurrected one of these guys, the instance + # would be damaged, with an empty __dict__. + expect(x, None, "bug1055820b") + +def test_bug1055820c(): + # Corresponds to temp2c.py in the bug report. This is pretty elaborate. + + c0 = C1055820(0) + # Move c0 into generation 2. + gc.collect() + + c1 = C1055820(1) + c1.keep_c0_alive = c0 + del c0.loop # now only c1 keeps c0 alive + + c2 = C1055820(2) + c2wr = weakref.ref(c2) # no callback! + + ouch = [] + def callback(ignored): + ouch[:] = [c2wr()] + + # The callback gets associated with a wr on an object in generation 2. + c0wr = weakref.ref(c0, callback) + + c0 = c1 = c2 = None + + # What we've set up: c0, c1, and c2 are all trash now. c0 is in + # generation 2. The only thing keeping it alive is that c1 points to it. + # c1 and c2 are in generation 0, and are in self-loops. There's a global + # weakref to c2 (c2wr), but that weakref has no callback. There's also + # a global weakref to c0 (c0wr), and that does have a callback, and that + # callback references c2 via c2wr(). + # + # c0 has a wr with callback, which references c2wr + # ^ + # | + # | Generation 2 above dots + #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . + # | Generation 0 below dots + # | + # | + # ^->c1 ^->c2 has a wr but no callback + # | | | | + # <--v <--v + # + # So this is the nightmare: when generation 0 gets collected, we see that + # c2 has a callback-free weakref, and c1 doesn't even have a weakref. + # Collecting generation 0 doesn't see c0 at all, and c0 is the only object + # that has a weakref with a callback. gc clears c1 and c2. Clearing c1 + # has the side effect of dropping the refcount on c0 to 0, so c0 goes + # away (despite that it's in an older generation) and c0's wr callback + # triggers. That in turn materializes a reference to c2 via c2wr(), but + # c2 gets cleared anyway by gc. + + # We want to let gc happen "naturally", to preserve the distinction + # between generations. + junk = [] + i = 0 + detector = GC_Detector() + while not detector.gc_happened: + i += 1 + if i > 10000: + raise TestFailed("gc didn't happen after 10000 iterations") + expect(len(ouch), 0, "bug1055820c") + junk.append([]) # this will eventually trigger gc + + expect(len(ouch), 1, "bug1055820c") # else the callback wasn't invoked + for x in ouch: + # If the callback resurrected c2, the instance would be damaged, + # with an empty __dict__. + expect(x, None, "bug1055820c") + +def test_bug1055820d(): + # Corresponds to temp2d.py in the bug report. This is very much like + # test_bug1055820c, but uses a __del__ method instead of a weakref + # callback to sneak in a resurrection of cyclic trash. + + ouch = [] + class D(C1055820): + def __del__(self): + ouch[:] = [c2wr()] + + d0 = D(0) + # Move all the above into generation 2. + gc.collect() + + c1 = C1055820(1) + c1.keep_d0_alive = d0 + del d0.loop # now only c1 keeps d0 alive + + c2 = C1055820(2) + c2wr = weakref.ref(c2) # no callback! + + d0 = c1 = c2 = None + + # What we've set up: d0, c1, and c2 are all trash now. d0 is in + # generation 2. The only thing keeping it alive is that c1 points to it. + # c1 and c2 are in generation 0, and are in self-loops. There's a global + # weakref to c2 (c2wr), but that weakref has no callback. There are no + # other weakrefs. + # + # d0 has a __del__ method that references c2wr + # ^ + # | + # | Generation 2 above dots + #. . . . . . . .|. . . . . . . . . . . . . . . . . . . . . . . . + # | Generation 0 below dots + # | + # | + # ^->c1 ^->c2 has a wr but no callback + # | | | | + # <--v <--v + # + # So this is the nightmare: when generation 0 gets collected, we see that + # c2 has a callback-free weakref, and c1 doesn't even have a weakref. + # Collecting generation 0 doesn't see d0 at all. gc clears c1 and c2. + # Clearing c1 has the side effect of dropping the refcount on d0 to 0, so + # d0 goes away (despite that it's in an older generation) and d0's __del__ + # triggers. That in turn materializes a reference to c2 via c2wr(), but + # c2 gets cleared anyway by gc. + + # We want to let gc happen "naturally", to preserve the distinction + # between generations. + detector = GC_Detector() + junk = [] + i = 0 + while not detector.gc_happened: + i += 1 + if i > 10000: + raise TestFailed("gc didn't happen after 10000 iterations") + expect(len(ouch), 0, "bug1055820d") + junk.append([]) # this will eventually trigger gc + + expect(len(ouch), 1, "bug1055820d") # else __del__ wasn't invoked + for x in ouch: + # If __del__ resurrected c2, the instance would be damaged, with an + # empty __dict__. + expect(x, None, "bug1055820d") + + def test_all(): gc.collect() # Delete 2nd generation garbage run_test("lists", test_list) @@ -392,6 +578,19 @@ run_test("boom_new", test_boom_new) run_test("boom2_new", test_boom2_new) run_test("get_referents", test_get_referents) + run_test("bug1055820b", test_bug1055820b) + + gc.enable() + try: + run_test("bug1055820c", test_bug1055820c) + finally: + gc.disable() + + gc.enable() + try: + run_test("bug1055820d", test_bug1055820d) + finally: + gc.disable() def test(): if verbose: From tim_one at users.sourceforge.net Sun Oct 31 02:13:39 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 02:13:46 2004 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.831.4.156, 1.831.4.157 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2582/Misc Modified Files: Tag: release23-maint NEWS Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear all weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.831.4.156 retrieving revision 1.831.4.157 diff -u -d -r1.831.4.156 -r1.831.4.157 --- NEWS 20 Oct 2004 11:55:54 -0000 1.831.4.156 +++ NEWS 31 Oct 2004 00:13:05 -0000 1.831.4.157 @@ -12,6 +12,17 @@ Core and builtins ----------------- +- Bug #1055820 Cyclic garbage collection was not protecting against that + calling a live weakref to a piece of cyclic trash could resurrect an + insane mutation of the trash if any Python code ran during gc (via + running a dead object's __del__ method, running another callback on a + weakref to a dead object, or via any Python code run in any other thread + that managed to obtain the GIL while a __del__ or callback was running + in the thread doing gc). The most likely symptom was "impossible" + ``AttributeEror`` exceptions, appearing seemingly at random, on weakly + referenced objects. The cure was to clear all weakrefs to unreachable + objects before allowing any callbacks to run. + - Bug #951851: Python crashed when reading import table of certain Windows DLLs @@ -88,7 +99,7 @@ - Bug #679953: zipfile can now handle file sizes over 2 GB. Previously the compressed and uncompressed file sizes were being stored as signed longs instead of unsigned as the ZIP spec specifies. - + - Bug #981530: Fix UnboundLocalError in shutil.rmtree(). This affects the documented behavior: the function passed to the onerror() handler can now also be os.listdir. @@ -134,7 +145,7 @@ - Bug #1034496: Use -h instead of -soname for Solaris compatibility. -- Patch #973204: Use -rpath instead of -R for runtime_library_dirs +- Patch #973204: Use -rpath instead of -R for runtime_library_dirs on Irix and True64. - Bug #978645: Modules/getpath.c now builds properly under --disable-framework From tim_one at users.sourceforge.net Sun Oct 31 02:13:40 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 02:13:47 2004 Subject: [Python-checkins] python/dist/src/Modules gc_weakref.txt, 2.1.2.1, 2.1.2.2 gcmodule.c, 2.71.10.2, 2.71.10.3 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2582/Modules Modified Files: Tag: release23-maint gc_weakref.txt gcmodule.c Log Message: SF 1055820: weakref callback vs gc vs threads In cyclic gc, clear all weakrefs to unreachable objects before allowing any Python code (weakref callbacks or __del__ methods) to run. This is a critical bugfix, affecting all versions of Python since weakrefs were introduced. Index: gc_weakref.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/gc_weakref.txt,v retrieving revision 2.1.2.1 retrieving revision 2.1.2.2 diff -u -d -r2.1.2.1 -r2.1.2.2 --- gc_weakref.txt 20 Nov 2003 22:13:51 -0000 2.1.2.1 +++ gc_weakref.txt 31 Oct 2004 00:13:06 -0000 2.1.2.2 @@ -1,3 +1,79 @@ +Intro +===== + +The basic rule for dealing with weakref callbacks (and __del__ methods too, +for that matter) during cyclic gc: + + Once gc has computed the set of unreachable objects, no Python-level + code can be allowed to access an unreachable object. + +If that can happen, then the Python code can resurrect unreachable objects +too, and gc can't detect that without starting over. Since gc eventually +runs tp_clear on all unreachable objects, if an unreachable object is +resurrected then tp_clear will eventually be called on it (or may already +have been called before resurrection). At best (and this has been an +historically common bug), tp_clear empties an instance's __dict__, and +"impossible" AttributeErrors result. At worst, tp_clear leaves behind an +insane object at the C level, and segfaults result (historically, most +often by setting a new-style class's mro pointer to NULL, after which +attribute lookups performed by the class can segfault). + +OTOH, it's OK to run Python-level code that can't access unreachable +objects, and sometimes that's necessary. The chief example is the callback +attached to a reachable weakref W to an unreachable object O. Since O is +going away, and W is still alive, the callback must be invoked. Because W +is still alive, everything reachable from its callback is also reachable, +so it's also safe to invoke the callback (although that's trickier than it +sounds, since other reachable weakrefs to other unreachable objects may +still exist, and be accessible to the callback -- there are lots of painful +details like this covered in the rest of this file). + +Python 2.4/2.3.5 +================ + +The "Before 2.3.3" section below turned out to be wrong in some ways, but +I'm leaving it as-is because it's more right than wrong, and serves as a +wonderful example of how painful analysis can miss not only the forest for +the trees, but also miss the trees for the aphids sucking the trees +dry . + +The primary thing it missed is that when a weakref to a piece of cyclic +trash (CT) exists, then any call to any Python code whatsoever can end up +materializing a strong reference to that weakref's CT referent, and so +possibly resurrect an insane object (one for which cyclic gc has called-- or +will call before it's done --tp_clear()). It's not even necessarily that a +weakref callback or __del__ method does something nasty on purpose: as +soon as we execute Python code, threads other than the gc thread can run +too, and they can do ordinary things with weakrefs that end up resurrecting +CT while gc is running. + + http://www.python.org/sf/1055820 + +shows how innocent it can be, and also how nasty. Variants of the three +focussed test cases attached to that bug report are now part of Python's +standard Lib/test/test_gc.py. + +Jim Fulton gave the best nutshell summary of the new (in 2.4 and 2.3.5) +approach: + + Clearing cyclic trash can call Python code. If there are weakrefs to + any of the cyclic trash, then those weakrefs can be used to resurrect + the objects. Therefore, *before* clearing cyclic trash, we need to + remove any weakrefs. If any of the weakrefs being removed have + callbacks, then we need to save the callbacks and call them *after* all + of the weakrefs have been cleared. + +Alas, doing just that much doesn't work, because it overlooks what turned +out to be the much subtler problems that were fixed earlier, and described +below. We do clear all weakrefs to CT now before breaking cycles, but not +all callbacks encountered can be run later. That's explained in horrid +detail below. + +Older text follows, with a some later comments in [] brackets: + +Before 2.3.3 +============ + Before 2.3.3, Python's cyclic gc didn't pay any attention to weakrefs. Segfaults in Zope3 resulted. @@ -19,12 +95,19 @@ happen at any later time if the callback manages to resurrect an insane object. +[That missed that, in addition, a weakref to CT can exist outside CT, and + any callback into Python can use such a non-CT weakref to resurrect its CT + referent. The same bad kinds of things can happen then.] + Note that if it's possible for the callback to get at objects in the trash cycles, it must also be the case that the callback itself is part of the trash cycles. Else the callback would have acted as an external root to the current collection, and nothing reachable from it would be in cyclic trash either. +[Except that a non-CT callback can also use a non-CT weakref to get at + CT objects.] + More, if the callback itself is in cyclic trash, then the weakref to which the callback is attached must also be trash, and for the same kind of reason: if the weakref acted as an external root, then the callback could @@ -47,6 +130,13 @@ a feature of Python's weakrefs too that when a weakref goes away, the callback (if any) associated with it is thrown away too, unexecuted. +[In 2.4/2.3.5, we first clear all weakrefs to CT objects, whether or not + those weakrefs are themselves CT, and whether or not they have callbacks. + The callbacks (if any) on non-CT weakrefs (if any) are invoked later, + after all weakrefs-to-CT have been cleared. The callbacks (if any) on CT + weakrefs (if any) are never invoked, for the excruciating reasons + explained here.] + Just that much is almost enough to prevent problems, by throwing away *almost* all the weakref callbacks that could get triggered by gc. The problem remaining is that clearing a weakref with a callback decrefs the @@ -56,7 +146,15 @@ latter weakrefs may or may not be part of cyclic trash. So, to prevent any Python code from running while gc is invoking tp_clear() -on all the objects in cyclic trash, it's not quite enough just to invoke +on all the objects in cyclic trash, + +[That was always wrong: we can't stop Python code from running when gc + is breaking cycles. If an object with a __del__ method is not itself in + a cycle, but is reachable only from CT, then breaking cycles will, as a + matter of course, drop the refcount on that object to 0, and its __del__ + will run right then. What we can and must stop is running any Python + code that could access CT.] + it's not quite enough just to invoke tp_clear() on weakrefs with callbacks first. Instead the weakref module grew a new private function (_PyWeakref_ClearRef) that does only part of tp_clear(): it removes the weakref from the weakly-referenced object's list @@ -65,9 +163,13 @@ trigger, and (unlike weakref's tp_clear()) also prevents any callback associated *with* wr's callback object from triggering. +[Although we may trigger such callbacks later, as explained below.] + Then we can call tp_clear on all the cyclic objects and never trigger Python code. +[As above, not so: it means never trigger Python code that can access CT.] + After we do that, the callback objects still need to be decref'ed. Callbacks (if any) *on* the callback objects that were also part of cyclic trash won't get invoked, because we cleared all trash weakrefs with callbacks at the @@ -76,6 +178,10 @@ reachable from them was part of cyclic trash, so gc didn't do any damage to objects reachable from them, and it's safe to call them at the end of gc. +[That's so. In addition, now we also invoke (if any) the callbacks on + non-CT weakrefs to CT objects, during the same pass that decrefs the + callback objects.] + An alternative would have been to treat objects with callbacks like objects with __del__ methods, refusing to collect them, appending them to gc.garbage instead. That would have been much easier. Jim Fulton gave a strong @@ -105,3 +211,9 @@ However, a weakref callback on a weakref callback has got to be rare. It's possible to do such a thing, so gc has to be robust against it, but I doubt anyone has done it outside the test case I wrote for it. + +[The callbacks (if any) on non-CT weakrefs to CT objects are also executed + in an arbitrary order now. But they were before too, depending on the + vagaries of when tp_clear() happened to break enough cycles to trigger + them. People simply shouldn't try to use __del__ or weakref callbacks to + do fancy stuff.] Index: gcmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/gcmodule.c,v retrieving revision 2.71.10.2 retrieving revision 2.71.10.3 diff -u -d -r2.71.10.2 -r2.71.10.3 --- gcmodule.c 24 Nov 2003 04:02:31 -0000 2.71.10.2 +++ gcmodule.c 31 Oct 2004 00:13:06 -0000 2.71.10.3 @@ -377,38 +377,30 @@ return 0; } -/* Move the objects in unreachable with __del__ methods into finalizers, - * and weakrefs with callbacks into wr_callbacks. - * The objects remaining in unreachable do not have __del__ methods, and are - * not weakrefs with callbacks. - * The objects moved have gc_refs changed to GC_REACHABLE; the objects - * remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE. +/* Move the objects in unreachable with __del__ methods into `finalizers`. + * Objects moved into `finalizers` have gc_refs set to GC_REACHABLE; the + * objects remaining in unreachable are left at GC_TENTATIVELY_UNREACHABLE. */ static void -move_troublemakers(PyGC_Head *unreachable, - PyGC_Head *finalizers, - PyGC_Head *wr_callbacks) +move_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers) { - PyGC_Head *gc = unreachable->gc.gc_next; + PyGC_Head *gc; + PyGC_Head *next; - while (gc != unreachable) { + /* March over unreachable. Move objects with finalizers into + * `finalizers`. + */ + for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { PyObject *op = FROM_GC(gc); - PyGC_Head *next = gc->gc.gc_next; assert(IS_TENTATIVELY_UNREACHABLE(op)); + next = gc->gc.gc_next; if (has_finalizer(op)) { gc_list_remove(gc); gc_list_append(gc, finalizers); gc->gc.gc_refs = GC_REACHABLE; } - else if (PyWeakref_Check(op) && - ((PyWeakReference *)op)->wr_callback) { - gc_list_remove(gc); - gc_list_append(gc, wr_callbacks); - gc->gc.gc_refs = GC_REACHABLE; - } - gc = next; } } @@ -444,82 +436,180 @@ } } -/* Clear all trash weakrefs with callbacks. This clears weakrefs first, - * which has the happy result of disabling the callbacks without executing - * them. A nasty technical complication: a weakref callback can itself be - * the target of a weakref, in which case decrefing the callback can cause - * another callback to trigger. But we can't allow arbitrary Python code to - * get executed at this point (the callback on the callback may try to muck - * with other cyclic trash we're trying to collect, even resurrecting it - * while we're in the middle of doing tp_clear() on the trash). - * - * The private _PyWeakref_ClearRef() function exists so that we can clear - * the reference in a weakref without triggering a callback on the callback. - * - * We have to save the callback objects and decref them later. But we can't - * allocate new memory to save them (if we can't get new memory, we're dead). - * So we grab a new reference on the clear'ed weakref, which prevents the - * rest of gc from reclaiming it. _PyWeakref_ClearRef() leaves the - * weakref's wr_callback member intact. - * - * In the end, then, wr_callbacks consists of cleared weakrefs that are - * immune from collection. Near the end of gc, after collecting all the - * cyclic trash, we call release_weakrefs(). That releases our references - * to the cleared weakrefs, which in turn may trigger callbacks on their - * callbacks. +/* Clear all weakrefs to unreachable objects, and if such a weakref has a + * callback, invoke it if necessary. Note that it's possible for such + * weakrefs to be outside the unreachable set -- indeed, those are precisely + * the weakrefs whose callbacks must be invoked. See gc_weakref.txt for + * overview & some details. Some weakrefs with callbacks may be reclaimed + * directly by this routine; the number reclaimed is the return value. Other + * weakrefs with callbacks may be moved into the `old` generation. Objects + * moved into `old` have gc_refs set to GC_REACHABLE; the objects remaining in + * unreachable are left at GC_TENTATIVELY_UNREACHABLE. When this returns, + * no object in `unreachable` is weakly referenced anymore. */ -static void -clear_weakrefs(PyGC_Head *wr_callbacks) +static int +handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old) { - PyGC_Head *gc = wr_callbacks->gc.gc_next; + PyGC_Head *gc; + PyObject *op; /* generally FROM_GC(gc) */ + PyWeakReference *wr; /* generally a cast of op */ - for (; gc != wr_callbacks; gc = gc->gc.gc_next) { - PyObject *op = FROM_GC(gc); - PyWeakReference *wr; + PyGC_Head wrcb_to_call; /* weakrefs with callbacks to call */ + PyGC_Head wrcb_to_kill; /* weakrefs with callbacks to ignore */ + + PyGC_Head *next; + int num_freed = 0; + + gc_list_init(&wrcb_to_call); + gc_list_init(&wrcb_to_kill); + + /* Clear all weakrefs to the objects in unreachable. If such a weakref + * also has a callback, move it into `wrcb_to_call` if the callback + * needs to be invoked, or into `wrcb_to_kill` if the callback should + * be ignored. Note that we cannot invoke any callbacks until all + * weakrefs to unreachable objects are cleared, lest the callback + * resurrect an unreachable object via a still-active weakref. That's + * why the weakrefs with callbacks are moved into different lists -- we + * make another pass over those lists after this pass completes. + */ + for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { + PyWeakReference **wrlist; + + op = FROM_GC(gc); + assert(IS_TENTATIVELY_UNREACHABLE(op)); + next = gc->gc.gc_next; + + if (! PyType_SUPPORTS_WEAKREFS(op->ob_type)) + continue; + + /* It supports weakrefs. Does it have any? */ + wrlist = (PyWeakReference **) + PyObject_GET_WEAKREFS_LISTPTR(op); + + /* `op` may have some weakrefs. March over the list, clear + * all the weakrefs, and move the weakrefs with callbacks + * into one of the wrcb_to_{call,kill} lists. + */ + for (wr = *wrlist; wr != NULL; wr = *wrlist) { + PyGC_Head *wrasgc; /* AS_GC(wr) */ + + /* _PyWeakref_ClearRef clears the weakref but leaves + * the callback pointer intact. Obscure: it also + * changes *wrlist. + */ + assert(wr->wr_object == op); + _PyWeakref_ClearRef(wr); + assert(wr->wr_object == Py_None); + if (wr->wr_callback == NULL) + continue; /* no callback */ + /* Headache time. `op` is going away, and is weakly referenced by + * `wr`, which has a callback. Should the callback be invoked? If wr + * is also trash, no: + * + * 1. There's no need to call it. The object and the weakref are + * both going away, so it's legitimate to pretend the weakref is + * going away first. The user has to ensure a weakref outlives its + * referent if they want a guarantee that the wr callback will get + * invoked. + * + * 2. It may be catastrophic to call it. If the callback is also in + * cyclic trash (CT), then although the CT is unreachable from + * outside the current generation, CT may be reachable from the + * callback. Then the callback could resurrect insane objects. + * + * Since the callback is never needed and may be unsafe in this case, + * wr is moved to wrcb_to_kill. + * + * OTOH, if wr isn't part of CT, we should invoke the callback: the + * weakref outlived the trash. Note that since wr isn't CT in this + * case, its callback can't be CT either -- wr acted as an external + * root to this generation, and therefore its callback did too. So + * nothing in CT is reachable from the callback either, so it's hard + * to imagine how calling it later could create a problem for us. wr + * is moved to wrcb_to_call in this case. + * + * Obscure: why do we move weakrefs with ignored callbacks to a list + * we crawl over later, instead of getting rid of the callback right + * now? It's because the obvious way doesn't work: setting + * wr->wr_callback to NULL requires that we decref the current + * wr->wr_callback. But callbacks are also weakly referenceable, so + * wr->wr_callback may *itself* be referenced by another weakref with + * another callback. The latter callback could get triggered now if + * we decref'ed now, but as explained before it's potentially unsafe to + * invoke any callback before all weakrefs to CT are cleared. + */ + /* Create a new reference so that wr can't go away + * before we can process it again. + */ + Py_INCREF(wr); + + /* Move wr to the appropriate list. */ + wrasgc = AS_GC(wr); + if (wrasgc == next) + next = wrasgc->gc.gc_next; + gc_list_remove(wrasgc); + gc_list_append(wrasgc, + IS_TENTATIVELY_UNREACHABLE(wr) ? + &wrcb_to_kill : &wrcb_to_call); + wrasgc->gc.gc_refs = GC_REACHABLE; + } + } + + /* Now that all weakrefs to trash have been cleared, it's safe to + * decref the callbacks we decided to ignore. We cannot invoke + * them because they may be able to resurrect unreachable (from + * outside) objects. + */ + while (! gc_list_is_empty(&wrcb_to_kill)) { + gc = wrcb_to_kill.gc.gc_next; + op = FROM_GC(gc); assert(IS_REACHABLE(op)); assert(PyWeakref_Check(op)); - wr = (PyWeakReference *)op; - assert(wr->wr_callback != NULL); - Py_INCREF(op); - _PyWeakref_ClearRef(wr); - } -} + assert(((PyWeakReference *)op)->wr_callback != NULL); -/* Called near the end of gc. This gives up the references we own to - * cleared weakrefs, allowing them to get collected, and in turn decref'ing - * their callbacks. - * - * If a callback object is itself the target of a weakref callback, - * decref'ing the callback object may trigger that other callback. If - * that other callback was part of the cyclic trash in this generation, - * that won't happen, since we cleared *all* trash-weakref callbacks near - * the start of gc. If that other callback was not part of the cyclic trash - * in this generation, then it acted like an external root to this round - * of gc, so all the objects reachable from that callback are still alive. - * - * Giving up the references to the weakref objects will probably make - * them go away too. However, if a weakref is reachable from finalizers, - * it won't go away. We move it to the old generation then. Since a - * weakref object doesn't have a finalizer, that's the right thing to do (it - * doesn't belong in gc.garbage). - * - * We return the number of weakref objects freed (those not appended to old). - */ -static int -release_weakrefs(PyGC_Head *wr_callbacks, PyGC_Head *old) -{ - int num_freed = 0; + /* Give up the reference we created in the first pass. When + * op's refcount hits 0 (which it may or may not do right now), + * op's tp_dealloc will decref op->wr_callback too. + */ + Py_DECREF(op); + if (wrcb_to_kill.gc.gc_next == gc) { + /* object is still alive -- move it */ + gc_list_remove(gc); + gc_list_append(gc, old); + } + else + ++num_freed; + } - while (! gc_list_is_empty(wr_callbacks)) { - PyGC_Head *gc = wr_callbacks->gc.gc_next; - PyObject *op = FROM_GC(gc); + /* Finally, invoke the callbacks we decided to honor. It's safe to + * invoke them because they cannot reference objects in `unreachable`. + */ + while (! gc_list_is_empty(&wrcb_to_call)) { + PyObject *temp; + PyObject *callback; + gc = wrcb_to_call.gc.gc_next; + op = FROM_GC(gc); assert(IS_REACHABLE(op)); assert(PyWeakref_Check(op)); - assert(((PyWeakReference *)op)->wr_callback != NULL); + wr = (PyWeakReference *)op; + callback = wr->wr_callback; + assert(callback != NULL); + + /* copy-paste of weakrefobject.c's handle_callback() */ + temp = PyObject_CallFunction(callback, "O", wr); + if (temp == NULL) + PyErr_WriteUnraisable(callback); + else + Py_DECREF(temp); + + /* Give up the reference we created in the first pass. When + * op's refcount hits 0 (which it may or may not do right now), + * op's tp_dealloc will decref op->wr_callback too. + */ Py_DECREF(op); - if (wr_callbacks->gc.gc_next == gc) { + if (wrcb_to_call.gc.gc_next == gc) { /* object is still alive -- move it */ gc_list_remove(gc); gc_list_append(gc, old); @@ -527,6 +617,7 @@ else ++num_freed; } + return num_freed; } @@ -633,7 +724,6 @@ PyGC_Head *old; /* next older generation */ PyGC_Head unreachable; /* non-problematic unreachable trash */ PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ - PyGC_Head wr_callbacks; /* weakrefs with callbacks */ PyGC_Head *gc; if (delstr == NULL) { @@ -671,9 +761,9 @@ old = young; /* Using ob_refcnt and gc_refs, calculate which objects in the - * container set are reachable from outside the set (ie. have a + * container set are reachable from outside the set (i.e., have a * refcount greater than 0 when all the references within the - * set are taken into account + * set are taken into account). */ update_refs(young); subtract_refs(young); @@ -695,23 +785,11 @@ * finalizers can't safely be deleted. Python programmers should take * care not to create such things. For Python, finalizers means * instance objects with __del__ methods. Weakrefs with callbacks - * can call arbitrary Python code, so those are special-cased too. - * - * Move unreachable objects with finalizers, and weakrefs with - * callbacks, into different lists. + * can also call arbitrary Python code but they will be dealt with by + * handle_weakrefs(). */ gc_list_init(&finalizers); - gc_list_init(&wr_callbacks); - move_troublemakers(&unreachable, &finalizers, &wr_callbacks); - /* Clear the trash weakrefs with callbacks. This prevents their - * callbacks from getting invoked (when a weakref goes away, so does - * its callback). - * We do this even if the weakrefs are reachable from finalizers. - * If we didn't, breaking cycles in unreachable later could trigger - * deallocation of objects in finalizers, which could in turn - * cause callbacks to trigger. This may not be ideal behavior. - */ - clear_weakrefs(&wr_callbacks); + move_finalizers(&unreachable, &finalizers); /* finalizers contains the unreachable objects with a finalizer; * unreachable objects reachable *from* those are also uncollectable, * and we move those into the finalizers list too. @@ -728,17 +806,16 @@ debug_cycle("collectable", FROM_GC(gc)); } } + + /* Clear weakrefs and invoke callbacks as necessary. */ + m += handle_weakrefs(&unreachable, old); + /* Call tp_clear on objects in the unreachable set. This will cause * the reference cycles to be broken. It may also cause some objects * in finalizers to be freed. */ delete_garbage(&unreachable, old); - /* Now that we're done analyzing stuff and breaking cycles, let - * delayed weakref callbacks run. - */ - m += release_weakrefs(&wr_callbacks, old); - /* Collect statistics on uncollectable objects found and print * debugging information. */ for (gc = finalizers.gc.gc_next; From rhettinger at users.sourceforge.net Sun Oct 31 06:47:02 2004 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun Oct 31 06:47:06 2004 Subject: [Python-checkins] python/dist/src/Include unicodeobject.h, 2.46, 2.47 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26240 Modified Files: unicodeobject.h Log Message: SF patch #1056231: typo in comment (unicodeobject.h) Index: unicodeobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/unicodeobject.h,v retrieving revision 2.46 retrieving revision 2.47 diff -u -d -r2.46 -r2.47 --- unicodeobject.h 7 Sep 2004 20:24:04 -0000 2.46 +++ unicodeobject.h 31 Oct 2004 05:46:59 -0000 2.47 @@ -293,7 +293,7 @@ /* If you want Python to use the compiler's wctype.h functions instead of the ones supplied with Python, define WANT_WCTYPE_FUNCTIONS or - configure Python using --with-ctype-functions. This reduces the + configure Python using --with-wctype-functions. This reduces the interpreter's code size. */ #if defined(HAVE_USABLE_WCHAR_T) && defined(WANT_WCTYPE_FUNCTIONS) From jlgijsbers at users.sourceforge.net Sun Oct 31 13:05:34 2004 From: jlgijsbers at users.sourceforge.net (jlgijsbers@users.sourceforge.net) Date: Sun Oct 31 13:05:36 2004 Subject: [Python-checkins] python/dist/src/Lib/test test_shutil.py,1.7,1.8 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25638/test Modified Files: test_shutil.py Log Message: Bug #1048941: shutil.rmtree error handling was always broken Rewrite rmtree again, this time without os.walk(). Error handling had been broken since Python 2.3, and the os.walk() version inherited this. Index: test_shutil.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_shutil.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- test_shutil.py 11 Sep 2004 21:26:21 -0000 1.7 +++ test_shutil.py 31 Oct 2004 12:05:31 -0000 1.8 @@ -1,8 +1,10 @@ + # Copyright (C) 2003 Python Software Foundation import unittest import shutil import tempfile +import stat import os import os.path from test import test_support @@ -13,8 +15,32 @@ # filename is guaranteed not to exist filename = tempfile.mktemp() self.assertRaises(OSError, shutil.rmtree, filename) - self.assertEqual(shutil.rmtree(filename, True), None) - shutil.rmtree(filename, False, lambda func, arg, exc: None) + + if hasattr(os, 'chmod'): + def test_on_error(self): + self.errorState = 0 + os.mkdir(TESTFN) + f = open(os.path.join(TESTFN, 'a'), 'w') + f.close() + # Make TESTFN unwritable. + os.chmod(TESTFN, stat.S_IRUSR) + + shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) + + # Make TESTFN writable again. + os.chmod(TESTFN, stat.S_IRWXU) + shutil.rmtree(TESTFN) + + def check_args_to_onerror(self, func, arg, exc): + if self.errorState == 0: + self.assertEqual(func, os.remove) + self.assertEqual(arg, os.path.join(TESTFN, 'a')) + self.assertEqual(exc[0], OSError) + self.errorState = 1 + else: + self.assertEqual(func, os.rmdir) + self.assertEqual(arg, TESTFN) + self.assertEqual(exc[0], OSError) def test_rmtree_dont_delete_file(self): # When called on a file instead of a directory, don't delete it. @@ -63,7 +89,6 @@ except OSError: pass - def test_main(): test_support.run_unittest(TestShutil) From jlgijsbers at users.sourceforge.net Sun Oct 31 13:05:34 2004 From: jlgijsbers at users.sourceforge.net (jlgijsbers@users.sourceforge.net) Date: Sun Oct 31 13:05:38 2004 Subject: [Python-checkins] python/dist/src/Lib shutil.py,1.33,1.34 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25638 Modified Files: shutil.py Log Message: Bug #1048941: shutil.rmtree error handling was always broken Rewrite rmtree again, this time without os.walk(). Error handling had been broken since Python 2.3, and the os.walk() version inherited this. Index: shutil.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/shutil.py,v retrieving revision 1.33 retrieving revision 1.34 diff -u -d -r1.33 -r1.34 --- shutil.py 7 Oct 2004 21:10:08 -0000 1.33 +++ shutil.py 31 Oct 2004 12:05:31 -0000 1.34 @@ -127,39 +127,45 @@ if errors: raise Error, errors -def _raise_err(err): - raise err - def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. - If ignore_errors is set, errors are ignored; otherwise, if - onerror is set, it is called to handle the error; otherwise, an - exception is raised. + If ignore_errors is set, errors are ignored; otherwise, if onerror + is set, it is called to handle the error with arguments (func, + path, exc_info) where func is os.listdir, os.remove, or os.rmdir; + path is the argument to that function that caused it to fail; and + exc_info is a tuple returned by sys.exc_info(). If ignore_errors + is false and onerror is None, an exception is raised. + """ - # This strange way of calling functions is necessary to keep the onerror - # argument working. Maybe sys._getframe hackery would work as well, but - # this is simple. - func = os.listdir - arg = path - try: - for (dirpath, dirnames, filenames) in os.walk(path, topdown=False, - onerror=_raise_err): - for filename in filenames: - func = os.remove - arg = os.path.join(dirpath, filename) - func(arg) - func = os.rmdir - arg = dirpath - func(arg) - except OSError: - exc = sys.exc_info() - if ignore_errors: + if ignore_errors: + def onerror(*args): pass - elif onerror is not None: - onerror(func, arg, exc) + elif onerror is None: + def onerror(*args): + raise + names = [] + try: + names = os.listdir(path) + except os.error, err: + onerror(os.listdir, path, sys.exc_info()) + for name in names: + fullname = os.path.join(path, name) + try: + mode = os.lstat(fullname).st_mode + except os.error: + mode = 0 + if stat.S_ISDIR(mode): + rmtree(fullname, ignore_errors, onerror) else: - raise exc[0], (exc[1][0], exc[1][1] + ' removing '+arg) + try: + os.remove(fullname) + except os.error, err: + onerror(os.remove, fullname, sys.exc_info()) + try: + os.rmdir(path) + except os.error: + onerror(os.rmdir, path, sys.exc_info()) def move(src, dst): """Recursively move a file or directory to another location. From jlgijsbers at users.sourceforge.net Sun Oct 31 13:19:37 2004 From: jlgijsbers at users.sourceforge.net (jlgijsbers@users.sourceforge.net) Date: Sun Oct 31 13:19:41 2004 Subject: [Python-checkins] python/dist/src/Doc/lib libtime.tex,1.69,1.70 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29242 Modified Files: libtime.tex Log Message: Bug #1057535: add link in time module to calendar.timegm(). Index: libtime.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libtime.tex,v retrieving revision 1.69 retrieving revision 1.70 diff -u -d -r1.69 -r1.70 --- libtime.tex 18 Oct 2004 01:53:15 -0000 1.69 +++ libtime.tex 31 Oct 2004 12:19:34 -0000 1.70 @@ -176,7 +176,8 @@ in UTC in which the dst flag is always zero. If \var{secs} is not provided or \constant{None}, the current time as returned by \function{time()} is used. Fractions of a second are ignored. See -above for a description of the \class{struct_time} object. +above for a description of the \class{struct_time} object. See +\function{calendar.timegm()} for the inverse of this function. \versionchanged[Allowed \var{secs} to be omitted]{2.1} \versionchanged[If \var{secs} is \constant{None}, the current time is used]{2.4} From tim_one at users.sourceforge.net Sun Oct 31 23:12:46 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 23:12:50 2004 Subject: [Python-checkins] python/dist/src/Modules gcmodule.c,2.77,2.78 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1891/Modules Modified Files: gcmodule.c Log Message: handle_weakrefs(): Simplification -- there's no need to make a second pass over the unreachable weakrefs-with-callbacks to unreachable objects. Index: gcmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/gcmodule.c,v retrieving revision 2.77 retrieving revision 2.78 diff -u -d -r2.77 -r2.78 --- gcmodule.c 30 Oct 2004 23:09:22 -0000 2.77 +++ gcmodule.c 31 Oct 2004 22:12:43 -0000 2.78 @@ -472,24 +472,19 @@ PyGC_Head *gc; PyObject *op; /* generally FROM_GC(gc) */ PyWeakReference *wr; /* generally a cast of op */ - PyGC_Head wrcb_to_call; /* weakrefs with callbacks to call */ - PyGC_Head wrcb_to_kill; /* weakrefs with callbacks to ignore */ - PyGC_Head *next; int num_freed = 0; gc_list_init(&wrcb_to_call); - gc_list_init(&wrcb_to_kill); /* Clear all weakrefs to the objects in unreachable. If such a weakref * also has a callback, move it into `wrcb_to_call` if the callback - * needs to be invoked, or into `wrcb_to_kill` if the callback should - * be ignored. Note that we cannot invoke any callbacks until all - * weakrefs to unreachable objects are cleared, lest the callback - * resurrect an unreachable object via a still-active weakref. That's - * why the weakrefs with callbacks are moved into different lists -- we - * make another pass over those lists after this pass completes. + * needs to be invoked. Note that we cannot invoke any callbacks until + * all weakrefs to unreachable objects are cleared, lest the callback + * resurrect an unreachable object via a still-active weakref. We + * make another pass over wrcb_to_call, invoking callbacks, after this + * pass completes. */ for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { PyWeakReference **wrlist; @@ -507,7 +502,7 @@ /* `op` may have some weakrefs. March over the list, clear * all the weakrefs, and move the weakrefs with callbacks - * into one of the wrcb_to_{call,kill} lists. + * that must be called into wrcb_to_call. */ for (wr = *wrlist; wr != NULL; wr = *wrlist) { PyGC_Head *wrasgc; /* AS_GC(wr) */ @@ -538,7 +533,9 @@ * callback. Then the callback could resurrect insane objects. * * Since the callback is never needed and may be unsafe in this case, - * wr is moved to wrcb_to_kill. + * wr is simply left in the unreachable set. Note that because we + * already called _PyWeakref_ClearRef(wr), its callback will never + * trigger. * * OTOH, if wr isn't part of CT, we should invoke the callback: the * weakref outlived the trash. Note that since wr isn't CT in this @@ -547,62 +544,28 @@ * nothing in CT is reachable from the callback either, so it's hard * to imagine how calling it later could create a problem for us. wr * is moved to wrcb_to_call in this case. - * - * Obscure: why do we move weakrefs with ignored callbacks to a list - * we crawl over later, instead of getting rid of the callback right - * now? It's because the obvious way doesn't work: setting - * wr->wr_callback to NULL requires that we decref the current - * wr->wr_callback. But callbacks are also weakly referenceable, so - * wr->wr_callback may *itself* be referenced by another weakref with - * another callback. The latter callback could get triggered now if - * we decref'ed now, but as explained before it's potentially unsafe to - * invoke any callback before all weakrefs to CT are cleared. */ + if (IS_TENTATIVELY_UNREACHABLE(wr)) + continue; + assert(IS_REACHABLE(wr)); + /* Create a new reference so that wr can't go away * before we can process it again. */ Py_INCREF(wr); - /* Move wr to the appropriate list. */ + /* Move wr to wrcb_to_call, for the next pass. */ wrasgc = AS_GC(wr); - if (wrasgc == next) - next = wrasgc->gc.gc_next; + assert(wrasgc != next); /* wrasgc is reachable, but + next isn't, so they can't + be the same */ gc_list_remove(wrasgc); - gc_list_append(wrasgc, - IS_TENTATIVELY_UNREACHABLE(wr) ? - &wrcb_to_kill : &wrcb_to_call); - wrasgc->gc.gc_refs = GC_REACHABLE; - } - } - - /* Now that all weakrefs to trash have been cleared, it's safe to - * decref the callbacks we decided to ignore. We cannot invoke - * them because they may be able to resurrect unreachable (from - * outside) objects. - */ - while (! gc_list_is_empty(&wrcb_to_kill)) { - gc = wrcb_to_kill.gc.gc_next; - op = FROM_GC(gc); - assert(IS_REACHABLE(op)); - assert(PyWeakref_Check(op)); - assert(((PyWeakReference *)op)->wr_callback != NULL); - - /* Give up the reference we created in the first pass. When - * op's refcount hits 0 (which it may or may not do right now), - * op's tp_dealloc will decref op->wr_callback too. - */ - Py_DECREF(op); - if (wrcb_to_kill.gc.gc_next == gc) { - /* object is still alive -- move it */ - gc_list_remove(gc); - gc_list_append(gc, old); + gc_list_append(wrasgc, &wrcb_to_call); } - else - ++num_freed; } - /* Finally, invoke the callbacks we decided to honor. It's safe to - * invoke them because they cannot reference objects in `unreachable`. + /* Invoke the callbacks we decided to honor. It's safe to invoke them + * because they can't reference unreachable objects. */ while (! gc_list_is_empty(&wrcb_to_call)) { PyObject *temp; @@ -625,7 +588,14 @@ /* Give up the reference we created in the first pass. When * op's refcount hits 0 (which it may or may not do right now), - * op's tp_dealloc will decref op->wr_callback too. + * op's tp_dealloc will decref op->wr_callback too. Note + * that the refcount probably will hit 0 now, and because this + * weakref was reachable to begin with, gc didn't already + * add it to its count of freed objects. Example: a reachable + * weak value dict maps some key to this reachable weakref. + * The callback removes this key->weakref mapping from the + * dict, leaving no other references to the weakref (excepting + * ours). */ Py_DECREF(op); if (wrcb_to_call.gc.gc_next == gc) { From tim_one at users.sourceforge.net Sun Oct 31 23:27:48 2004 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sun Oct 31 23:27:51 2004 Subject: [Python-checkins] python/dist/src/Modules gcmodule.c, 2.71.10.3, 2.71.10.4 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4662/Modules Modified Files: Tag: release23-maint gcmodule.c Log Message: handle_weakrefs(): Simplification -- there's no need to make a second pass over the unreachable weakrefs-with-callbacks to unreachable objects. Index: gcmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/gcmodule.c,v retrieving revision 2.71.10.3 retrieving revision 2.71.10.4 diff -u -d -r2.71.10.3 -r2.71.10.4 --- gcmodule.c 31 Oct 2004 00:13:06 -0000 2.71.10.3 +++ gcmodule.c 31 Oct 2004 22:27:45 -0000 2.71.10.4 @@ -453,24 +453,19 @@ PyGC_Head *gc; PyObject *op; /* generally FROM_GC(gc) */ PyWeakReference *wr; /* generally a cast of op */ - PyGC_Head wrcb_to_call; /* weakrefs with callbacks to call */ - PyGC_Head wrcb_to_kill; /* weakrefs with callbacks to ignore */ - PyGC_Head *next; int num_freed = 0; gc_list_init(&wrcb_to_call); - gc_list_init(&wrcb_to_kill); /* Clear all weakrefs to the objects in unreachable. If such a weakref * also has a callback, move it into `wrcb_to_call` if the callback - * needs to be invoked, or into `wrcb_to_kill` if the callback should - * be ignored. Note that we cannot invoke any callbacks until all - * weakrefs to unreachable objects are cleared, lest the callback - * resurrect an unreachable object via a still-active weakref. That's - * why the weakrefs with callbacks are moved into different lists -- we - * make another pass over those lists after this pass completes. + * needs to be invoked. Note that we cannot invoke any callbacks until + * all weakrefs to unreachable objects are cleared, lest the callback + * resurrect an unreachable object via a still-active weakref. We + * make another pass over wrcb_to_call, invoking callbacks, after this + * pass completes. */ for (gc = unreachable->gc.gc_next; gc != unreachable; gc = next) { PyWeakReference **wrlist; @@ -488,7 +483,7 @@ /* `op` may have some weakrefs. March over the list, clear * all the weakrefs, and move the weakrefs with callbacks - * into one of the wrcb_to_{call,kill} lists. + * that must be called into wrcb_to_call. */ for (wr = *wrlist; wr != NULL; wr = *wrlist) { PyGC_Head *wrasgc; /* AS_GC(wr) */ @@ -519,7 +514,9 @@ * callback. Then the callback could resurrect insane objects. * * Since the callback is never needed and may be unsafe in this case, - * wr is moved to wrcb_to_kill. + * wr is simply left in the unreachable set. Note that because we + * already called _PyWeakref_ClearRef(wr), its callback will never + * trigger. * * OTOH, if wr isn't part of CT, we should invoke the callback: the * weakref outlived the trash. Note that since wr isn't CT in this @@ -528,62 +525,28 @@ * nothing in CT is reachable from the callback either, so it's hard * to imagine how calling it later could create a problem for us. wr * is moved to wrcb_to_call in this case. - * - * Obscure: why do we move weakrefs with ignored callbacks to a list - * we crawl over later, instead of getting rid of the callback right - * now? It's because the obvious way doesn't work: setting - * wr->wr_callback to NULL requires that we decref the current - * wr->wr_callback. But callbacks are also weakly referenceable, so - * wr->wr_callback may *itself* be referenced by another weakref with - * another callback. The latter callback could get triggered now if - * we decref'ed now, but as explained before it's potentially unsafe to - * invoke any callback before all weakrefs to CT are cleared. */ + if (IS_TENTATIVELY_UNREACHABLE(wr)) + continue; + assert(IS_REACHABLE(wr)); + /* Create a new reference so that wr can't go away * before we can process it again. */ Py_INCREF(wr); - /* Move wr to the appropriate list. */ + /* Move wr to wrcb_to_call, for the next pass. */ wrasgc = AS_GC(wr); - if (wrasgc == next) - next = wrasgc->gc.gc_next; + assert(wrasgc != next); /* wrasgc is reachable, but + next isn't, so they can't + be the same */ gc_list_remove(wrasgc); - gc_list_append(wrasgc, - IS_TENTATIVELY_UNREACHABLE(wr) ? - &wrcb_to_kill : &wrcb_to_call); - wrasgc->gc.gc_refs = GC_REACHABLE; - } - } - - /* Now that all weakrefs to trash have been cleared, it's safe to - * decref the callbacks we decided to ignore. We cannot invoke - * them because they may be able to resurrect unreachable (from - * outside) objects. - */ - while (! gc_list_is_empty(&wrcb_to_kill)) { - gc = wrcb_to_kill.gc.gc_next; - op = FROM_GC(gc); - assert(IS_REACHABLE(op)); - assert(PyWeakref_Check(op)); - assert(((PyWeakReference *)op)->wr_callback != NULL); - - /* Give up the reference we created in the first pass. When - * op's refcount hits 0 (which it may or may not do right now), - * op's tp_dealloc will decref op->wr_callback too. - */ - Py_DECREF(op); - if (wrcb_to_kill.gc.gc_next == gc) { - /* object is still alive -- move it */ - gc_list_remove(gc); - gc_list_append(gc, old); + gc_list_append(wrasgc, &wrcb_to_call); } - else - ++num_freed; } - /* Finally, invoke the callbacks we decided to honor. It's safe to - * invoke them because they cannot reference objects in `unreachable`. + /* Invoke the callbacks we decided to honor. It's safe to invoke them + * because they can't reference unreachable objects. */ while (! gc_list_is_empty(&wrcb_to_call)) { PyObject *temp; @@ -606,7 +569,14 @@ /* Give up the reference we created in the first pass. When * op's refcount hits 0 (which it may or may not do right now), - * op's tp_dealloc will decref op->wr_callback too. + * op's tp_dealloc will decref op->wr_callback too. Note + * that the refcount probably will hit 0 now, and because this + * weakref was reachable to begin with, gc didn't already + * add it to its count of freed objects. Example: a reachable + * weak value dict maps some key to this reachable weakref. + * The callback removes this key->weakref mapping from the + * dict, leaving no other references to the weakref (excepting + * ours). */ Py_DECREF(op); if (wrcb_to_call.gc.gc_next == gc) {