From perky at users.sourceforge.net Mon Aug 1 07:26:46 2005 From: perky at users.sourceforge.net (perky@users.sourceforge.net) Date: Sun, 31 Jul 2005 22:26:46 -0700 Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.36,1.37 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29494/Objects Modified Files: setobject.c Log Message: Fix build on gcc: PySetIter_Type should be static in definition part also. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.36 retrieving revision 1.37 diff -u -d -r1.36 -r1.37 --- setobject.c 31 Jul 2005 15:36:06 -0000 1.36 +++ setobject.c 1 Aug 2005 05:26:41 -0000 1.37 @@ -602,7 +602,7 @@ return NULL; } -PyTypeObject PySetIter_Type = { +static PyTypeObject PySetIter_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /* ob_size */ "setiterator", /* tp_name */ From rhettinger at users.sourceforge.net Mon Aug 1 23:39:30 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Mon, 01 Aug 2005 14:39:30 -0700 Subject: [Python-checkins] python/dist/src/Lib/test test_set.py,1.18,1.19 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3433/Lib/test Modified Files: test_set.py Log Message: * Improve code for the empty frozenset singleton: - Handle both frozenset() and frozenset([]). - Do not use singleton for frozenset subclasses. - Finalize the singleton. - Add test cases. * Factor-out set_update_internal() from set_update(). Simplifies the code for several internal callers. * Factor constant expressions out of loop in set_merge_internal(). * Minor comment touch-ups. Index: test_set.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_set.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- test_set.py 5 Jul 2005 05:34:43 -0000 1.18 +++ test_set.py 1 Aug 2005 21:39:28 -0000 1.19 @@ -391,6 +391,15 @@ s.__init__(self.otherword) self.assertEqual(s, set(self.word)) + def test_singleton_empty_frozenset(self): + f = frozenset() + efs = [frozenset(), frozenset([]), frozenset(()), frozenset(''), + frozenset(), frozenset([]), frozenset(()), frozenset(''), + frozenset(xrange(0)), frozenset(frozenset()), + frozenset(f), f] + # All of the empty frozensets should have just one id() + self.assertEqual(len(set(map(id, efs))), 1) + def test_constructor_identity(self): s = self.thetype(range(3)) t = self.thetype(s) @@ -456,6 +465,17 @@ t = self.thetype(s) self.assertEqual(s, t) + def test_singleton_empty_frozenset(self): + Frozenset = self.thetype + f = frozenset() + F = Frozenset() + efs = [Frozenset(), Frozenset([]), Frozenset(()), Frozenset(''), + Frozenset(), Frozenset([]), Frozenset(()), Frozenset(''), + Frozenset(xrange(0)), Frozenset(Frozenset()), + Frozenset(frozenset()), f, F, Frozenset(f), Frozenset(F)] + # All empty frozenset subclass instances should have different ids + self.assertEqual(len(set(map(id, efs))), len(efs)) + # Tests taken from test_sets.py ============================================= empty_set = set() From rhettinger at users.sourceforge.net Mon Aug 1 23:39:30 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Mon, 01 Aug 2005 14:39:30 -0700 Subject: [Python-checkins] python/dist/src/Include pythonrun.h, 2.66, 2.67 setobject.h, 2.6, 2.7 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3433/Include Modified Files: pythonrun.h setobject.h Log Message: * Improve code for the empty frozenset singleton: - Handle both frozenset() and frozenset([]). - Do not use singleton for frozenset subclasses. - Finalize the singleton. - Add test cases. * Factor-out set_update_internal() from set_update(). Simplifies the code for several internal callers. * Factor constant expressions out of loop in set_merge_internal(). * Minor comment touch-ups. Index: pythonrun.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/pythonrun.h,v retrieving revision 2.66 retrieving revision 2.67 diff -u -d -r2.66 -r2.67 --- pythonrun.h 27 May 2005 15:23:13 -0000 2.66 +++ pythonrun.h 1 Aug 2005 21:39:27 -0000 2.67 @@ -115,6 +115,7 @@ PyAPI_FUNC(void) PyCFunction_Fini(void); PyAPI_FUNC(void) PyTuple_Fini(void); PyAPI_FUNC(void) PyList_Fini(void); +PyAPI_FUNC(void) PySet_Fini(void); PyAPI_FUNC(void) PyString_Fini(void); PyAPI_FUNC(void) PyInt_Fini(void); PyAPI_FUNC(void) PyFloat_Fini(void); Index: setobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/setobject.h,v retrieving revision 2.6 retrieving revision 2.7 diff -u -d -r2.6 -r2.7 --- setobject.h 31 Jul 2005 01:16:36 -0000 2.6 +++ setobject.h 1 Aug 2005 21:39:27 -0000 2.7 @@ -42,8 +42,7 @@ /* table points to smalltable for small tables, else to * additional malloc'ed memory. table is never NULL! This rule - * saves repeated runtime null-tests in the workhorse getitem and - * setitem calls. + * saves repeated runtime null-tests. */ setentry *table; setentry *(*lookup)(PySetObject *so, PyObject *key, long hash); From rhettinger at users.sourceforge.net Mon Aug 1 23:39:31 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Mon, 01 Aug 2005 14:39:31 -0700 Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.37,1.38 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3433/Objects Modified Files: setobject.c Log Message: * Improve code for the empty frozenset singleton: - Handle both frozenset() and frozenset([]). - Do not use singleton for frozenset subclasses. - Finalize the singleton. - Add test cases. * Factor-out set_update_internal() from set_update(). Simplifies the code for several internal callers. * Factor constant expressions out of loop in set_merge_internal(). * Minor comment touch-ups. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.37 retrieving revision 1.38 diff -u -d -r1.37 -r1.38 --- setobject.c 1 Aug 2005 05:26:41 -0000 1.37 +++ setobject.c 1 Aug 2005 21:39:28 -0000 1.38 @@ -311,9 +311,6 @@ return 0; } -/*** Internal functions (derived from public dictionary api functions ) ***/ - - /* CAUTION: set_add_internal() must guarantee that it won't resize the table */ static int set_add_internal(register PySetObject *so, PyObject *key) @@ -435,10 +432,10 @@ /* * Iterate over a set table. Use like so: * - * int i; + * int pos; * PyObject *key; - * i = 0; # important! i should not otherwise be changed by you - * while (set_next_internal(yourset, &i, &key)) { + * pos = 0; # important! pos should not otherwise be changed by you + * while (set_next_internal(yourset, &pos, &key)) { * Refer to borrowed reference in key. * } * @@ -467,14 +464,13 @@ return 1; } -/* Methods */ - static int set_merge_internal(PySetObject *so, PyObject *otherset) { - register PySetObject *other; + PySetObject *other; register int i; - setentry *entry; + register setentry *entry, *othertable; + register int othermask; assert (PyAnySet_Check(so)); assert (PyAnySet_Check(otherset)); @@ -491,8 +487,10 @@ if (set_table_resize(so, (so->used + other->used)*2) != 0) return -1; } - for (i = 0; i <= other->mask; i++) { - entry = &other->table[i]; + othermask = other->mask; + othertable = other->table; + for (i = 0; i <= othermask; i++) { + entry = &othertable[i]; if (entry->key != NULL && entry->key != dummy) { Py_INCREF(entry->key); @@ -517,9 +515,9 @@ return key != NULL && key != dummy; } -static PyTypeObject PySetIter_Type; /* Forward */ +/***** Set iterator types **********************************************/ -/* Set iterator types */ +static PyTypeObject PySetIter_Type; /* Forward */ typedef struct { PyObject_HEAD @@ -647,41 +645,52 @@ All rights reserved. */ -static PyObject * -set_update(PySetObject *so, PyObject *other) +static int +set_len(PyObject *so) +{ + return ((PySetObject *)so)->used; +} + +static int +set_update_internal(PySetObject *so, PyObject *other) { PyObject *key, *it; - if (PyAnySet_Check(other)) { - if (set_merge_internal(so, other) == -1) - return NULL; - Py_RETURN_NONE; - } + if (PyAnySet_Check(other)) + return set_merge_internal(so, other); if (PyDict_Check(other)) { PyObject *key, *value; int pos = 0; while (PyDict_Next(other, &pos, &key, &value)) { if (set_add_internal(so, key) == -1) - return NULL; + return -1; } - Py_RETURN_NONE; + return 0; } it = PyObject_GetIter(other); if (it == NULL) - return NULL; + return -1; while ((key = PyIter_Next(it)) != NULL) { if (set_add_internal(so, key) == -1) { Py_DECREF(it); Py_DECREF(key); - return NULL; + return -1; } Py_DECREF(key); } Py_DECREF(it); if (PyErr_Occurred()) + return -1; + return 0; +} + +static PyObject * +set_update(PySetObject *so, PyObject *other) +{ + if (set_update_internal(so, other) == -1) return NULL; Py_RETURN_NONE; } @@ -692,7 +701,6 @@ static PyObject * make_new_set(PyTypeObject *type, PyObject *iterable) { - PyObject *tmp; register PySetObject *so = NULL; if (dummy == NULL) { /* Auto-initialize dummy */ @@ -712,37 +720,51 @@ so->weakreflist = NULL; if (iterable != NULL) { - tmp = set_update(so, iterable); - if (tmp == NULL) { + if (set_update_internal(so, iterable) == -1) { Py_DECREF(so); return NULL; } - Py_DECREF(tmp); } return (PyObject *)so; } +/* The empty frozenset is a singleton */ +static PyObject *emptyfrozenset = NULL; + static PyObject * frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PyObject *iterable = NULL; - static PyObject *emptyfrozenset = NULL; + PyObject *iterable = NULL, *result; if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable)) return NULL; - if (iterable == NULL) { - if (type == &PyFrozenSet_Type) { - if (emptyfrozenset == NULL) - emptyfrozenset = make_new_set(type, NULL); - Py_INCREF(emptyfrozenset); - return emptyfrozenset; + + if (type != &PyFrozenSet_Type) + return make_new_set(type, iterable); + + if (iterable != NULL) { + /* frozenset(f) is idempotent */ + if (PyFrozenSet_CheckExact(iterable)) { + Py_INCREF(iterable); + return iterable; } - } else if (PyFrozenSet_CheckExact(iterable)) { - Py_INCREF(iterable); - return iterable; + result = make_new_set(type, iterable); + if (result == NULL || set_len(result)) + return result; + Py_DECREF(result); } - return make_new_set(type, iterable); + /* The empty frozenset is a singleton */ + if (emptyfrozenset == NULL) + emptyfrozenset = make_new_set(type, NULL); + Py_XINCREF(emptyfrozenset); + return emptyfrozenset; +} + +void +PySet_Fini(void) +{ + Py_XDECREF(emptyfrozenset); } static PyObject * @@ -786,12 +808,6 @@ return 0; } -static int -set_len(PyObject *so) -{ - return ((PySetObject *)so)->used; -} - /* set_swap_bodies() switches the contents of any two sets by moving their internal data pointers and, if needed, copying the internal smalltables. Semantically equivalent to: @@ -892,17 +908,14 @@ set_union(PySetObject *so, PyObject *other) { PySetObject *result; - PyObject *rv; result = (PySetObject *)set_copy(so); if (result == NULL) return NULL; - rv = set_update(result, other); - if (rv == NULL) { + if (set_update_internal(result, other) == -1) { Py_DECREF(result); return NULL; } - Py_DECREF(rv); return (PyObject *)result; } @@ -924,16 +937,12 @@ static PyObject * set_ior(PySetObject *so, PyObject *other) { - PyObject *result; - if (!PyAnySet_Check(other)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } - result = set_update(so, other); - if (result == NULL) + if (set_update_internal(so, other) == -1) return NULL; - Py_DECREF(result); Py_INCREF(so); return (PyObject *)so; } @@ -1553,7 +1562,6 @@ set_init(PySetObject *self, PyObject *args, PyObject *kwds) { PyObject *iterable = NULL; - PyObject *result; if (!PyAnySet_Check(self)) return -1; @@ -1563,12 +1571,7 @@ self->hash = -1; if (iterable == NULL) return 0; - result = set_update(self, iterable); - if (result != NULL) { - Py_DECREF(result); - return 0; - } - return -1; + return set_update_internal(self, iterable); } static PySequenceMethods set_as_sequence = { From rhettinger at users.sourceforge.net Mon Aug 1 23:39:33 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Mon, 01 Aug 2005 14:39:33 -0700 Subject: [Python-checkins] python/dist/src/Python pythonrun.c,2.214,2.215 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3433/Python Modified Files: pythonrun.c Log Message: * Improve code for the empty frozenset singleton: - Handle both frozenset() and frozenset([]). - Do not use singleton for frozenset subclasses. - Finalize the singleton. - Add test cases. * Factor-out set_update_internal() from set_update(). Simplifies the code for several internal callers. * Factor constant expressions out of loop in set_merge_internal(). * Minor comment touch-ups. Index: pythonrun.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pythonrun.c,v retrieving revision 2.214 retrieving revision 2.215 diff -u -d -r2.214 -r2.215 --- pythonrun.c 27 May 2005 15:23:20 -0000 2.214 +++ pythonrun.c 1 Aug 2005 21:39:29 -0000 2.215 @@ -420,6 +420,7 @@ PyCFunction_Fini(); PyTuple_Fini(); PyList_Fini(); + PySet_Fini(); PyString_Fini(); PyInt_Fini(); PyFloat_Fini(); From pje at users.sourceforge.net Tue Aug 2 02:46:50 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 01 Aug 2005 17:46:50 -0700 Subject: [Python-checkins] python/dist/src/Python ceval.c, 2.424, 2.425 compile.c, 2.350, 2.351 exceptions.c, 1.49, 1.50 graminit.c, 2.39, 2.40 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12011/Python Modified Files: ceval.c compile.c exceptions.c graminit.c Log Message: PEP 342 implementation. Per Guido's comments, the generator throw() method still needs to support string exceptions, and allow None for the third argument. Documentation updates are needed, too. Index: ceval.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v retrieving revision 2.424 retrieving revision 2.425 diff -u -d -r2.424 -r2.425 --- ceval.c 25 Jun 2005 08:23:40 -0000 2.424 +++ ceval.c 2 Aug 2005 00:46:45 -0000 2.425 @@ -499,7 +499,14 @@ /* Interpreter main loop */ PyObject * -PyEval_EvalFrame(PyFrameObject *f) +PyEval_EvalFrame(PyFrameObject *f) { + /* This is for backward compatibility with extension modules that + used this API; core interpreter code should call PyEval_EvalFrameEx() */ + return PyEval_EvalFrameEx(f, 0); +} + +PyObject * +PyEval_EvalFrameEx(PyFrameObject *f, int throw) { #ifdef DXPAIRS int lastopcode = 0; @@ -747,6 +754,11 @@ x = Py_None; /* Not a reference, just anything non-NULL */ w = NULL; + if (throw) { /* support for generator.throw() */ + why = WHY_EXCEPTION; + goto on_error; + } + for (;;) { #ifdef WITH_TSC if (inst1 == 0) { @@ -2733,7 +2745,7 @@ return PyGen_New(f); } - retval = PyEval_EvalFrame(f); + retval = PyEval_EvalFrameEx(f,0); fail: /* Jump here from prelude on failure */ @@ -3636,7 +3648,7 @@ Py_INCREF(*stack); fastlocals[i] = *stack++; } - retval = PyEval_EvalFrame(f); + retval = PyEval_EvalFrameEx(f,0); assert(tstate != NULL); ++tstate->recursion_depth; Py_DECREF(f); Index: compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.350 retrieving revision 2.351 diff -u -d -r2.350 -r2.351 --- compile.c 25 Jun 2005 08:23:41 -0000 2.350 +++ compile.c 2 Aug 2005 00:46:46 -0000 2.351 @@ -2145,6 +2145,7 @@ else { com_test(c, t); com_addbyte(c, YIELD_VALUE); + com_addbyte(c, POP_TOP); com_pop(c, 1); } @@ -2193,6 +2194,7 @@ else { com_test(c, t); com_addbyte(c, YIELD_VALUE); + com_addbyte(c, POP_TOP); com_pop(c, 1); } com_addfwref(c, JUMP_FORWARD, &anchor); @@ -2354,6 +2356,10 @@ } } + +/* forward reference */ +static void com_yield_expr(struct compiling *c, node *n); + static void com_atom(struct compiling *c, node *n) { @@ -2369,7 +2375,10 @@ com_push(c, 1); } else - com_testlist_gexp(c, CHILD(n, 1)); + if (TYPE(CHILD(n, 1)) == yield_expr) + com_yield_expr(c, CHILD(n, 1)); + else + com_testlist_gexp(c, CHILD(n, 1)); break; case LSQB: /* '[' [listmaker] ']' */ if (TYPE(CHILD(n, 1)) == RSQB) { @@ -3436,7 +3445,11 @@ } n = CHILD(n, 0); break; - + case yield_expr: + com_error(c, PyExc_SyntaxError, + "assignment to yield expression not possible"); + return; + case test: case and_test: case not_test: @@ -3493,7 +3506,7 @@ } if (assigning > OP_APPLY) { com_error(c, PyExc_SyntaxError, - "augmented assign to tuple literal or generator expression not possible"); + "augmented assign to tuple literal, yield, or generator expression not possible"); return; } break; @@ -3729,27 +3742,42 @@ } static void -com_yield_stmt(struct compiling *c, node *n) +com_yield_expr(struct compiling *c, node *n) { int i; - REQ(n, yield_stmt); /* 'yield' testlist */ + REQ(n, yield_expr); /* 'yield' testlist */ if (!c->c_infunction) { com_error(c, PyExc_SyntaxError, "'yield' outside function"); } - for (i = 0; i < c->c_nblocks; ++i) { + /* for (i = 0; i < c->c_nblocks; ++i) { if (c->c_block[i] == SETUP_FINALLY) { com_error(c, PyExc_SyntaxError, "'yield' not allowed in a 'try' block " "with a 'finally' clause"); return; } + } */ + + if (NCH(n) < 2) { + com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); + com_push(c, 1); } - com_node(c, CHILD(n, 1)); + else + com_node(c, CHILD(n, 1)); com_addbyte(c, YIELD_VALUE); +} + +static void +com_yield_stmt(struct compiling *c, node *n) +{ + REQ(n, yield_stmt); /* yield_expr */ + com_node(c, CHILD(n, 0)); + com_addbyte(c, POP_TOP); com_pop(c, 1); } + static void com_raise_stmt(struct compiling *c, node *n) { @@ -4768,6 +4796,10 @@ /* Expression nodes */ + case yield_expr: + com_yield_expr(c, n); + break; + case testlist: case testlist1: case testlist_safe: @@ -5027,7 +5059,9 @@ REQ(CHILD(n, 1), gen_for); c->c_name = ""; + c->c_infunction = 1; com_gen_for(c, CHILD(n, 1), CHILD(n, 0), 1); + c->c_infunction = 0; com_addoparg(c, LOAD_CONST, com_addconst(c, Py_None)); com_push(c, 1); @@ -6115,7 +6149,7 @@ #define symtable_add_use(ST, NAME) symtable_add_def((ST), (NAME), USE) -/* Look for a yield stmt under n. Return 1 if found, else 0. +/* Look for a yield stmt or expr under n. Return 1 if found, else 0. This hack is used to look inside "if 0:" blocks (which are normally ignored) in case those are the only places a yield occurs (so that this function is a generator). */ @@ -6137,6 +6171,7 @@ return 0; case yield_stmt: + case yield_expr: return GENERATOR; default: @@ -6247,8 +6282,10 @@ case del_stmt: symtable_assign(st, CHILD(n, 1), 0); break; - case yield_stmt: + case yield_expr: st->st_cur->ste_generator = 1; + if (NCH(n)==1) + break; n = CHILD(n, 1); goto loop; case expr_stmt: @@ -6341,9 +6378,15 @@ /* fall through */ case atom: - if (TYPE(n) == atom && TYPE(CHILD(n, 0)) == NAME) { - symtable_add_use(st, STR(CHILD(n, 0))); - break; + if (TYPE(n) == atom) { + if (TYPE(CHILD(n, 0)) == NAME) { + symtable_add_use(st, STR(CHILD(n, 0))); + break; + } + else if (TYPE(CHILD(n,0)) == LPAR) { + n = CHILD(n,1); + goto loop; + } } /* fall through */ default: @@ -6739,6 +6782,15 @@ symtable_add_def(st, STR(tmp), DEF_LOCAL | def_flag); } return; + + case yield_expr: + st->st_cur->ste_generator = 1; + if (NCH(n)==2) { + n = CHILD(n, 1); + goto loop; + } + return; + case dotted_as_name: if (NCH(n) == 3) symtable_add_def(st, STR(CHILD(n, 2)), Index: exceptions.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/exceptions.c,v retrieving revision 1.49 retrieving revision 1.50 diff -u -d -r1.49 -r1.50 --- exceptions.c 25 Aug 2004 02:14:08 -0000 1.49 +++ exceptions.c 2 Aug 2005 00:46:46 -0000 1.50 @@ -57,6 +57,7 @@ |\n\ +-- SystemExit\n\ +-- StopIteration\n\ + +-- GeneratorExit\n\ +-- StandardError\n\ | |\n\ | +-- KeyboardInterrupt\n\ @@ -394,6 +395,7 @@ PyDoc_STRVAR(TypeError__doc__, "Inappropriate argument type."); PyDoc_STRVAR(StopIteration__doc__, "Signal the end from iterator.next()."); +PyDoc_STRVAR(GeneratorExit__doc__, "Request that a generator exit."); @@ -1583,6 +1585,7 @@ PyObject *PyExc_Exception; PyObject *PyExc_StopIteration; +PyObject *PyExc_GeneratorExit; PyObject *PyExc_StandardError; PyObject *PyExc_ArithmeticError; PyObject *PyExc_LookupError; @@ -1657,6 +1660,8 @@ {"Exception", &PyExc_Exception}, {"StopIteration", &PyExc_StopIteration, &PyExc_Exception, StopIteration__doc__}, + {"GeneratorExit", &PyExc_GeneratorExit, &PyExc_Exception, + GeneratorExit__doc__}, {"StandardError", &PyExc_StandardError, &PyExc_Exception, StandardError__doc__}, {"TypeError", &PyExc_TypeError, 0, TypeError__doc__}, Index: graminit.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/graminit.c,v retrieving revision 2.39 retrieving revision 2.40 diff -u -d -r2.39 -r2.40 --- graminit.c 5 Mar 2005 06:47:56 -0000 2.39 +++ graminit.c 2 Aug 2005 00:46:46 -0000 2.40 @@ -279,10 +279,12 @@ {25, 3}, {0, 1}, }; -static arc arcs_13_2[1] = { +static arc arcs_13_2[2] = { + {43, 4}, {9, 4}, }; -static arc arcs_13_3[1] = { +static arc arcs_13_3[2] = { + {43, 5}, {9, 5}, }; static arc arcs_13_4[1] = { @@ -295,13 +297,12 @@ static state states_13[6] = { {1, arcs_13_0}, {3, arcs_13_1}, - {1, arcs_13_2}, - {1, arcs_13_3}, + {2, arcs_13_2}, + {2, arcs_13_3}, {1, arcs_13_4}, {2, arcs_13_5}, }; static arc arcs_14_0[12] = { - {43, 1}, {44, 1}, {45, 1}, {46, 1}, @@ -313,6 +314,7 @@ {52, 1}, {53, 1}, {54, 1}, + {55, 1}, }; static arc arcs_14_1[1] = { {0, 1}, @@ -322,11 +324,11 @@ {1, arcs_14_1}, }; static arc arcs_15_0[1] = { - {55, 1}, + {56, 1}, }; static arc arcs_15_1[3] = { {26, 2}, - {56, 3}, + {57, 3}, {0, 1}, }; static arc arcs_15_2[2] = { @@ -367,10 +369,10 @@ {2, arcs_15_8}, }; static arc arcs_16_0[1] = { - {57, 1}, + {58, 1}, }; static arc arcs_16_1[1] = { - {58, 2}, + {59, 2}, }; static arc arcs_16_2[1] = { {0, 2}, @@ -381,7 +383,7 @@ {1, arcs_16_2}, }; static arc arcs_17_0[1] = { - {59, 1}, + {60, 1}, }; static arc arcs_17_1[1] = { {0, 1}, @@ -391,11 +393,11 @@ {1, arcs_17_1}, }; static arc arcs_18_0[5] = { - {60, 1}, {61, 1}, {62, 1}, {63, 1}, {64, 1}, + {65, 1}, }; static arc arcs_18_1[1] = { {0, 1}, @@ -405,7 +407,7 @@ {1, arcs_18_1}, }; static arc arcs_19_0[1] = { - {65, 1}, + {66, 1}, }; static arc arcs_19_1[1] = { {0, 1}, @@ -415,7 +417,7 @@ {1, arcs_19_1}, }; static arc arcs_20_0[1] = { - {66, 1}, + {67, 1}, }; static arc arcs_20_1[1] = { {0, 1}, @@ -425,7 +427,7 @@ {1, arcs_20_1}, }; static arc arcs_21_0[1] = { - {67, 1}, + {68, 1}, }; static arc arcs_21_1[2] = { {9, 2}, @@ -440,18 +442,14 @@ {1, arcs_21_2}, }; static arc arcs_22_0[1] = { - {68, 1}, + {43, 1}, }; static arc arcs_22_1[1] = { - {9, 2}, -}; -static arc arcs_22_2[1] = { - {0, 2}, + {0, 1}, }; -static state states_22[3] = { +static state states_22[2] = { {1, arcs_22_0}, {1, arcs_22_1}, - {1, arcs_22_2}, }; static arc arcs_23_0[1] = { {69, 1}, @@ -779,7 +777,7 @@ {93, 1}, }; static arc arcs_38_1[1] = { - {58, 2}, + {59, 2}, }; static arc arcs_38_2[1] = { {82, 3}, @@ -1034,7 +1032,7 @@ }; static arc arcs_50_1[3] = { {123, 0}, - {56, 0}, + {57, 0}, {0, 1}, }; static state states_50[2] = { @@ -1113,7 +1111,8 @@ {144, 5}, {145, 6}, }; -static arc arcs_55_1[2] = { +static arc arcs_55_1[3] = { + {43, 7}, {135, 7}, {15, 5}, }; @@ -1149,7 +1148,7 @@ }; static state states_55[11] = { {7, arcs_55_0}, - {2, arcs_55_1}, + {3, arcs_55_1}, {2, arcs_55_2}, {2, arcs_55_3}, {1, arcs_55_4}, @@ -1533,7 +1532,7 @@ {93, 1}, }; static arc arcs_71_1[1] = { - {58, 2}, + {59, 2}, }; static arc arcs_71_2[1] = { {82, 3}, @@ -1590,7 +1589,7 @@ {93, 1}, }; static arc arcs_74_1[1] = { - {58, 2}, + {59, 2}, }; static arc arcs_74_2[1] = { {82, 3}, @@ -1653,165 +1652,182 @@ {1, arcs_77_0}, {1, arcs_77_1}, }; -static dfa dfas[78] = { +static arc arcs_78_0[1] = { + {160, 1}, +}; +static arc arcs_78_1[2] = { + {9, 2}, + {0, 1}, +}; +static arc arcs_78_2[1] = { + {0, 2}, +}; +static state states_78[3] = { + {1, arcs_78_0}, + {2, arcs_78_1}, + {1, arcs_78_2}, +}; +static dfa dfas[79] = { {256, "single_input", 0, 3, states_0, - "\004\050\014\000\000\000\200\012\076\205\011\162\000\002\000\140\010\111\023\002"}, + "\004\050\014\000\000\000\000\025\074\205\011\162\000\002\000\140\010\111\023\002\001"}, {257, "file_input", 0, 2, states_1, - "\204\050\014\000\000\000\200\012\076\205\011\162\000\002\000\140\010\111\023\002"}, + "\204\050\014\000\000\000\000\025\074\205\011\162\000\002\000\140\010\111\023\002\001"}, {258, "eval_input", 0, 3, states_2, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {259, "decorator", 0, 7, states_3, - "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {260, "decorators", 0, 2, states_4, - "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {261, "funcdef", 0, 7, states_5, - "\000\010\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\010\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {262, "parameters", 0, 4, states_6, - "\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {263, "varargslist", 0, 10, states_7, - "\000\040\010\060\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\040\010\060\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {264, "fpdef", 0, 4, states_8, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {265, "fplist", 0, 3, states_9, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {266, "stmt", 0, 2, states_10, - "\000\050\014\000\000\000\200\012\076\205\011\162\000\002\000\140\010\111\023\002"}, + "\000\050\014\000\000\000\000\025\074\205\011\162\000\002\000\140\010\111\023\002\001"}, {267, "simple_stmt", 0, 4, states_11, - "\000\040\010\000\000\000\200\012\076\205\011\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\025\074\205\011\000\000\002\000\140\010\111\023\000\001"}, {268, "small_stmt", 0, 2, states_12, - "\000\040\010\000\000\000\200\012\076\205\011\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\025\074\205\011\000\000\002\000\140\010\111\023\000\001"}, {269, "expr_stmt", 0, 6, states_13, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {270, "augassign", 0, 2, states_14, - "\000\000\000\000\000\370\177\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\360\377\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {271, "print_stmt", 0, 9, states_15, - "\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {272, "del_stmt", 0, 3, states_16, - "\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {273, "pass_stmt", 0, 2, states_17, - "\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {274, "flow_stmt", 0, 2, states_18, - "\000\000\000\000\000\000\000\000\076\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\074\000\000\000\000\000\000\000\000\000\000\000\001"}, {275, "break_stmt", 0, 2, states_19, - "\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000"}, {276, "continue_stmt", 0, 2, states_20, - "\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000"}, {277, "return_stmt", 0, 3, states_21, - "\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000\000"}, - {278, "yield_stmt", 0, 3, states_22, - "\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000\000\000\000"}, + {278, "yield_stmt", 0, 2, states_22, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"}, {279, "raise_stmt", 0, 7, states_23, - "\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000"}, {280, "import_stmt", 0, 2, states_24, - "\000\000\000\000\000\000\000\000\000\005\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\005\000\000\000\000\000\000\000\000\000\000\000"}, {281, "import_name", 0, 3, states_25, - "\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000\000"}, {282, "import_from", 0, 7, states_26, - "\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000"}, {283, "import_as_name", 0, 4, states_27, - "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {284, "dotted_as_name", 0, 4, states_28, - "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {285, "import_as_names", 0, 3, states_29, - "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {286, "dotted_as_names", 0, 2, states_30, - "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {287, "dotted_name", 0, 2, states_31, - "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {288, "global_stmt", 0, 3, states_32, - "\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\200\000\000\000\000\000\000\000\000\000\000\000"}, {289, "exec_stmt", 0, 7, states_33, - "\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\001\000\000\000\000\000\000\000\000\000\000"}, {290, "assert_stmt", 0, 5, states_34, - "\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\010\000\000\000\000\000\000\000\000\000\000"}, {291, "compound_stmt", 0, 2, states_35, - "\000\010\004\000\000\000\000\000\000\000\000\162\000\000\000\000\000\000\000\002"}, + "\000\010\004\000\000\000\000\000\000\000\000\162\000\000\000\000\000\000\000\002\000"}, {292, "if_stmt", 0, 8, states_36, - "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000"}, {293, "while_stmt", 0, 8, states_37, - "\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\020\000\000\000\000\000\000\000\000\000"}, {294, "for_stmt", 0, 10, states_38, - "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000"}, {295, "try_stmt", 0, 10, states_39, - "\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\000\000"}, {296, "except_clause", 0, 5, states_40, - "\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"}, {297, "suite", 0, 5, states_41, - "\004\040\010\000\000\000\200\012\076\205\011\000\000\002\000\140\010\111\023\000"}, + "\004\040\010\000\000\000\000\025\074\205\011\000\000\002\000\140\010\111\023\000\001"}, {298, "test", 0, 4, states_42, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {299, "and_test", 0, 2, states_43, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\003\000\000"}, {300, "not_test", 0, 3, states_44, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\003\000\000"}, {301, "comparison", 0, 2, states_45, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"}, {302, "comp_op", 0, 4, states_46, - "\000\000\000\000\000\000\000\000\000\000\004\000\000\362\017\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\004\000\000\362\017\000\000\000\000\000\000"}, {303, "expr", 0, 2, states_47, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"}, {304, "xor_expr", 0, 2, states_48, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"}, {305, "and_expr", 0, 2, states_49, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"}, {306, "shift_expr", 0, 2, states_50, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"}, {307, "arith_expr", 0, 2, states_51, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"}, {308, "term", 0, 2, states_52, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"}, {309, "factor", 0, 3, states_53, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"}, {310, "power", 0, 4, states_54, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\111\003\000\000"}, {311, "atom", 0, 11, states_55, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\111\003\000\000"}, {312, "listmaker", 0, 5, states_56, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {313, "testlist_gexp", 0, 5, states_57, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {314, "lambdef", 0, 5, states_58, - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\020\000\000"}, {315, "trailer", 0, 7, states_59, - "\000\040\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\001\000\000"}, + "\000\040\000\000\000\000\000\000\000\100\000\000\000\000\000\000\000\001\000\000\000"}, {316, "subscriptlist", 0, 3, states_60, - "\000\040\050\000\000\000\000\000\000\100\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\050\000\000\000\000\000\000\100\000\000\000\002\000\140\010\111\023\000\000"}, {317, "subscript", 0, 7, states_61, - "\000\040\050\000\000\000\000\000\000\100\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\050\000\000\000\000\000\000\100\000\000\000\002\000\140\010\111\023\000\000"}, {318, "sliceop", 0, 3, states_62, - "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\040\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, {319, "exprlist", 0, 3, states_63, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\000\000\140\010\111\003\000\000"}, {320, "testlist", 0, 3, states_64, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {321, "testlist_safe", 0, 5, states_65, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {322, "dictmaker", 0, 5, states_66, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {323, "classdef", 0, 8, states_67, - "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002"}, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\000"}, {324, "arglist", 0, 8, states_68, - "\000\040\010\060\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\060\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {325, "argument", 0, 5, states_69, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {326, "list_iter", 0, 2, states_70, - "\000\000\000\000\000\000\000\000\000\000\000\042\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\042\000\000\000\000\000\000\000\000\000"}, {327, "list_for", 0, 6, states_71, - "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000"}, {328, "list_if", 0, 4, states_72, - "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000"}, {329, "gen_iter", 0, 2, states_73, - "\000\000\000\000\000\000\000\000\000\000\000\042\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\042\000\000\000\000\000\000\000\000\000"}, {330, "gen_for", 0, 6, states_74, - "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\040\000\000\000\000\000\000\000\000\000"}, {331, "gen_if", 0, 4, states_75, - "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000"}, + "\000\000\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000\000\000\000\000"}, {332, "testlist1", 0, 2, states_76, - "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000"}, + "\000\040\010\000\000\000\000\000\000\000\000\000\000\002\000\140\010\111\023\000\000"}, {333, "encoding_decl", 0, 2, states_77, - "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + "\000\000\010\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"}, + {334, "yield_expr", 0, 3, states_78, + "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\001"}, }; -static label labels[160] = { +static label labels[161] = { {0, "EMPTY"}, {256, 0}, {4, 0}, @@ -1855,6 +1871,7 @@ {289, 0}, {290, 0}, {270, 0}, + {334, 0}, {37, 0}, {38, 0}, {39, 0}, @@ -1880,7 +1897,6 @@ {1, "break"}, {1, "continue"}, {1, "return"}, - {1, "yield"}, {1, "raise"}, {281, 0}, {282, 0}, @@ -1972,10 +1988,11 @@ {329, 0}, {331, 0}, {333, 0}, + {1, "yield"}, }; grammar _PyParser_Grammar = { - 78, + 79, dfas, - {160, labels}, + {161, labels}, 256 }; From pje at users.sourceforge.net Tue Aug 2 02:47:14 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 01 Aug 2005 17:47:14 -0700 Subject: [Python-checkins] python/dist/src/Grammar Grammar,1.53,1.54 Message-ID: Update of /cvsroot/python/python/dist/src/Grammar In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12011/Grammar Modified Files: Grammar Log Message: PEP 342 implementation. Per Guido's comments, the generator throw() method still needs to support string exceptions, and allow None for the third argument. Documentation updates are needed, too. Index: Grammar =================================================================== RCS file: /cvsroot/python/python/dist/src/Grammar/Grammar,v retrieving revision 1.53 retrieving revision 1.54 diff -u -d -r1.53 -r1.54 --- Grammar 5 Mar 2005 06:47:56 -0000 1.53 +++ Grammar 2 Aug 2005 00:46:38 -0000 1.54 @@ -39,7 +39,7 @@ stmt: simple_stmt | compound_stmt simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt -expr_stmt: testlist (augassign testlist | ('=' testlist)*) +expr_stmt: testlist (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist))*) augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=' # For normal assignments, additional restrictions enforced by the interpreter print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] ) @@ -49,7 +49,7 @@ break_stmt: 'break' continue_stmt: 'continue' return_stmt: 'return' [testlist] -yield_stmt: 'yield' testlist +yield_stmt: yield_expr raise_stmt: 'raise' [test [',' test [',' test]]] import_stmt: import_name | import_from import_name: 'import' dotted_as_names @@ -86,7 +86,7 @@ term: factor (('*'|'/'|'%'|'//') factor)* factor: ('+'|'-'|'~') factor | power power: atom trailer* ['**' factor] -atom: '(' [testlist_gexp] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+ +atom: '(' [yield_expr|testlist_gexp] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist1 '`' | NAME | NUMBER | STRING+ listmaker: test ( list_for | (',' test)* [','] ) testlist_gexp: test ( gen_for | (',' test)* [','] ) lambdef: 'lambda' [varargslist] ':' test @@ -116,3 +116,6 @@ # not used in grammar, but may appear in "node" passed from Parser to Compiler encoding_decl: NAME + +yield_expr: 'yield' [testlist] + From pje at users.sourceforge.net Tue Aug 2 02:47:15 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 01 Aug 2005 17:47:15 -0700 Subject: [Python-checkins] python/dist/src/Include ceval.h, 2.53, 2.54 graminit.h, 2.23, 2.24 pyerrors.h, 2.66, 2.67 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12011/Include Modified Files: ceval.h graminit.h pyerrors.h Log Message: PEP 342 implementation. Per Guido's comments, the generator throw() method still needs to support string exceptions, and allow None for the third argument. Documentation updates are needed, too. Index: ceval.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/ceval.h,v retrieving revision 2.53 retrieving revision 2.54 diff -u -d -r2.53 -r2.54 --- ceval.h 11 Oct 2004 02:40:35 -0000 2.53 +++ ceval.h 2 Aug 2005 00:46:42 -0000 2.54 @@ -65,6 +65,7 @@ PyAPI_FUNC(PyObject *) PyEval_GetCallStats(PyObject *); PyAPI_FUNC(PyObject *) PyEval_EvalFrame(struct _frame *); +PyAPI_FUNC(PyObject *) PyEval_EvalFrameEx(struct _frame *f, int exc); /* this used to be handled on a per-thread basis - now just two globals */ PyAPI_DATA(volatile int) _Py_Ticker; Index: graminit.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/graminit.h,v retrieving revision 2.23 retrieving revision 2.24 diff -u -d -r2.23 -r2.24 --- graminit.h 31 Aug 2004 10:07:00 -0000 2.23 +++ graminit.h 2 Aug 2005 00:46:42 -0000 2.24 @@ -76,3 +76,4 @@ #define gen_if 331 #define testlist1 332 #define encoding_decl 333 +#define yield_expr 334 Index: pyerrors.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/pyerrors.h,v retrieving revision 2.66 retrieving revision 2.67 diff -u -d -r2.66 -r2.67 --- pyerrors.h 25 Aug 2004 02:14:06 -0000 2.66 +++ pyerrors.h 2 Aug 2005 00:46:42 -0000 2.67 @@ -25,6 +25,7 @@ PyAPI_DATA(PyObject *) PyExc_Exception; PyAPI_DATA(PyObject *) PyExc_StopIteration; +PyAPI_DATA(PyObject *) PyExc_GeneratorExit; PyAPI_DATA(PyObject *) PyExc_StandardError; PyAPI_DATA(PyObject *) PyExc_ArithmeticError; PyAPI_DATA(PyObject *) PyExc_LookupError; From pje at users.sourceforge.net Tue Aug 2 02:47:15 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 01 Aug 2005 17:47:15 -0700 Subject: [Python-checkins] python/dist/src/Lib/compiler transformer.py, 1.51, 1.52 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/compiler In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12011/Lib/compiler Modified Files: transformer.py Log Message: PEP 342 implementation. Per Guido's comments, the generator throw() method still needs to support string exceptions, and allow None for the third argument. Documentation updates are needed, too. Index: transformer.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/compiler/transformer.py,v retrieving revision 1.51 retrieving revision 1.52 diff -u -d -r1.51 -r1.52 --- transformer.py 2 Jul 2005 18:37:41 -0000 1.51 +++ transformer.py 2 Aug 2005 00:46:43 -0000 1.52 @@ -403,7 +403,15 @@ return Return(self.com_node(nodelist[1]), lineno=nodelist[0][2]) def yield_stmt(self, nodelist): - return Yield(self.com_node(nodelist[1]), lineno=nodelist[0][2]) + expr = self.com_node(nodelist[0]) + return Discard(expr, lineno=expr.lineno) + + def yield_expr(self, nodelist): + if len(nodelist)>1: + value = nodelist[1] + else: + value = Const(None) + return Yield(self.com_node(value), lineno=nodelist[0][2]) def raise_stmt(self, nodelist): # raise: [test [',' test [',' test]]] @@ -1402,6 +1410,8 @@ if hasattr(symbol, 'yield_stmt'): _legal_node_types.append(symbol.yield_stmt) +if hasattr(symbol, 'yield_expr'): + _legal_node_types.append(symbol.yield_expr) _assign_types = [ symbol.test, From pje at users.sourceforge.net Tue Aug 2 02:47:15 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 01 Aug 2005 17:47:15 -0700 Subject: [Python-checkins] python/dist/src/Lib symbol.py,1.18,1.19 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12011/Lib Modified Files: symbol.py Log Message: PEP 342 implementation. Per Guido's comments, the generator throw() method still needs to support string exceptions, and allow None for the third argument. Documentation updates are needed, too. Index: symbol.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/symbol.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- symbol.py 31 Aug 2004 10:07:00 -0000 1.18 +++ symbol.py 2 Aug 2005 00:46:42 -0000 1.19 @@ -88,6 +88,7 @@ gen_if = 331 testlist1 = 332 encoding_decl = 333 +yield_expr = 334 #--end constants-- sym_name = {} From pje at users.sourceforge.net Tue Aug 2 02:47:16 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 01 Aug 2005 17:47:16 -0700 Subject: [Python-checkins] python/dist/src/Lib/test test_generators.py, 1.44, 1.45 test_genexps.py, 1.7, 1.8 test_parser.py, 1.22, 1.23 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12011/Lib/test Modified Files: test_generators.py test_genexps.py test_parser.py Log Message: PEP 342 implementation. Per Guido's comments, the generator throw() method still needs to support string exceptions, and allow None for the third argument. Documentation updates are needed, too. Index: test_generators.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_generators.py,v retrieving revision 1.44 retrieving revision 1.45 diff -u -d -r1.44 -r1.45 --- test_generators.py 13 Sep 2004 01:07:12 -0000 1.44 +++ test_generators.py 2 Aug 2005 00:46:43 -0000 1.45 @@ -382,7 +382,7 @@ >>> type(i) >>> [s for s in dir(i) if not s.startswith('_')] -['gi_frame', 'gi_running', 'next'] +['close', 'gi_frame', 'gi_running', 'next', 'send', 'throw'] >>> print i.next.__doc__ x.next() -> the next value, or raise StopIteration >>> iter(i) is i @@ -421,6 +421,7 @@ ... self.name = name ... self.parent = None ... self.generator = self.generate() +... self.close = self.generator.close ... ... def generate(self): ... while not self.parent: @@ -482,6 +483,9 @@ A->A B->G C->A D->G E->G F->A G->G H->G I->A J->G K->A L->A M->G merged A into G A->G B->G C->G D->G E->G F->G G->G H->G I->G J->G K->G L->G M->G + +>>> for s in sets: s.close() # break cycles + """ # Emacs turd ' @@ -589,6 +593,7 @@ ... def __init__(self, g): ... self.sofar = [] ... self.fetch = g.next +... self.close = g.close ... ... def __getitem__(self, i): ... sofar, fetch = self.sofar, self.fetch @@ -619,6 +624,7 @@ [200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384] [400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675] +>>> m235.close() Ye olde Fibonacci generator, LazyList style. @@ -642,6 +648,7 @@ >>> fib = LazyList(fibgen(1, 2)) >>> firstn(iter(fib), 17) [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584] +>>> fib.close() """ # syntax_tests mostly provokes SyntaxErrors. Also fiddling with #if 0 @@ -672,7 +679,7 @@ .. SyntaxError: 'return' with argument inside generator (, line 3) -This one is fine: +These are fine: >>> def f(): ... yield 1 @@ -683,9 +690,6 @@ ... yield 1 ... finally: ... pass -Traceback (most recent call last): - .. -SyntaxError: 'yield' not allowed in a 'try' block with a 'finally' clause (, line 3) >>> def f(): ... try: @@ -697,11 +701,6 @@ ... pass ... finally: ... pass -Traceback (most recent call last): - ... -SyntaxError: 'yield' not allowed in a 'try' block with a 'finally' clause (, line 6) - -But this is fine: >>> def f(): ... try: @@ -722,14 +721,16 @@ >>> def f(): ... yield -Traceback (most recent call last): -SyntaxError: invalid syntax +>>> type(f()) + + >>> def f(): ... if 0: ... yield -Traceback (most recent call last): -SyntaxError: invalid syntax +>>> type(f()) + + >>> def f(): ... if 0: @@ -805,7 +806,7 @@ ... if 0: ... yield 2 # because it's a generator Traceback (most recent call last): -SyntaxError: 'return' with argument inside generator (, line 8) +SyntaxError: 'return' with argument inside generator (, line 8) This one caused a crash (see SF bug 567538): @@ -1383,6 +1384,250 @@ """ +coroutine_tests = """\ +Sending a value into a started generator: + +>>> def f(): +... print (yield 1) +... yield 2 +>>> g = f() +>>> g.next() +1 +>>> g.send(42) +42 +2 + +Sending a value into a new generator produces a TypeError: + +>>> f().send("foo") +Traceback (most recent call last): +... +TypeError: can't send non-None value to a just-started generator + + +Yield by itself yields None: + +>>> def f(): yield +>>> list(f()) +[None] + + + +An obscene abuse of a yield expression within a generator expression: + +>>> list((yield 21) for i in range(4)) +[21, None, 21, None, 21, None, 21, None] + +And a more sane, but still weird usage: + +>>> def f(): list(i for i in [(yield 26)]) +>>> type(f()) + + + +Check some syntax errors for yield expressions: + +>>> f=lambda: (yield 1),(yield 2) +Traceback (most recent call last): + ... +SyntaxError: 'yield' outside function (, line 1) + +>>> def f(): return lambda x=(yield): 1 +Traceback (most recent call last): + ... +SyntaxError: 'return' with argument inside generator (, line 1) + +>>> def f(): x = yield = y +Traceback (most recent call last): + ... +SyntaxError: assignment to yield expression not possible (, line 1) + + +Now check some throw() conditions: + +>>> def f(): +... while True: +... try: +... print (yield) +... except ValueError,v: +... print "caught ValueError (%s)" % (v), +>>> import sys +>>> g = f() +>>> g.next() + +>>> g.throw(ValueError) # type only +caught ValueError () + +>>> g.throw(ValueError("xyz")) # value only +caught ValueError (xyz) + +>>> g.throw(ValueError, ValueError(1)) # value+matching type +caught ValueError (1) + +>>> g.throw(ValueError, TypeError(1)) # mismatched type, rewrapped +caught ValueError (1) + +>>> g.throw(ValueError(1), "foo") # bad args +Traceback (most recent call last): + ... +TypeError: instance exception may not have a separate value + +>>> g.throw(ValueError, "foo", 23) # bad args +Traceback (most recent call last): + ... +TypeError: throw() third argument must be a traceback object + +>>> def throw(g,exc): +... try: +... raise exc +... except: +... g.throw(*sys.exc_info()) +>>> throw(g,ValueError) # do it with traceback included +caught ValueError () + +>>> g.send(1) +1 + +>>> throw(g,TypeError) # terminate the generator +Traceback (most recent call last): + ... +TypeError + +>>> print g.gi_frame +None + +>>> g.send(2) +Traceback (most recent call last): + ... +StopIteration + +>>> g.throw(ValueError,6) # throw on closed generator +Traceback (most recent call last): + ... +ValueError: 6 + +>>> f().throw(ValueError,7) # throw on just-opened generator +Traceback (most recent call last): + ... +ValueError: 7 + + +Now let's try closing a generator: + +>>> def f(): +... try: yield +... except GeneratorExit: +... print "exiting" + +>>> g = f() +>>> g.next() +>>> g.close() +exiting +>>> g.close() # should be no-op now + +>>> f().close() # close on just-opened generator should be fine + +>>> def f(): yield # an even simpler generator +>>> f().close() # close before opening +>>> g = f() +>>> g.next() +>>> g.close() # close normally + +And finalization: + +>>> def f(): +... try: yield +... finally: +... print "exiting" + +>>> g = f() +>>> g.next() +>>> del g +exiting + + +Now let's try some ill-behaved generators: + +>>> def f(): +... try: yield +... except GeneratorExit: +... yield "foo!" +>>> g = f() +>>> g.next() +>>> g.close() +Traceback (most recent call last): + ... +RuntimeError: generator ignored GeneratorExit +>>> g.close() + + +Our ill-behaved code should be invoked during GC: + +>>> import sys, StringIO +>>> old, sys.stderr = sys.stderr, StringIO.StringIO() +>>> g = f() +>>> g.next() +>>> del g +>>> sys.stderr.getvalue().startswith( +... "Exception exceptions.RuntimeError: 'generator ignored GeneratorExit' in " +... ) +True +>>> sys.stderr = old + + +And errors thrown during closing should propagate: + +>>> def f(): +... try: yield +... except GeneratorExit: +... raise TypeError("fie!") +>>> g = f() +>>> g.next() +>>> g.close() +Traceback (most recent call last): + ... +TypeError: fie! + + +Ensure that various yield expression constructs make their +enclosing function a generator: + +>>> def f(): x += yield +>>> type(f()) + + +>>> def f(): x = yield +>>> type(f()) + + +>>> def f(): lambda x=(yield): 1 +>>> type(f()) + + +>>> def f(): x=(i for i in (yield) if (yield)) +>>> type(f()) + + +>>> def f(d): d[(yield "a")] = d[(yield "b")] = 27 +>>> data = [1,2] +>>> g = f(data) +>>> type(g) + +>>> g.send(None) +'a' +>>> data +[1, 2] +>>> g.send(0) +'b' +>>> data +[27, 2] +>>> try: g.send(1) +... except StopIteration: pass +>>> data +[27, 27] + +""" + __test__ = {"tut": tutorial_tests, "pep": pep_tests, "email": email_tests, @@ -1390,6 +1635,7 @@ "syntax": syntax_tests, "conjoin": conjoin_tests, "weakref": weakref_tests, + "coroutine": coroutine_tests, } # Magic test name that regrtest.py invokes *after* importing this module. Index: test_genexps.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_genexps.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- test_genexps.py 30 Sep 2004 22:29:03 -0000 1.7 +++ test_genexps.py 2 Aug 2005 00:46:43 -0000 1.8 @@ -130,7 +130,7 @@ >>> (y for y in (1,2)) += 10 Traceback (most recent call last): ... - SyntaxError: augmented assign to tuple literal or generator expression not possible + SyntaxError: augmented assign to tuple literal, yield, or generator expression not possible Index: test_parser.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_parser.py,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- test_parser.py 20 Apr 2005 17:45:12 -0000 1.22 +++ test_parser.py 2 Aug 2005 00:46:43 -0000 1.23 @@ -29,11 +29,22 @@ def test_yield_statement(self): self.check_suite("def f(): yield 1") + self.check_suite("def f(): yield") + self.check_suite("def f(): x += yield") + self.check_suite("def f(): x = yield 1") + self.check_suite("def f(): x = y = yield 1") + self.check_suite("def f(): x = yield") + self.check_suite("def f(): x = y = yield") + self.check_suite("def f(): 1 + (yield)*2") + self.check_suite("def f(): (yield 1)*2") self.check_suite("def f(): return; yield 1") self.check_suite("def f(): yield 1; return") self.check_suite("def f():\n" " for x in range(30):\n" " yield x\n") + self.check_suite("def f():\n" + " if (yield):\n" + " yield x\n") def test_expressions(self): self.check_expr("foo(1)") From pje at users.sourceforge.net Tue Aug 2 02:47:18 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 01 Aug 2005 17:47:18 -0700 Subject: [Python-checkins] python/dist/src/Modules gcmodule.c, 2.81, 2.82 parsermodule.c, 2.86, 2.87 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12011/Modules Modified Files: gcmodule.c parsermodule.c Log Message: PEP 342 implementation. Per Guido's comments, the generator throw() method still needs to support string exceptions, and allow None for the third argument. Documentation updates are needed, too. Index: gcmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/gcmodule.c,v retrieving revision 2.81 retrieving revision 2.82 diff -u -d -r2.81 -r2.82 --- gcmodule.c 18 Jun 2005 17:37:06 -0000 2.81 +++ gcmodule.c 2 Aug 2005 00:46:43 -0000 2.82 @@ -413,10 +413,8 @@ assert(delstr != NULL); return _PyInstance_Lookup(op, delstr) != NULL; } - else if (PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE)) + else return op->ob_type->tp_del != NULL; - else - return 0; } /* Move the objects in unreachable with __del__ methods into `finalizers`. Index: parsermodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/parsermodule.c,v retrieving revision 2.86 retrieving revision 2.87 diff -u -d -r2.86 -r2.87 --- parsermodule.c 9 Apr 2005 02:30:14 -0000 2.86 +++ parsermodule.c 2 Aug 2005 00:46:44 -0000 2.87 @@ -859,7 +859,8 @@ VALIDATER(listmaker); VALIDATER(yield_stmt); VALIDATER(testlist1); VALIDATER(gen_for); VALIDATER(gen_iter); VALIDATER(gen_if); -VALIDATER(testlist_gexp); +VALIDATER(testlist_gexp); VALIDATER(yield_expr); +VALIDATER(yield_or_testlist); #undef VALIDATER @@ -1507,6 +1508,15 @@ static int +validate_yield_or_testlist(node *tree) +{ + if (TYPE(tree) == yield_expr) + return validate_yield_expr(tree); + else + return validate_testlist(tree); +} + +static int validate_expr_stmt(node *tree) { int j; @@ -1517,8 +1527,8 @@ if (res && nch == 3 && TYPE(CHILD(tree, 1)) == augassign) { - res = (validate_numnodes(CHILD(tree, 1), 1, "augassign") - && validate_testlist(CHILD(tree, 2))); + res = validate_numnodes(CHILD(tree, 1), 1, "augassign") + && validate_yield_or_testlist(CHILD(tree, 2)); if (res) { char *s = STR(CHILD(CHILD(tree, 1), 0)); @@ -1541,8 +1551,8 @@ } else { for (j = 1; res && (j < nch); j += 2) - res = (validate_equal(CHILD(tree, j)) - && validate_testlist(CHILD(tree, j + 1))); + res = validate_equal(CHILD(tree, j)) + && validate_yield_or_testlist(CHILD(tree, j + 1)); } return (res); } @@ -1649,15 +1659,31 @@ } -/* yield_stmt: 'yield' testlist +/* yield_expr: 'yield' [testlist] + */ +static int +validate_yield_expr(node *tree) +{ + int nch = NCH(tree); + int res = (validate_ntype(tree, yield_expr) + && ((nch == 1) || (nch == 2)) + && validate_name(CHILD(tree, 0), "yield")); + + if (res && (nch == 2)) + res = validate_testlist(CHILD(tree, 1)); + + return (res); +} + + +/* yield_stmt: yield_expr */ static int validate_yield_stmt(node *tree) { return (validate_ntype(tree, yield_stmt) - && validate_numnodes(tree, 2, "yield_stmt") - && validate_name(CHILD(tree, 0), "yield") - && validate_testlist(CHILD(tree, 1))); + && validate_numnodes(tree, 1, "yield_stmt") + && validate_yield_expr(CHILD(tree, 0))); } @@ -2300,8 +2326,12 @@ res = ((nch <= 3) && (validate_rparen(CHILD(tree, nch - 1)))); - if (res && (nch == 3)) - res = validate_testlist_gexp(CHILD(tree, 1)); + if (res && (nch == 3)) { + if (TYPE(CHILD(tree, 1))==yield_expr) + res = validate_yield_expr(CHILD(tree, 1)); + else + res = validate_testlist_gexp(CHILD(tree, 1)); + } break; case LSQB: if (nch == 2) @@ -2914,6 +2944,9 @@ case testlist: res = validate_testlist(tree); break; + case yield_expr: + res = validate_yield_expr(tree); + break; case testlist1: res = validate_testlist1(tree); break; From pje at users.sourceforge.net Tue Aug 2 02:47:18 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 01 Aug 2005 17:47:18 -0700 Subject: [Python-checkins] python/dist/src/Objects genobject.c,1.4,1.5 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12011/Objects Modified Files: genobject.c Log Message: PEP 342 implementation. Per Guido's comments, the generator throw() method still needs to support string exceptions, and allow None for the third argument. Documentation updates are needed, too. Index: genobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/genobject.c,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- genobject.c 1 Sep 2004 07:02:44 -0000 1.4 +++ genobject.c 2 Aug 2005 00:46:45 -0000 1.5 @@ -15,15 +15,31 @@ static void gen_dealloc(PyGenObject *gen) { + PyObject *self = (PyObject *) gen; + _PyObject_GC_UNTRACK(gen); + if (gen->gi_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) gen); - Py_DECREF(gen->gi_frame); + + + _PyObject_GC_TRACK(self); + + if (gen->gi_frame->f_stacktop!=NULL) { + /* Generator is paused, so we need to close */ + gen->ob_type->tp_del(self); + if (self->ob_refcnt > 0) + return; /* resurrected. :( */ + } + + _PyObject_GC_UNTRACK(self); + Py_XDECREF(gen->gi_frame); PyObject_GC_Del(gen); } + static PyObject * -gen_iternext(PyGenObject *gen) +gen_send_ex(PyGenObject *gen, PyObject *arg, int exc) { PyThreadState *tstate = PyThreadState_GET(); PyFrameObject *f = gen->gi_frame; @@ -34,8 +50,24 @@ "generator already executing"); return NULL; } - if (f->f_stacktop == NULL) + if ((PyObject *)f == Py_None || f->f_stacktop == NULL) { + /* Only set exception if called from send() */ + if (arg && !exc) PyErr_SetNone(PyExc_StopIteration); return NULL; + } + + if (f->f_lasti == -1) { + if (arg && arg != Py_None) { + PyErr_SetString(PyExc_TypeError, + "can't send non-None value to a just-started generator"); + return NULL; + } + } else { + /* Push arg onto the frame's value stack */ + result = arg ? arg : Py_None; + Py_INCREF(result); + *(f->f_stacktop++) = result; + } /* Generators always return to their most recent caller, not * necessarily their creator. */ @@ -44,7 +76,7 @@ f->f_back = tstate->frame; gen->gi_running = 1; - result = PyEval_EvalFrame(f); + result = PyEval_EvalFrameEx(f, exc); gen->gi_running = 0; /* Don't keep the reference to f_back any longer than necessary. It @@ -58,17 +90,199 @@ if (result == Py_None && f->f_stacktop == NULL) { Py_DECREF(result); result = NULL; + /* Set exception if not called by gen_iternext() */ + if (arg) PyErr_SetNone(PyExc_StopIteration); + } + + if (!result || f->f_stacktop == NULL) { + /* generator can't be rerun, so release the frame */ + Py_DECREF(f); + gen->gi_frame = (PyFrameObject *)Py_None; + Py_INCREF(Py_None); } return result; } +PyDoc_STRVAR(send_doc, +"send(arg) -> send 'arg' into generator, return next yielded value or raise StopIteration."); + +static PyObject * +gen_send(PyGenObject *gen, PyObject *arg) +{ + return gen_send_ex(gen, arg, 0); +} + +PyDoc_STRVAR(close_doc, +"close(arg) -> raise GeneratorExit inside generator."); + +static PyObject * +gen_close(PyGenObject *gen, PyObject *args) +{ + PyObject *retval; + PyErr_SetNone(PyExc_GeneratorExit); + retval = gen_send_ex(gen, Py_None, 1); + if (retval) { + Py_DECREF(retval); + PyErr_SetString(PyExc_RuntimeError, + "generator ignored GeneratorExit"); + return NULL; + } + if ( PyErr_ExceptionMatches(PyExc_StopIteration) + || PyErr_ExceptionMatches(PyExc_GeneratorExit) ) + { + PyErr_Clear(); /* ignore these errors */ + Py_INCREF(Py_None); + return Py_None; + } + return NULL; +} + +static void +gen_del(PyObject *self) +{ + PyObject *res; + PyObject *error_type, *error_value, *error_traceback; + PyGenObject *gen = (PyGenObject *)self; + + if ((PyObject *)gen->gi_frame == Py_None || gen->gi_frame->f_stacktop==NULL) + /* Generator isn't paused, so no need to close */ + return; + + /* Temporarily resurrect the object. */ + assert(self->ob_refcnt == 0); + self->ob_refcnt = 1; + + /* Save the current exception, if any. */ + PyErr_Fetch(&error_type, &error_value, &error_traceback); + + res = gen_close((PyGenObject *)self, NULL); + + if (res == NULL) + PyErr_WriteUnraisable((PyObject *)self); + else + Py_DECREF(res); + + /* Restore the saved exception. */ + PyErr_Restore(error_type, error_value, error_traceback); + + /* Undo the temporary resurrection; can't use DECREF here, it would + * cause a recursive call. + */ + assert(self->ob_refcnt > 0); + if (--self->ob_refcnt == 0) + return; /* this is the normal path out */ + + /* close() resurrected it! Make it look like the original Py_DECREF + * never happened. + */ + { + int refcnt = self->ob_refcnt; + _Py_NewReference(self); + self->ob_refcnt = refcnt; + } + assert(!PyType_IS_GC(self->ob_type) || + _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); + + /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so + * we need to undo that. */ + _Py_DEC_REFTOTAL; + /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object + * chain, so no more to do there. + * If COUNT_ALLOCS, the original decref bumped tp_frees, and + * _Py_NewReference bumped tp_allocs: both of those need to be + * undone. + */ +#ifdef COUNT_ALLOCS + --self->ob_type->tp_frees; + --self->ob_type->tp_allocs; +#endif +} + + + +PyDoc_STRVAR(throw_doc, +"throw(typ[,val[,tb]]) -> raise exception in generator, return next yielded value or raise StopIteration."); + +static PyObject * +gen_throw(PyGenObject *gen, PyObject *args) +{ + PyObject *typ; + PyObject *tb = NULL; + PyObject *val = NULL; + + if (!PyArg_ParseTuple(args, "O|OO:throw", &typ, &val, &tb)) + return NULL; + + if (tb && !PyTraceBack_Check(tb)) { + PyErr_SetString(PyExc_TypeError, + "throw() third argument must be a traceback object"); + return NULL; + } + + Py_INCREF(typ); + Py_XINCREF(val); + Py_XINCREF(tb); + + if (PyClass_Check(typ)) { + PyErr_NormalizeException(&typ, &val, &tb); + } + + else if (PyInstance_Check(typ)) { + /* Raising an instance. The value should be a dummy. */ + if (val && val != Py_None) { + PyErr_SetString(PyExc_TypeError, + "instance exception may not have a separate value"); + goto failed_throw; + } + else { + /* Normalize to raise , */ + val = typ; + typ = (PyObject*) ((PyInstanceObject*)typ)->in_class; + Py_INCREF(typ); + } + } + else { + /* Not something you can raise. You get an exception + anyway, just not what you specified :-) */ + PyErr_Format(PyExc_TypeError, + "exceptions must be classes, or instances, not %s", + typ->ob_type->tp_name); + goto failed_throw; + } + + PyErr_Restore(typ,val,tb); + return gen_send_ex(gen, Py_None, 1); + +failed_throw: + /* Didn't use our arguments, so restore their original refcounts */ + Py_DECREF(typ); + Py_XDECREF(val); + Py_XDECREF(tb); + return NULL; +} + + +static PyObject * +gen_iternext(PyGenObject *gen) +{ + return gen_send_ex(gen, NULL, 0); +} + + static PyMemberDef gen_memberlist[] = { {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), RO}, {"gi_running", T_INT, offsetof(PyGenObject, gi_running), RO}, {NULL} /* Sentinel */ }; +static PyMethodDef gen_methods[] = { + {"send",(PyCFunction)gen_send, METH_O, send_doc}, + {"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc}, + {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, + {NULL, NULL} /* Sentinel */ +}; + PyTypeObject PyGen_Type = { PyObject_HEAD_INIT(&PyType_Type) 0, /* ob_size */ @@ -99,11 +313,26 @@ offsetof(PyGenObject, gi_weakreflist), /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)gen_iternext, /* tp_iternext */ - 0, /* tp_methods */ + gen_methods, /* tp_methods */ gen_memberlist, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ + + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ + 0, /* tp_is_gc */ + 0, /* tp_bases */ + 0, /* tp_mro */ + 0, /* tp_cache */ + 0, /* tp_subclasses */ + 0, /* tp_weaklist */ + gen_del, /* tp_del */ }; PyObject * From montanaro at users.sourceforge.net Tue Aug 2 04:50:28 2005 From: montanaro at users.sourceforge.net (montanaro@users.sourceforge.net) Date: Mon, 01 Aug 2005 19:50:28 -0700 Subject: [Python-checkins] python/dist/src/Lib cgi.py,1.83,1.84 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31219 Modified Files: cgi.py Log Message: Bring cgi.escape docstring slightly more in line with the library ref manual. Closes #1243553. Index: cgi.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/cgi.py,v retrieving revision 1.83 retrieving revision 1.84 diff -u -d -r1.83 -r1.84 --- cgi.py 8 Jan 2005 13:56:36 -0000 1.83 +++ cgi.py 2 Aug 2005 02:50:25 -0000 1.84 @@ -1041,7 +1041,9 @@ # ========= def escape(s, quote=None): - """Replace special characters '&', '<' and '>' by SGML entities.""" + '''Replace special characters "&", "<" and ">" to HTML-safe sequences. + If the optional flag quote is true, the quotation mark character (") + is also translated.''' s = s.replace("&", "&") # Must be done first! s = s.replace("<", "<") s = s.replace(">", ">") From montanaro at users.sourceforge.net Tue Aug 2 04:54:01 2005 From: montanaro at users.sourceforge.net (montanaro@users.sourceforge.net) Date: Mon, 01 Aug 2005 19:54:01 -0700 Subject: [Python-checkins] python/dist/src/Doc/lib libcgi.tex,1.45,1.46 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31743 Modified Files: libcgi.tex Log Message: Minor tweak as a side effect of fixing #1243553. The Unicode name for " is 'quotation mark', so I decided to use it instead of 'double-quote'. Index: libcgi.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcgi.tex,v retrieving revision 1.45 retrieving revision 1.46 diff -u -d -r1.45 -r1.46 --- libcgi.tex 10 Jul 2004 11:15:56 -0000 1.45 +++ libcgi.tex 2 Aug 2005 02:53:59 -0000 1.46 @@ -404,7 +404,7 @@ \character{\&}, \character{<} and \character{>} in string \var{s} to HTML-safe sequences. Use this if you need to display text that might contain such characters in HTML. If the optional flag \var{quote} is -true, the double-quote character (\character{"}) is also translated; +true, the quotation mark character (\character{"}) is also translated; this helps for inclusion in an HTML attribute value, as in \code{}. If the value to be quoted might include single- or double-quote characters, or both, consider using the From rhettinger at users.sourceforge.net Tue Aug 2 05:45:26 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Mon, 01 Aug 2005 20:45:26 -0700 Subject: [Python-checkins] python/dist/src/Include setobject.h,2.7,2.8 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6483/Include Modified Files: setobject.h Log Message: Model set.pop() after dict.popitem(). Index: setobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/setobject.h,v retrieving revision 2.7 retrieving revision 2.8 diff -u -d -r2.7 -r2.8 --- setobject.h 1 Aug 2005 21:39:27 -0000 2.7 +++ setobject.h 2 Aug 2005 03:45:16 -0000 2.8 @@ -13,6 +13,10 @@ 1. Unused: key == NULL 2. Active: key != NULL and key != dummy 3. Dummy: key == dummy + +Note: .pop() abuses the hash field of an Unused or Dummy slot to +hold a search finger. The hash field of Unused or Dummy slots has +no meaning otherwise. */ #define PySet_MINSIZE 8 From rhettinger at users.sourceforge.net Tue Aug 2 05:45:26 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Mon, 01 Aug 2005 20:45:26 -0700 Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.38,1.39 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6483/Objects Modified Files: setobject.c Log Message: Model set.pop() after dict.popitem(). Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- setobject.c 1 Aug 2005 21:39:28 -0000 1.38 +++ setobject.c 2 Aug 2005 03:45:14 -0000 1.39 @@ -1508,24 +1508,42 @@ set_pop(PySetObject *so) { PyObject *key; - int pos = 0; - int rv; + register setentry *entry; + register int i = 0; - if (!set_next_internal(so, &pos, &key)) { + assert (PyAnySet_Check(so)); + if (so->used == 0) { PyErr_SetString(PyExc_KeyError, "pop from an empty set"); return NULL; } - Py_INCREF(key); - rv = set_discard_internal(so, key); - if (rv == -1) { - Py_DECREF(key); - return NULL; - } else if (rv == DISCARD_NOTFOUND) { - Py_DECREF(key); - PyErr_SetObject(PyExc_KeyError, key); - return NULL; + /* Set entry to "the first" unused or dummy set entry. We abuse + * the hash field of slot 0 to hold a search finger: + * If slot 0 has a value, use slot 0. + * Else slot 0 is being used to hold a search finger, + * and we use its hash value as the first index to look. + */ + entry = &so->table[0]; + if (entry->key == NULL || entry->key == dummy) { + i = (int)entry->hash; + /* The hash field may be a real hash value, or it may be a + * legit search finger, or it may be a once-legit search + * finger that's out of bounds now because it wrapped around + * or the table shrunk -- simply make sure it's in bounds now. + */ + if (i > so->mask || i < 1) + i = 1; /* skip slot 0 */ + while ((entry = &so->table[i])->key == NULL || entry->key==dummy) { + i++; + if (i > so->mask) + i = 1; + } } + key = entry->key; + Py_INCREF(dummy); + entry->key = dummy; + so->used--; + so->table[0].hash = i + 1; /* next place to start */ return key; } From gregorykjohnson at users.sourceforge.net Tue Aug 2 05:49:04 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Mon, 01 Aug 2005 20:49:04 -0700 Subject: [Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.2, 1.3 test_mailbox.py, 1.2, 1.3 libmailbox.tex, 1.3, 1.4 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6902 Modified Files: mailbox.py test_mailbox.py libmailbox.tex Log Message: * Implement mbox (needs more tests). * Implement mailbox locking. * Replace flush() on mailboxes with close(). Use close() in tests. * Fix numerous non-portable format assumptions by using os.linesep. * Refactor much test code. Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- mailbox.py 30 Jul 2005 22:49:08 -0000 1.2 +++ mailbox.py 2 Aug 2005 03:49:01 -0000 1.3 @@ -12,6 +12,10 @@ import email.Message import email.Generator import rfc822 +try: + import fnctl +except ImportError: + pass __all__ = [ 'open', 'Mailbox', 'Maildir', 'mbox', 'MH', 'Babyl', 'MMDF', 'Message', 'MaildirMessage', 'mboxMessage', 'MHMessage', @@ -162,8 +166,8 @@ if bad_key: raise KeyError, "No message with key(s)" - def flush(self): - """Write any pending changes to disk.""" + def close(self): + """Close mailbox and write any pending changes to disk.""" raise NotImplementedError, "Method must be implemented by subclass" def _dump_message(self, message, target): @@ -301,8 +305,8 @@ self._refresh() return len(self._toc) - def flush(self): - """Write any pending changes to disk.""" + def close(self): + """Close mailbox and write any pending changes to disk.""" return # Maildir changes are always written immediately. def list_folders(self): @@ -396,6 +400,181 @@ raise KeyError, "No message with key '%s'" % key +class mbox(Mailbox): + """A classic mbox mailbox.""" + + def __init__(self, path, factory=None): + """Initialize an mbox instance.""" + Mailbox.__init__(self, path, factory) + try: + f = file(self._path, 'r+') + except IOError, e: + if e.errno == errno.ENOENT: + f = file(self._path, 'w+') + elif e.errno == errno.EACCES: + f = file(self._path, 'r') + else: + raise + try: + _lock_file(f) + except: + f.close() + raise + self._file = f + self._toc = None + self._next_key = 0 + + def add(self, message): + """Add message and return assigned key.""" + self._lookup() + self._toc[self._next_key] = self._append_message(message) + self._next_key += 1 + return self._next_key - 1 + + def remove(self, key): + """Remove the keyed message; raise KeyError if it doesn't exist.""" + del self._toc[key] + + def __setitem__(self, key, message): + """Replace the keyed message; raise KeyError if it doesn't exist.""" + self._lookup(key) + start, stop = self._append_message(message) + self._toc[key] = (start, stop) + + def get_message(self, key): + start, stop = self._lookup(key) + self._file.seek(start) + from_line = self._file.readline() + msg = mboxMessage(self._file.read(stop - self._file.tell())) + msg.set_from(from_line[5:-1]) + return msg + + def get_string(self, key, from_=False): + """Return a string representation or raise a KeyError.""" + start, stop = self._lookup(key) + self._file.seek(start) + if not from_: + self._file.readline() + return self._file.read(stop - self._file.tell()) + + def get_file(self, key, from_=False): + """Return a file-like representation or raise a KeyError.""" + start, stop = self._lookup(key) + self._file.seek(start) + if not from_: + self._file.readline() + return _PartialFile(self._file, self._file.tell(), stop) + + def iterkeys(self): + """Return an iterator over keys.""" + self._lookup() + for key in self._toc.keys(): + yield key + + def has_key(self, key): + """Return True if the keyed message exists, False otherwise.""" + self._lookup() + return key in self._toc + + def __len__(self): + """Return a count of messages in the mailbox.""" + self._lookup() + return len(self._toc) + + def close(self): + """Close mailbox and write any pending changes to disk.""" + self._lookup() + f = file(self._path + '.tmp', 'w') + try: + new_toc = {} + for key in sorted(self._toc.keys()): + start, stop = self._toc[key] + self._file.seek(start) + if f.tell() != 0: + f.write(os.linesep) + new_start = f.tell() + while True: + buffer = self._file.read(min(4096, + stop - self._file.tell())) + if buffer == '': + break + f.write(buffer) + new_toc[key] = (new_start, f.tell()) + finally: + f.close() + try: + os.rename(self._path + '.tmp', self._path) + except oserror, e: + if e.errno == errno.eexist: + # xxx: is this is the exception Windows raises? + os.remove(self._path) + os.rename(self._path + '.tmp', self._path) + else: + raise + self._file.close() + if os.path.exists(self._path + '.lock'): + os.remove(self._path + '.lock') + + def _generate_toc(self): + """Generate key-to-(start, stop) table of contents.""" + starts, stops = [], [] + self._file.seek(0) + prev_line = '' + while True: + pos = self._file.tell() + line = self._file.readline() + if line[:5] == 'From ': + starts.append(pos) + # The preceeding newline is part of the separator, e.g., + # "\nFrom .*\n", not part of the previous message. Ignore it. + if prev_line != '': + stops.append(pos - len(os.linesep)) + elif line == '': + stops.append(pos) + break + prev_line = line + self._toc = dict(enumerate(zip(starts, stops))) + self._next_key = len(self._toc) + + def _lookup(self, key=None): + """Return (start, stop) for given key, or raise a KeyError.""" + if self._toc is None: + self._generate_toc() + if key is not None: + try: + return self._toc[key] + except IndexError: + raise KeyError, "No message with key '%s'" % key + + def _append_message(self, message): + """Append message to mailbox and return (start, stop) offset.""" + from_line = None + if isinstance(message, str) and message[:5] == 'From ': + newline = message.find(os.linesep) + if newline != -1: + from_line = message[:newline] + message = message[newline + len(os.linesep):] + else: + from_line = message + message = '' + elif isinstance(message, _mboxMMDFMessage): + from_line = 'From ' + message.get_from() + elif isinstance(message, email.Message.Message): + from_line = message.get_unixfrom() + if from_line is None: + from_line = 'From MAILER-DAEMON %s' % \ + time.strftime('%a %b %d %H:%M:%S %Y', time.gmtime()) + self._file.seek(0, 2) + if self._file.tell() == 0: + start = self._file.tell() + self._file.write('%s%s' % (from_line, os.linesep)) + else: + start = self._file.tell() + 1 + self._file.write('%s%s%s' % (os.linesep, from_line, os.linesep)) + self._dump_message(message, self._file) + return (start, self._file.tell()) + + class Message(email.Message.Message): """Message with mailbox-format-specific properties.""" @@ -533,6 +712,7 @@ elif 'Return-Path' in message: # XXX: generate "From " line from Return-Path: and Received: pass + Message.__init__(self, message) def get_from(self): @@ -876,3 +1056,53 @@ class Error(Exception): """Raised for module-specific errors.""" + + +def _lock_file(f): + """Use various means to lock f (f.name should be absolute).""" + if 'fcntl' in globals(): + try: + fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB) + except IOError, e: + if e.errno == errno.EAGAIN: + raise Error, 'Failed to acquire exclusive lock ' \ + 'using lockf: %s' % f.name + elif e.errno == errno.EBADF: + try: + fcntl.lockf(f, fcntl.LOCK_SH | fntl.LOCK_NB) + except IOError, e: + if e.errno == errno.EAGAIN: + raise Error, 'Failed to acquire shared lock ' \ + 'using lockf: %s' % f.name + else: + raise + else: + raise + try: + fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) + except IOError, e: + if e.errno == errno.EWOULDBLOCK: + raise Error, 'Failed to aquire exclusive lock ' \ + 'using flock: %s' % f.name + else: + raise + tmp_name = f.name + '.%s.%s' % (socket.gethostname(), os.getpid()) + try: + file(tmp_name, 'w').close() + except IOError, e: + if e.errno == errno.EACCESS: + pass + else: + raise + else: + try: + if hasattr(os, 'link'): + os.link(tmp_name, f.name + '.lock') + os.unlink(tmp_name) + else: + os.rename(tmp_name, f.name + '.lock') + except OSError, e: + if e.errno == errno.EEXIST: + raise Error, 'Failed to acquire dot lock: %s' % f.name + else: + raise Index: test_mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- test_mailbox.py 30 Jul 2005 22:49:08 -0000 1.2 +++ test_mailbox.py 2 Aug 2005 03:49:01 -0000 1.3 @@ -10,6 +10,7 @@ from test import test_support import unittest import mailbox +import glob class TestBase(unittest.TestCase): @@ -44,191 +45,172 @@ class TestMailbox(TestBase): _factory = None # Overridden by subclasses to reuse tests [...1009 lines suppressed...] +-- +Gregory K. Johnson +""", +"""H4sICM2D1UIAA3RleHQAC8nILFYAokSFktSKEoW0zJxUPa7wzJIMhZLyfIWczLzUYj0uAHTs +3FYlAAAA +""") def test_main(): - test_support.run_unittest(TestMaildir, TestMessage, TestMaildirMessage, - TestMboxMessage, TestMHMessage, TestBabylMessage, - TestMMDFMessage, TestMessageConversion, - TestProxyFile, TestPartialFile) + tests = (TestMaildir, TestMbox, TestMessage, TestMaildirMessage, + TestMboxMessage, TestMHMessage, TestBabylMessage, TestMMDFMessage, + TestMessageConversion, TestProxyFile, TestPartialFile) + test_support.run_unittest(*tests) if __name__ == '__main__': Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- libmailbox.tex 30 Jul 2005 22:49:08 -0000 1.3 +++ libmailbox.tex 2 Aug 2005 03:49:01 -0000 1.4 @@ -242,10 +242,10 @@ are not supported.} \end{methoddesc} -\begin{methoddesc}{flush}{} -Write any pending changes to the filesystem. For some \class{Mailbox} -subclasses, this is done automatically and calling \method{flush()} has no -effect. More specific documentation is provided by each subclass. +\begin{methoddesc}{close}{} +Close the mailbox and write any pending changes to the filesystem. For some +\class{Mailbox} subclasses, changes are written immediately even without +calling this method. \end{methoddesc} @@ -316,9 +316,9 @@ these methods to manipulate the same mailbox simultaneously.} \end{methoddesc} -\begin{methoddesc}{flush}{} -All changes to Maildir mailboxes are immediately applied. This method does -nothing. +\begin{methoddesc}{close}{} +All changes to Maildir mailboxes are immediately applied even without calling +this method. \end{methoddesc} \begin{methoddesc}{get_file}{key} @@ -368,6 +368,9 @@ \begin{seealso} \seelink{http://www.qmail.org/man/man5/mbox.html}{mbox man page from qmail}{A specification of the format and its variations.} + \seelink{http://www.tin.org/bin/man.cgi?section=5\&topic=mbox}{mbox man + page from tin}{Another specification of the format, with details on + locking.} \seelink{http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html} {Configuring Netscape Mail on \UNIX{}: Why The Content-Length Format is Bad}{An argument for using the original mbox format rather than a @@ -451,8 +454,9 @@ XXX \end{methoddesc} -\begin{methoddesc}{flush}{} -All changes to MH mailboxes are immediately applied. This method does nothing. +\begin{methoddesc}{close}{} +All changes to MH mailboxes are immediately applied even without calling this +method. \end{methoddesc} \begin{classdesc}{MH}{path\optional{, factory}} From birkenfeld at users.sourceforge.net Tue Aug 2 12:28:18 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Tue, 02 Aug 2005 03:28:18 -0700 Subject: [Python-checkins] python/dist/src/Doc/lib libre.tex,1.113,1.114 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31597/Doc/lib Modified Files: libre.tex Log Message: [ 1243192 ] Incorrect documentation of re.UNICODE Index: libre.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libre.tex,v retrieving revision 1.113 retrieving revision 1.114 diff -u -d -r1.113 -r1.114 --- libre.tex 1 Jan 2005 00:28:37 -0000 1.113 +++ libre.tex 2 Aug 2005 10:28:08 -0000 1.114 @@ -342,17 +342,33 @@ at the beginning or end of a word. This is just the opposite of {}\code{\e b}, so is also subject to the settings of \code{LOCALE} and \code{UNICODE}. -\item[\code{\e d}]Matches any decimal digit; this is -equivalent to the set \regexp{[0-9]}. +\item[\code{\e d}]When the \constant{UNICODE} flag is not specified, matches +any decimal digit; this is equivalent to the set \regexp{[0-9]}. +With \constant{UNICODE}, it will match whatever is classified as a digit +in the Unicode character properties database. -\item[\code{\e D}]Matches any non-digit character; this is -equivalent to the set \regexp{[{\textasciicircum}0-9]}. +\item[\code{\e D}]When the \constant{UNICODE} flag is not specified, matches +any non-digit character; this is equivalent to the set +\regexp{[{\textasciicircum}0-9]}. With \constant{UNICODE}, it will match +anything other than character marked as digits in the Unicode character +properties database. -\item[\code{\e s}]Matches any whitespace character; this is +\item[\code{\e s}]When the \constant{LOCALE} and \constant{UNICODE} +flags are not specified, matches any whitespace character; this is equivalent to the set \regexp{[ \e t\e n\e r\e f\e v]}. +With \constant{LOCALE}, it will match this set plus whatever characters +are defined as space for the current locale. If \constant{UNICODE} is set, +this will match the characters \regexp{[ \e t\e n\e r\e f\e v]} plus +whatever is classified as space in the Unicode character properties +database. -\item[\code{\e S}]Matches any non-whitespace character; this is -equivalent to the set \regexp{[\textasciicircum\ \e t\e n\e r\e f\e v]}. +\item[\code{\e S}]When the \constant{LOCALE} and \constant{UNICODE} +flags are not specified, matches any non-whitespace character; this is +equivalent to the set \regexp{[\textasciicircum\ \e t\e n\e r\e f\e v]} +With \constant{LOCALE}, it will match any character not in this set, +and not defined as space in the current locale. If \constant{UNICODE} +is set, this will match anything other than \regexp{[ \e t\e n\e r\e f\e v]} +and characters marked as space in the Unicode character properties database. \item[\code{\e w}]When the \constant{LOCALE} and \constant{UNICODE} flags are not specified, matches any alphanumeric character and the @@ -468,8 +484,8 @@ \begin{datadesc}{L} \dataline{LOCALE} -Make \regexp{\e w}, \regexp{\e W}, \regexp{\e b}, and -\regexp{\e B} dependent on the current locale. +Make \regexp{\e w}, \regexp{\e W}, \regexp{\e b}, \regexp{\e B}, +\regexp{\e s} and \regexp{\e S} dependent on the current locale. \end{datadesc} \begin{datadesc}{M} @@ -493,8 +509,9 @@ \begin{datadesc}{U} \dataline{UNICODE} -Make \regexp{\e w}, \regexp{\e W}, \regexp{\e b}, and -\regexp{\e B} dependent on the Unicode character properties database. +Make \regexp{\e w}, \regexp{\e W}, \regexp{\e b}, \regexp{\e B}, +\regexp{\e d}, \regexp{\e D}, \regexp{\e s} and \regexp{\e S} +dependent on the Unicode character properties database. \versionadded{2.0} \end{datadesc} From birkenfeld at users.sourceforge.net Tue Aug 2 12:28:40 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Tue, 02 Aug 2005 03:28:40 -0700 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1327,1.1328 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31597/Misc Modified Files: NEWS Log Message: [ 1243192 ] Incorrect documentation of re.UNICODE Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1327 retrieving revision 1.1328 diff -u -d -r1.1327 -r1.1328 --- NEWS 31 Jul 2005 01:16:35 -0000 1.1327 +++ NEWS 2 Aug 2005 10:28:04 -0000 1.1328 @@ -433,6 +433,8 @@ Documentation ------------- +- Bug #1243192: re.UNICODE and re.LOCALE affect \d, \D, \s and \S. + - Bug #755617: Document the effects of os.chown() on Windows. - Patch #1180012: The documentation for modulefinder is now in the library reference. From birkenfeld at users.sourceforge.net Tue Aug 2 12:30:24 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Tue, 02 Aug 2005 03:30:24 -0700 Subject: [Python-checkins] python/dist/src/Doc/lib libre.tex, 1.112.2.1, 1.112.2.2 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31952/Doc/lib Modified Files: Tag: release24-maint libre.tex Log Message: backport [ 1243192 ] Incorrect documentation of re.UNICODE Index: libre.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libre.tex,v retrieving revision 1.112.2.1 retrieving revision 1.112.2.2 diff -u -d -r1.112.2.1 -r1.112.2.2 --- libre.tex 1 Jan 2005 00:34:53 -0000 1.112.2.1 +++ libre.tex 2 Aug 2005 10:30:08 -0000 1.112.2.2 @@ -342,17 +342,33 @@ at the beginning or end of a word. This is just the opposite of {}\code{\e b}, so is also subject to the settings of \code{LOCALE} and \code{UNICODE}. -\item[\code{\e d}]Matches any decimal digit; this is -equivalent to the set \regexp{[0-9]}. +\item[\code{\e d}]When the \constant{UNICODE} flag is not specified, matches +any decimal digit; this is equivalent to the set \regexp{[0-9]}. +With \constant{UNICODE}, it will match whatever is classified as a digit +in the Unicode character properties database. -\item[\code{\e D}]Matches any non-digit character; this is -equivalent to the set \regexp{[{\textasciicircum}0-9]}. +\item[\code{\e D}]When the \constant{UNICODE} flag is not specified, matches +any non-digit character; this is equivalent to the set +\regexp{[{\textasciicircum}0-9]}. With \constant{UNICODE}, it will match +anything other than character marked as digits in the Unicode character +properties database. -\item[\code{\e s}]Matches any whitespace character; this is +\item[\code{\e s}]When the \constant{LOCALE} and \constant{UNICODE} +flags are not specified, matches any whitespace character; this is equivalent to the set \regexp{[ \e t\e n\e r\e f\e v]}. +With \constant{LOCALE}, it will match this set plus whatever characters +are defined as space for the current locale. If \constant{UNICODE} is set, +this will match the characters \regexp{[ \e t\e n\e r\e f\e v]} plus +whatever is classified as space in the Unicode character properties +database. -\item[\code{\e S}]Matches any non-whitespace character; this is -equivalent to the set \regexp{[\textasciicircum\ \e t\e n\e r\e f\e v]}. +\item[\code{\e S}]When the \constant{LOCALE} and \constant{UNICODE} +flags are not specified, matches any non-whitespace character; this is +equivalent to the set \regexp{[\textasciicircum\ \e t\e n\e r\e f\e v]} +With \constant{LOCALE}, it will match any character not in this set, +and not defined as space in the current locale. If \constant{UNICODE} +is set, this will match anything other than \regexp{[ \e t\e n\e r\e f\e v]} +and characters marked as space in the Unicode character properties database. \item[\code{\e w}]When the \constant{LOCALE} and \constant{UNICODE} flags are not specified, matches any alphanumeric character and the @@ -468,8 +484,8 @@ \begin{datadesc}{L} \dataline{LOCALE} -Make \regexp{\e w}, \regexp{\e W}, \regexp{\e b}, and -\regexp{\e B} dependent on the current locale. +Make \regexp{\e w}, \regexp{\e W}, \regexp{\e b}, \regexp{\e B}, +\regexp{\e s} and \regexp{\e S} dependent on the current locale. \end{datadesc} \begin{datadesc}{M} @@ -493,8 +509,9 @@ \begin{datadesc}{U} \dataline{UNICODE} -Make \regexp{\e w}, \regexp{\e W}, \regexp{\e b}, and -\regexp{\e B} dependent on the Unicode character properties database. +Make \regexp{\e w}, \regexp{\e W}, \regexp{\e b}, \regexp{\e B}, +\regexp{\e d}, \regexp{\e D}, \regexp{\e s} and \regexp{\e S} +dependent on the Unicode character properties database. \versionadded{2.0} \end{datadesc} From birkenfeld at users.sourceforge.net Tue Aug 2 12:30:24 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Tue, 02 Aug 2005 03:30:24 -0700 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.67, 1.1193.2.68 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31952/Misc Modified Files: Tag: release24-maint NEWS Log Message: backport [ 1243192 ] Incorrect documentation of re.UNICODE Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.67 retrieving revision 1.1193.2.68 diff -u -d -r1.1193.2.67 -r1.1193.2.68 --- NEWS 26 Jul 2005 23:59:58 -0000 1.1193.2.67 +++ NEWS 2 Aug 2005 10:30:08 -0000 1.1193.2.68 @@ -98,6 +98,8 @@ Documentation ------------- +- Bug #1243192: re.UNICODE and re.LOCALE affect \d, \D, \s and \S. + - Bug #755617: Document the effects of os.chown() on Windows. - Patch #1180012: The documentation for modulefinder is now in the library reference. From birkenfeld at users.sourceforge.net Tue Aug 2 16:00:01 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Tue, 02 Aug 2005 07:00:01 -0700 Subject: [Python-checkins] python/nondist/sandbox/path path.py,1.8,1.9 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/path In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3627 Modified Files: path.py Log Message: Use self.__class__ instead of hardcoded Path. Index: path.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/path/path.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- path.py 30 Jul 2005 12:14:14 -0000 1.8 +++ path.py 2 Aug 2005 13:59:58 -0000 1.9 @@ -59,21 +59,21 @@ The argument can be either a string or an existing Path object. """ if not args: - return Path(os.curdir) + return typ(os.curdir) for arg in args: if not isinstance(arg, basestring): - raise ValueError("Path() arguments must be Path, str or unicode") + raise ValueError("%s() arguments must be Path, str or unicode" % typ.__name__) if len(args) == 1: return _base.__new__(typ, *args) else: - return Path(os.path.join(*args)) + return typ(os.path.join(*args)) # Iterating over a string yields its parts def __iter__(self): return iter(self.parts()) def __repr__(self): - return 'Path(%s)' % repr(_base(self)) + return '%s(%r)' % (self.__class__.__name__, _base(self)) def base(self): return _base(self) @@ -82,12 +82,12 @@ # Caution: this is not a join! def __add__(self, other): if isinstance(other, basestring): - return Path(_base(self) + other) + return self.__class__(_base(self) + other) return NotImplemented def __radd__(self, other): if isinstance(other, basestring): - return Path(other + _base(self)) + return self.__class__(other + _base(self)) return NotImplemented # The / joins paths @@ -98,13 +98,13 @@ # Alternative constructor. - @staticmethod - def cwd(): + @classmethod + def cwd(cls): """ Return the current working directory as a path object. """ if os.path.supports_unicode_filenames: - return Path(os.getcwdu()) + return cls(os.getcwdu()) else: - return Path(os.getcwd()) + return cls(os.getcwd()) # --- Operations which return strings @@ -113,7 +113,7 @@ os.path.basename, None, None, """ The name of this file or directory without the full path. - For example, path('/usr/local/lib/libpython.so').basename == 'libpython.so' + For example, Path('/usr/local/lib/libpython.so').basename == 'libpython.so' """) def _get_namebase(self): @@ -132,8 +132,8 @@ _get_namebase, None, None, """ The same as Path.basename, but with one file extension stripped off. - For example, path('/home/guido/python.tar.gz').basename == 'python.tar.gz', - but path('/home/guido/python.tar.gz').namebase == 'python.tar' + For example, Path('/home/guido/python.tar.gz').basename == 'python.tar.gz', + but Path('/home/guido/python.tar.gz').namebase == 'python.tar' """) ext = property( @@ -149,22 +149,22 @@ # --- Operations which return Path objects def abspath(self): - return Path(os.path.abspath(self)) + return self.__class__(os.path.abspath(self)) def normcase(self): - return Path(os.path.normcase(self)) + return self.__class__(os.path.normcase(self)) def normpath(self): - return Path(os.path.normpath(self)) + return self.__class__(os.path.normpath(self)) def realpath(self): - return Path(os.path.realpath(self)) + return self.__class__(os.path.realpath(self)) def expanduser(self): - return Path(os.path.expanduser(self)) + return self.__class__(os.path.expanduser(self)) def expandvars(self): - return Path(os.path.expandvars(self)) + return self.__class__(os.path.expandvars(self)) def expand(self): """ Clean up a filename by calling expandvars(), @@ -176,7 +176,7 @@ return self.expandvars().expanduser().normpath() def _get_directory(self): - return Path(os.path.dirname(self)) + return self.__class__(os.path.dirname(self)) directory = property( _get_directory, None, None, @@ -198,7 +198,7 @@ def splitpath(self): """ p.splitpath() -> Return (p.directory, p.basename). """ parent, child = os.path.split(self) - return Path(parent), child + return self.__class__(parent), child def splitdrive(self): """ p.splitdrive() -> Return (Path(p.drive), ). @@ -208,7 +208,7 @@ is simply (Path(''), p). This is always the case on Unix. """ drive, rel = os.path.splitdrive(self) - return Path(drive), rel + return self.__class__(drive), rel def splitext(self): """ p.splitext() -> Return (p.stripext(), p.ext). @@ -220,16 +220,16 @@ last path segment. """ filename, ext = os.path.splitext(self) - return Path(filename), ext + return self.__class__(filename), ext if hasattr(os.path, 'splitunc'): def splitunc(self): unc, rest = os.path.splitunc(self) - return Path(unc), rest + return self.__class__(unc), rest def _get_uncshare(self): unc, r = os.path.splitunc(self) - return Path(unc) + return self.__class__(unc) uncshare = property( _get_uncshare, None, None, @@ -241,7 +241,7 @@ character (os.sep) if needed. Returns a new path object. """ - return Path(os.path.join(self, *args)) + return self.__class__(os.path.join(self, *args)) joinpath = joinwith @@ -271,7 +271,7 @@ """ Return this path as a relative path, based from the current working directory. """ - return Path.cwd().relpathto(self) + return self.__class__.cwd().relpathto(self) def relpathto(self, dest): """ Return a relative path from self to dest. @@ -281,7 +281,7 @@ dest.abspath(). """ origin = self.abspath() - dest = Path(dest).abspath() + dest = self.__class__(dest).abspath() orig_list = origin.normcase().parts() # Don't normcase dest! We want to preserve the case. @@ -306,15 +306,15 @@ segments += dest_list[i:] if len(segments) == 0: # If they happen to be identical, use os.curdir. - return Path(os.curdir) + return self.__class__(os.curdir) else: - return Path(os.path.join(*segments)) + return self.__class__(os.path.join(*segments)) # --- Listing, searching, walking, and matching def listdir(self): - return [Path(p) for p in os.listdir(self)] + return [self.__class__(p) for p in os.listdir(self)] def children(self, pattern=None): """ D.children() -> List of items in this directory, @@ -422,7 +422,7 @@ For example, path('/users').glob('*/bin/*') returns a list of all the files users have in their bin directories. """ - return map(Path, glob.glob(self / pattern)) + return map(self.__class__, glob.glob(self / pattern)) # --- Reading or writing an entire file at once. @@ -799,7 +799,7 @@ The result may be an absolute or a relative path. """ - return Path(os.readlink(self)) + return self.__class__(os.readlink(self)) def readlinkabs(self): """ Return the path to which this symbolic link points. @@ -833,4 +833,7 @@ if hasattr(os, 'startfile'): def startfile(self): os.startfile(self) - + + if hasattr(os, 'chdir'): + def chdir(self): + os.chdir(self) From akuchling at users.sourceforge.net Tue Aug 2 19:13:24 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue, 02 Aug 2005 10:13:24 -0700 Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew25.tex, 1.14, 1.15 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21649 Modified Files: whatsnew25.tex Log Message: Add note Index: whatsnew25.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew25.tex,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- whatsnew25.tex 22 Jul 2005 18:39:19 -0000 1.14 +++ whatsnew25.tex 2 Aug 2005 17:13:21 -0000 1.15 @@ -100,6 +100,20 @@ %====================================================================== +\section{PEP 342: New Generator Features} + +XXX write this section + +\begin{seealso} + +\seepep{342}{Coroutines via Enhanced Generators}{PEP written by +Guido van Rossum and Phillip J. Eby; +implemented by Phillip J. Eby.} + +\end{seealso} + + +%====================================================================== \section{Other Language Changes} Here are all of the changes that Python 2.5 makes to the core Python From akuchling at users.sourceforge.net Tue Aug 2 19:20:38 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue, 02 Aug 2005 10:20:38 -0700 Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew25.tex, 1.15, 1.16 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23280 Modified Files: whatsnew25.tex Log Message: Add example Index: whatsnew25.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew25.tex,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- whatsnew25.tex 2 Aug 2005 17:13:21 -0000 1.15 +++ whatsnew25.tex 2 Aug 2005 17:20:36 -0000 1.16 @@ -60,9 +60,21 @@ server_log = functional.partial(log, subsystem='server') \end{verbatim} -Here's another example, from a program that uses PyGTk. +Here's another example, from a program that uses PyGTk. Here a +context-sensitive pop-up menu is being constructed dynamically. The +callback provided for the menu option is a partially applied version +of the \method{open_item()} method, where the first argument has been +provided. -% XXX add example from my GTk programming +\begin{verbatim} +... +class Application: + def open_item(self, path): + ... + def init (self): + open_func = functional.partial(self.open_item, item_path) + popup_menu.append( ("Open", open_func, 1) ) +\end{verbatim} \begin{seealso} From gregorykjohnson at users.sourceforge.net Tue Aug 2 21:18:56 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Tue, 02 Aug 2005 12:18:56 -0700 Subject: [Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.3, 1.4 test_mailbox.py, 1.3, 1.4 libmailbox.tex, 1.4, 1.5 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23886 Modified Files: mailbox.py test_mailbox.py libmailbox.tex Log Message: * Implement MMDF, refactoring much code from mbox * Improve locking for mbox and MMDF: * Use os.open() with O_EXCL for dot locking * Only lock while writing, as other mailbox manipulation programs do * Bring back flush() method in addition to close() * Add some mbox- and MMDF-specific tests Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- mailbox.py 2 Aug 2005 03:49:01 -0000 1.3 +++ mailbox.py 2 Aug 2005 19:18:53 -0000 1.4 @@ -166,8 +166,12 @@ if bad_key: raise KeyError, "No message with key(s)" + def flush(self): + """Write any pending changes to the disk.""" + raise NotImplementedError, "Method must be implemented by subclass" + def close(self): - """Close mailbox and write any pending changes to disk.""" + """Flush and close the mailbox.""" raise NotImplementedError, "Method must be implemented by subclass" def _dump_message(self, message, target): @@ -305,10 +309,14 @@ self._refresh() return len(self._toc) - def close(self): - """Close mailbox and write any pending changes to disk.""" + def flush(self): + """Write any pending changes to disk.""" return # Maildir changes are always written immediately. + def close(self): + """Flush and close the mailbox.""" + return + def list_folders(self): """Return a list of folder names.""" result = [] @@ -400,11 +408,11 @@ raise KeyError, "No message with key '%s'" % key -class mbox(Mailbox): - """A classic mbox mailbox.""" +class _mboxMMDF(Mailbox): + """An mbox or MMDF mailbox.""" def __init__(self, path, factory=None): - """Initialize an mbox instance.""" + """Initialize an mbox or MMDF mailbox.""" Mailbox.__init__(self, path, factory) try: f = file(self._path, 'r+') @@ -415,14 +423,11 @@ f = file(self._path, 'r') else: raise - try: - _lock_file(f) - except: - f.close() - raise self._file = f self._toc = None self._next_key = 0 + self._pending = False # No changes require rewriting the file. + self._mtime = os.fstat(self._file.fileno()).st_mtime def add(self, message): """Add message and return assigned key.""" @@ -434,24 +439,28 @@ def remove(self, key): """Remove the keyed message; raise KeyError if it doesn't exist.""" del self._toc[key] + self._pending = True def __setitem__(self, key, message): """Replace the keyed message; raise KeyError if it doesn't exist.""" self._lookup(key) start, stop = self._append_message(message) self._toc[key] = (start, stop) + self._pending = True def get_message(self, key): start, stop = self._lookup(key) + self._assert_mtime() self._file.seek(start) from_line = self._file.readline() - msg = mboxMessage(self._file.read(stop - self._file.tell())) + msg = self._message_factory(self._file.read(stop - self._file.tell())) msg.set_from(from_line[5:-1]) return msg def get_string(self, key, from_=False): """Return a string representation or raise a KeyError.""" start, stop = self._lookup(key) + self._assert_mtime() self._file.seek(start) if not from_: self._file.readline() @@ -460,6 +469,7 @@ def get_file(self, key, from_=False): """Return a file-like representation or raise a KeyError.""" start, stop = self._lookup(key) + self._assert_mtime() self._file.seek(start) if not from_: self._file.readline() @@ -481,60 +491,51 @@ self._lookup() return len(self._toc) - def close(self): - """Close mailbox and write any pending changes to disk.""" - self._lookup() - f = file(self._path + '.tmp', 'w') - try: - new_toc = {} - for key in sorted(self._toc.keys()): - start, stop = self._toc[key] - self._file.seek(start) - if f.tell() != 0: - f.write(os.linesep) - new_start = f.tell() - while True: - buffer = self._file.read(min(4096, - stop - self._file.tell())) - if buffer == '': - break - f.write(buffer) - new_toc[key] = (new_start, f.tell()) - finally: - f.close() - try: - os.rename(self._path + '.tmp', self._path) - except oserror, e: - if e.errno == errno.eexist: - # xxx: is this is the exception Windows raises? - os.remove(self._path) + def flush(self): + """Write any pending changes to disk.""" + if self._pending: + self._lookup() + dotlock_inode = _lock_file(self._file) + self._assert_mtime() + f = file(self._path + '.tmp', 'w') + try: + try: + new_toc = {} + for key in sorted(self._toc.keys()): + start, stop = self._toc[key] + self._file.seek(start) + self._pre_write_hook(f) + new_start = f.tell() + while True: + buffer = self._file.read( + min(4096, stop - self._file.tell())) + if buffer == '': + break + f.write(buffer) + new_toc[key] = (new_start, f.tell()) + self._post_write_hook(f) + finally: + f.close() + finally: + _unlock_file(self._file, dotlock_inode) + try: os.rename(self._path + '.tmp', self._path) - else: - raise - self._file.close() - if os.path.exists(self._path + '.lock'): - os.remove(self._path + '.lock') + except OSError, e: + if e.errno == errno.EEXIST: + # XXX: Is this the exception Windows raises? + os.remove(self._path) + os.rename(self._path + '.tmp', self._path) + else: + raise + self._file.flush() + self._set_mtime() + _unlock_file(self._file, dotlock_inode) + self._pending = False - def _generate_toc(self): - """Generate key-to-(start, stop) table of contents.""" - starts, stops = [], [] - self._file.seek(0) - prev_line = '' - while True: - pos = self._file.tell() - line = self._file.readline() - if line[:5] == 'From ': - starts.append(pos) - # The preceeding newline is part of the separator, e.g., - # "\nFrom .*\n", not part of the previous message. Ignore it. - if prev_line != '': - stops.append(pos - len(os.linesep)) - elif line == '': - stops.append(pos) - break - prev_line = line - self._toc = dict(enumerate(zip(starts, stops))) - self._next_key = len(self._toc) + def close(self): + """Flush and close the mailbox.""" + self.flush() + self._file.close() def _lookup(self, key=None): """Return (start, stop) for given key, or raise a KeyError.""" @@ -564,15 +565,113 @@ if from_line is None: from_line = 'From MAILER-DAEMON %s' % \ time.strftime('%a %b %d %H:%M:%S %Y', time.gmtime()) - self._file.seek(0, 2) - if self._file.tell() == 0: + dotlock_inode = _lock_file(self._file) + self._assert_mtime() + try: + self._file.seek(0, 2) + self._pre_write_hook(self._file) start = self._file.tell() self._file.write('%s%s' % (from_line, os.linesep)) - else: - start = self._file.tell() + 1 - self._file.write('%s%s%s' % (os.linesep, from_line, os.linesep)) - self._dump_message(message, self._file) - return (start, self._file.tell()) + self._dump_message(message, self._file) + stop = self._file.tell() + self._post_write_hook(self._file) + self._file.flush() + self._set_mtime() + finally: + _unlock_file(self._file, dotlock_inode) + return (start, stop) + + def _assert_mtime(self): + """Raise an exception if the file has been externally modified.""" + if self._mtime != os.fstat(self._file.fileno()).st_mtime: + raise Error, 'External modifications detected: use refresh(): ' \ + '%r vs %r' % (self._mtime, + os.fstat(self._file.fileno()).st_mtime) + + def _set_mtime(self): + """Store the current mtime.""" + self._mtime = os.fstat(self._file.fileno()).st_mtime + + + +class mbox(_mboxMMDF): + """A classic mbox mailbox.""" + + def __init__(self, path, factory=None): + """Initialize an mbox mailbox.""" + self._message_factory = mboxMessage + _mboxMMDF.__init__(self, path, factory) + + def _pre_write_hook(self, f): + """Called by close before writing each message.""" + if f.tell() != 0: + f.write(os.linesep) + + def _post_write_hook(self, f): + """Called by close after writing each message.""" + return + + def _generate_toc(self): + """Generate key-to-(start, stop) table of contents.""" + starts, stops = [], [] + self._assert_mtime() + self._file.seek(0) + prev_line = '' + while True: + pos = self._file.tell() + line = self._file.readline() + if line[:5] == 'From ': + starts.append(pos) + # The preceeding newline is part of the separator, e.g., + # "\nFrom .*\n", not part of the previous message. Ignore it. + if prev_line != '': + stops.append(pos - len(os.linesep)) + elif line == '': + stops.append(pos) + break + prev_line = line + self._toc = dict(enumerate(zip(starts, stops))) + self._next_key = len(self._toc) + + +class MMDF(_mboxMMDF): + """An MMDF mailbox.""" + + def __init__(self, path, factory=None): + """Initialize an MMDF mailbox.""" + self._message_factory = MMDFMessage + _mboxMMDF.__init__(self, path, factory) + + def _pre_write_hook(self, f): + """Called by close before writing each message.""" + f.write('\001\001\001\001\n') + + def _post_write_hook(self, f): + """Called by close after writing each message.""" + f.write('\n\001\001\001\001\n') + + def _generate_toc(self): + """Generate key-to-(start, stop) table of contents.""" + starts, stops = [], [] + self._assert_mtime() + self._file.seek(0) + while True: + line = self._file.readline() + if line[:4 + len(os.linesep)] == '\001\001\001\001' + os.linesep: + starts.append(self._file.tell()) + while True: + pos = self._file.tell() + line = self._file.readline() + if line == '\001\001\001\001' + os.linesep: + stops.append(pos - len(os.linesep)) + break + elif line == '': + stops.append(pos) + break + elif line == '': + break + self._toc = dict(enumerate(zip(starts, stops))) + self._next_key = len(self._toc) class Message(email.Message.Message): @@ -1059,20 +1158,20 @@ def _lock_file(f): - """Use various means to lock f (f.name should be absolute).""" + """Use various means to lock file f. Return dotlock inode or None.""" if 'fcntl' in globals(): try: fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError, e: if e.errno == errno.EAGAIN: - raise Error, 'Failed to acquire exclusive lock ' \ + raise Error, 'Exclusive lock cannot be acquired ' \ 'using lockf: %s' % f.name elif e.errno == errno.EBADF: try: fcntl.lockf(f, fcntl.LOCK_SH | fntl.LOCK_NB) except IOError, e: if e.errno == errno.EAGAIN: - raise Error, 'Failed to acquire shared lock ' \ + raise Error, 'Shared lock cannot be acquired ' \ 'using lockf: %s' % f.name else: raise @@ -1082,27 +1181,55 @@ fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError, e: if e.errno == errno.EWOULDBLOCK: - raise Error, 'Failed to aquire exclusive lock ' \ + raise Error, 'Exclusive lock cannot be acquired ' \ 'using flock: %s' % f.name else: raise tmp_name = f.name + '.%s.%s' % (socket.gethostname(), os.getpid()) try: - file(tmp_name, 'w').close() + dotlock = os.open(tmp_name, os.O_WRONLY | os.O_EXCL | os.O_CREAT, 0600) + dotlock_inode = os.fstat(dotlock).st_ino + os.close(dotlock) except IOError, e: if e.errno == errno.EACCESS: - pass + pass # Without write access, just skip dotlocking. + elif e.errno == errno.EEXIST: + raise Error, 'Failed to create unique file ' \ + 'for dot lock: %s' % tmp_name + else: + raise + try: + if os.path.exists(f.name + '.lock') and \ + time.time() - os.getmtime(f.name + '.lock') > 300: + try: + os.remove(f.name + '.lock') + except IOError, e: + if e.errno == errno.EACCESS: + raise Error, 'Stale dot lock cannot be removed: %s' \ + % f.name + '.lock' + else: + raise + if hasattr(os, 'link'): + os.link(tmp_name, f.name + '.lock') + os.unlink(tmp_name) + else: + os.rename(tmp_name, f.name + '.lock') + except OSError, e: + if e.errno == errno.EEXIST: + raise Error, 'Dot lock exists and cannot be acquired: %s' % \ + f.name + '.lock' else: raise else: - try: - if hasattr(os, 'link'): - os.link(tmp_name, f.name + '.lock') - os.unlink(tmp_name) - else: - os.rename(tmp_name, f.name + '.lock') - except OSError, e: - if e.errno == errno.EEXIST: - raise Error, 'Failed to acquire dot lock: %s' % f.name - else: - raise + return dotlock_inode + return None + + +def _unlock_file(f, dotlock_inode): + """Unlock file f by various means, given a dotlock_inode (or None).""" + if 'fcntl' in globals(): + fcntl.lockf(f, fcntl.LOCK_UN) + fcntl.flock(f, fcntl.LOCK_UN) + if dotlock_inode is not None and \ + dotlock_inode == os.stat(f.name + '.lock').st_ino: + os.remove(f.name + '.lock') Index: test_mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- test_mailbox.py 2 Aug 2005 03:49:01 -0000 1.3 +++ test_mailbox.py 2 Aug 2005 19:18:53 -0000 1.4 @@ -11,6 +11,10 @@ import unittest import mailbox import glob +try: + import fcntl +except ImportError: + pass class TestBase(unittest.TestCase): @@ -370,13 +374,20 @@ self.assert_(self._box.get_string(key2) == self._template % "changed 2") + def test_flush(self): + # Write changes to disk + self._test_flush_or_close(self._box.flush) + def test_close(self): # Close mailbox and flush changes to disk + self._test_flush_or_close(self._box.close) + + def _test_flush_or_close(self, method): contents = [self._template % i for i in xrange(3)] self._box.add(contents[0]) self._box.add(contents[1]) self._box.add(contents[2]) - self._box.close() + method() self._box = self._factory(self._path) keys = self._box.keys() self.assert_(len(keys) == 3) @@ -602,15 +613,62 @@ self.assert_(self._box._toc == {}) -class TestMbox(TestMailbox): - - _factory = lambda self, path, factory=None: mailbox.mbox(path, factory) +class _TestMboxMMDF(TestMailbox): def tearDown(self): self._delete_recursively(self._path) for lock_remnant in glob.glob(self._path + '.*'): os.remove(lock_remnant) + def test_add_from_string(self): + # Add a string starting with 'From ' to the mailbox + key = self._box.add('From foo at bar blah\nFrom: foo\n\n0') + self.assert_(self._box[key].get_from() == 'foo at bar blah') + self.assert_(self._box[key].get_payload() == '0') + + def test_add_mbox_or_mmdf_message(self): + # Add an mboxMessage or MMDFMessage + for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage): + msg = class_('From foo at bar blah\nFrom: foo\n\n0') + key = self._box.add(msg) + + def test_open_close_open(self): + # Open and inspect previously-created mailbox + values = [self._template % i for i in xrange(3)] + for value in values: + self._box.add(value) + self._box.close() + mtime = os.path.getmtime(self._path) + self._box = self._factory(self._path) + self.assert_(len(self._box) == 3) + for key in self._box.iterkeys(): + self.assert_(self._box.get_string(key) in values) + self._box.close() + self.assert_(mtime == os.path.getmtime(self._path)) + + def test_add_and_close(self): + # Verifying that closing a mailbox doesn't change added items + self._box.add(_sample_message) + for i in xrange(3): + self._box.add(self._template % i) + self._box.add(_sample_message) + self._box._file.flush() + self._box._file.seek(0) + contents = self._box._file.read() + self._box.close() + self.assert_(contents == file(self._path, 'r').read()) + self._box = self._factory(self._path) + + +class TestMbox(_TestMboxMMDF): + + _factory = lambda self, path, factory=None: mailbox.mbox(path, factory) + + +class TestMMDF(_TestMboxMMDF): + + _factory = lambda self, path, factory=None: mailbox.MMDF(path, factory) + class TestMessage(TestBase): @@ -1382,7 +1440,7 @@ def test_main(): - tests = (TestMaildir, TestMbox, TestMessage, TestMaildirMessage, + tests = (TestMaildir, TestMbox, TestMMDF, TestMessage, TestMaildirMessage, TestMboxMessage, TestMHMessage, TestBabylMessage, TestMMDFMessage, TestMessageConversion, TestProxyFile, TestPartialFile) test_support.run_unittest(*tests) Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- libmailbox.tex 2 Aug 2005 03:49:01 -0000 1.4 +++ libmailbox.tex 2 Aug 2005 19:18:54 -0000 1.5 @@ -242,10 +242,14 @@ are not supported.} \end{methoddesc} +\begin{methoddesc}{flush}{} +Write any pending changes to the filesystem. For some \class{Mailbox} +subclasses, changes are written immediately and this method does nothing. +\end{methoddesc} + \begin{methoddesc}{close}{} -Close the mailbox and write any pending changes to the filesystem. For some -\class{Mailbox} subclasses, changes are written immediately even without -calling this method. +Flush the mailbox and close any open files. For some \class{Mailbox} +subclasses, this method does nothing. \end{methoddesc} @@ -316,9 +320,14 @@ these methods to manipulate the same mailbox simultaneously.} \end{methoddesc} +\begin{methoddesc}{flush}{} +All changes to Maildir mailboxes are immediately applied, so this method does +nothing. +\end{methoddesc} + \begin{methoddesc}{close}{} -All changes to Maildir mailboxes are immediately applied even without calling -this method. +\class{Maildir} instances do not keep any open files, so this method does +nothing. \end{methoddesc} \begin{methoddesc}{get_file}{key} @@ -454,9 +463,13 @@ XXX \end{methoddesc} -\begin{methoddesc}{close}{} -All changes to MH mailboxes are immediately applied even without calling this -method. +\begin{methoddesc}{flush}{} +All changes to MH mailboxes are immediately applied, so this method does +nothing. +\end{methoddesc} + +\begin{methoddesc}{flush}{} +\class{MH} instances do not keep any open files, so this method does nothing. \end{methoddesc} \begin{classdesc}{MH}{path\optional{, factory}} From gregorykjohnson at users.sourceforge.net Tue Aug 2 23:46:16 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Tue, 02 Aug 2005 14:46:16 -0700 Subject: [Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.4, 1.5 test_mailbox.py, 1.4, 1.5 libmailbox.tex, 1.5, 1.6 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29669 Modified Files: mailbox.py test_mailbox.py libmailbox.tex Log Message: * Implement MH (except sequences) * Use mailbox.Error instead of IOError for non-empty folder removal Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- mailbox.py 2 Aug 2005 19:18:53 -0000 1.4 +++ mailbox.py 2 Aug 2005 21:46:13 -0000 1.5 @@ -341,12 +341,12 @@ for entry in os.listdir(os.path.join(path, 'new')) + \ os.listdir(os.path.join(path, 'cur')): if len(entry) < 1 or entry[0] != '.': - raise IOError, "Folder '%s' contains message" % name + raise Error, "Folder '%s' contains message" % name for entry in os.listdir(path): if entry != 'new' and entry != 'cur' and entry != 'tmp' and \ os.path.isdir(os.path.join(path, entry)): - raise IOError, "Folder '%s' contains subdirectory '%s'" % \ - (name, entry) + raise Error, "Folder '%s' contains subdirectory '%s'" % \ + (name, entry) for root, dirs, files in os.walk(path, topdown=False): for entry in files: os.remove(os.path.join(root, entry)) @@ -674,6 +674,176 @@ self._next_key = len(self._toc) +class MH(Mailbox): + """An MH mailbox.""" + + def __init__(self, path, factory=None): + """Initialize an MH instance.""" + Mailbox.__init__(self, path, factory) + if not os.path.exists(self._path): + os.mkdir(self._path, 0700) + + def add(self, message): + """Add message and return assigned key.""" + keys = self.keys() + if len(keys) == 0: + new_key = 1 + else: + new_key = max(keys) + 1 + fd = os.open(os.path.join(self._path, str(new_key)), + os.O_CREAT | os.O_EXCL | os.O_WRONLY) + f = os.fdopen(fd, 'w') + try: + try: + dotlock_inode = _lock_file(f) + try: + self._dump_message(message, f) + # XXX: update sequences based on message + f.flush() + finally: + _unlock_file(f, dotlock_inode) + finally: + f.close() + except: + os.remove(os.path.join(self._path, str(new_key))) + raise + return new_key + + def remove(self, key): + """Remove the keyed message; raise KeyError if it doesn't exist.""" + try: + os.remove(os.path.join(self._path, str(key))) + except OSError, e: + if e.errno == errno.ENOENT: + raise KeyError, "No message with key '%s'" % key + else: + raise + + def __setitem__(self, key, message): + """Replace the keyed message; raise KeyError if it doesn't exist.""" + try: + f_r = file(os.path.join(self._path, str(key)), 'r+') + except IOError, e: + if e.errno == errno.ENOENT: + raise KeyError, "No message with key '%s'" % key + else: + raise + try: + dotlock_inode = _lock_file(f_r) + try: + f_w = file(os.path.join(self._path, str(key)), 'w') + try: + self._dump_message(message, f_w) + finally: + f_w.close() + finally: + _unlock_file(f_r, dotlock_inode) + finally: + f_r.close() + + def get_message(self, key): + """Return a Message representation or raise a KeyError.""" + try: + f = file(os.path.join(self._path, str(key)), 'r') + except IOError, e: + if e.errno == errno.ENOENT: + raise KeyError, "No message with key '%s'" % key + else: + raise + try: + msg = MHMessage(f) + finally: + f.close() + # XXX: set sequences on msg + return msg + + def get_string(self, key): + """Return a string representation or raise a KeyError.""" + try: + f = file(os.path.join(self._path, str(key)), 'r') + except IOError, e: + if e.errno == errno.ENOENT: + raise KeyError, "No message with key '%s'" % key + else: + raise + try: + return f.read() + finally: + f.close() + + def get_file(self, key): + """Return a file-like representation or raise a KeyError.""" + try: + f = file(os.path.join(self._path, str(key)), 'r') + except IOError, e: + if e.errno == errno.ENOENT: + raise KeyError, "No message with key '%s'" % key + else: + raise + return _ProxyFile(f) + + def iterkeys(self): + """Return an iterator over keys.""" + for x in sorted(int(x) for x in os.listdir(self._path) if x.isdigit()): + yield int(x) + + def has_key(self, key): + """Return True if the keyed message exists, False otherwise.""" + return os.path.exists(os.path.join(self._path, str(key))) + + def __len__(self): + """Return a count of messages in the mailbox.""" + return len(list(self.iterkeys())) + + def flush(self): + """Write any pending changes to the disk.""" + return + + def close(self): + """Flush and close the mailbox.""" + return + + def list_folders(self): + """Return a list of folders in this mailbox.""" + result = [] + for entry in os.listdir(self._path): + if os.path.isdir(os.path.join(self._path, entry)): + result.append(entry) + return result + + def open_folder(self, name): + """Return an MH instance for folder name, creating it if necessary.""" + return MH(os.path.join(self._path, name)) + + def remove_folder(self, name): + """Delete folder name.""" + path = os.path.join(self._path, name) + entries = os.listdir(path) + if entries == ['.mh_sequences']: + os.remove(os.path.join(path, '.mh_sequences')) + elif entries == []: + pass + else: + raise Error, "Folder '%s' is not empty" % self._path + os.rmdir(path) + + def list_sequences(self, name): + """Return a list of the names of sequences defined in the mailbox.""" + raise NotImplementedError, 'Method not yet implemented' + + def get_sequence(self, name): + """Return a list of the keys in sequence 'name'.""" + raise NotImplementedError, 'Method not yet implemented' + + def set_sequence(self, name): + """Set the keys in sequence 'name'.""" + raise NotImplementedError, 'Method not yet implemented' + + def pack(self): + """Eliminate numbering gaps in message names. Invalidates keys.""" + raise NotImplementedError, 'Method not yet implemented' + + class Message(email.Message.Message): """Message with mailbox-format-specific properties.""" Index: test_mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- test_mailbox.py 2 Aug 2005 19:18:53 -0000 1.4 +++ test_mailbox.py 2 Aug 2005 21:46:13 -0000 1.5 @@ -670,6 +670,11 @@ _factory = lambda self, path, factory=None: mailbox.MMDF(path, factory) +class TestMH(TestMailbox): + + _factory = lambda self, path, factory=None: mailbox.MH(path, factory) + + class TestMessage(TestBase): _factory = mailbox.Message # Overridden by subclasses to reuse tests @@ -1440,9 +1445,10 @@ def test_main(): - tests = (TestMaildir, TestMbox, TestMMDF, TestMessage, TestMaildirMessage, - TestMboxMessage, TestMHMessage, TestBabylMessage, TestMMDFMessage, - TestMessageConversion, TestProxyFile, TestPartialFile) + tests = (TestMaildir, TestMbox, TestMMDF, TestMH, TestMessage, + TestMaildirMessage, TestMboxMessage, TestMHMessage, + TestBabylMessage, TestMMDFMessage, TestMessageConversion, + TestProxyFile, TestPartialFile) test_support.run_unittest(*tests) Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- libmailbox.tex 2 Aug 2005 19:18:54 -0000 1.5 +++ libmailbox.tex 2 Aug 2005 21:46:13 -0000 1.6 @@ -291,8 +291,8 @@ \begin{methoddesc}{remove_folder}{name} Delete the folder whose name is \var{name}. If the folder contains any -messages, an \exception{IOError} exception will be raised and the folder will -not be deleted. +messages, a \exception{mailbox.Error} exception will be raised and the folder +will not be deleted. \end{methoddesc} \begin{methoddesc}{clean}{} @@ -404,13 +404,18 @@ \dfn{folders}) in addition to messages. Folders may be nested indefinitely. MH mailboxes support \dfn{sequences}, which are named lists used to logically -group messages without moving them to sub-folders. Some mail reading programs +group messages without moving them to sub-folders. Sequences are defined in a +file called \file{.mh_sequences} in each folder. Some mail reading programs (although not the standard \program{mh} and \program{nmh} implementations) use sequences to the same end as flags are used in other formats: unread messages are added to the "unseen" sequence, replied-to messages are added to the "replied" sequence, and important messages are added upon request to the "flagged" sequence. +\class{MH} manipulates MH mailboxes, but it does not attempt to emulate +\program{mh}. In particular, it does not access or modify \file{context} or +\file{.mh_profile} files. + \class{MH} instances have all of the methods of \class{Mailbox} in addition to the following: @@ -426,8 +431,8 @@ \begin{methoddesc}{remove_folder}{name} Delete the folder whose name is \var{name}. If the folder contains any -messages, an \exception{IOError} exception will be raised and the folder will -not be deleted. +messages, a \exception{mailbox.Error} exception will be raised and the folder +will not be deleted. \end{methoddesc} \begin{methoddesc}{list_sequences}{} @@ -468,14 +473,14 @@ nothing. \end{methoddesc} -\begin{methoddesc}{flush}{} +\begin{methoddesc}{close}{} \class{MH} instances do not keep any open files, so this method does nothing. \end{methoddesc} \begin{classdesc}{MH}{path\optional{, factory}} A subclass of \class{Mailbox} for mailboxes in MH format. Parameters \var{path} -and \var{factory} has the same meaning as with the module-level \method{open()} -function. +and \var{factory} have the same meaning as with the module-level +\method{open()} function. \end{classdesc} \class{MH} instances have all of the methods of \class{Mailbox} in addition to @@ -500,7 +505,7 @@ \begin{classdesc}{Babyl}{path\optional{, factory}} A subclass of \class{Mailbox} for mailboxes in Babyl format. Parameters -\var{path} and \var{factory} has the same meaning as with the module-level +\var{path} and \var{factory} have the same meaning as with the module-level \method{open()} function. \end{classdesc} @@ -531,7 +536,7 @@ \begin{classdesc}{MMDF}{path\optional{, factory}} A subclass of \class{Mailbox} for mailboxes in MMDF format. Parameters -\var{path} and \var{factory} has the same meaning as with the module-level +\var{path} and \var{factory} have the same meaning as with the module-level \method{open()} function. \end{classdesc} From birkenfeld at users.sourceforge.net Wed Aug 3 09:17:36 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 03 Aug 2005 00:17:36 -0700 Subject: [Python-checkins] python/dist/src/Doc/lib libfuncs.tex, 1.185, 1.186 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24435/Doc/lib Modified Files: libfuncs.tex Log Message: bug [ 1250306 ] incorrect description of range function Index: libfuncs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libfuncs.tex,v retrieving revision 1.185 retrieving revision 1.186 diff -u -d -r1.185 -r1.186 --- libfuncs.tex 22 Jul 2005 18:39:19 -0000 1.185 +++ libfuncs.tex 3 Aug 2005 07:17:33 -0000 1.186 @@ -775,7 +775,7 @@ \var{start} + 2 * \var{step}, \ldots]}. If \var{step} is positive, the last element is the largest \code{\var{start} + \var{i} * \var{step}} less than \var{stop}; if \var{step} is negative, the last - element is the largest \code{\var{start} + \var{i} * \var{step}} + element is the smallest \code{\var{start} + \var{i} * \var{step}} greater than \var{stop}. \var{step} must not be zero (or else \exception{ValueError} is raised). Example: From birkenfeld at users.sourceforge.net Wed Aug 3 09:18:06 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 03 Aug 2005 00:18:06 -0700 Subject: [Python-checkins] python/dist/src/Doc/lib libfuncs.tex, 1.175.2.5, 1.175.2.6 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24581/Doc/lib Modified Files: Tag: release24-maint libfuncs.tex Log Message: backport bug [ 1250306 ] incorrect description of range function Index: libfuncs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libfuncs.tex,v retrieving revision 1.175.2.5 retrieving revision 1.175.2.6 diff -u -d -r1.175.2.5 -r1.175.2.6 --- libfuncs.tex 22 Jul 2005 18:40:02 -0000 1.175.2.5 +++ libfuncs.tex 3 Aug 2005 07:18:04 -0000 1.175.2.6 @@ -737,7 +737,7 @@ \var{start} + 2 * \var{step}, \ldots]}. If \var{step} is positive, the last element is the largest \code{\var{start} + \var{i} * \var{step}} less than \var{stop}; if \var{step} is negative, the last - element is the largest \code{\var{start} + \var{i} * \var{step}} + element is the smallest \code{\var{start} + \var{i} * \var{step}} greater than \var{stop}. \var{step} must not be zero (or else \exception{ValueError} is raised). Example: From birkenfeld at users.sourceforge.net Wed Aug 3 09:30:13 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 03 Aug 2005 00:30:13 -0700 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1328,1.1329 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26243/Misc Modified Files: NEWS Log Message: patch [ 1105730 ] Faster commonprefix in macpath, ntpath, etc. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1328 retrieving revision 1.1329 diff -u -d -r1.1328 -r1.1329 --- NEWS 2 Aug 2005 10:28:04 -0000 1.1328 +++ NEWS 3 Aug 2005 07:30:10 -0000 1.1329 @@ -178,6 +178,9 @@ Library ------- +- Patch #1105730: Apply the new implementation of commonprefix in posixpath + to ntpath, macpath, os2emxpath and riscospath. + - Fix a problem in Tkinter introduced by SF patch #869468: delete bogus __hasattr__ and __delattr__ methods on class Tk that were breaking Tkdnd. From birkenfeld at users.sourceforge.net Wed Aug 3 09:30:14 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 03 Aug 2005 00:30:14 -0700 Subject: [Python-checkins] python/dist/src/Lib/plat-riscos riscospath.py, 1.11, 1.12 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/plat-riscos In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26243/Lib/plat-riscos Modified Files: riscospath.py Log Message: patch [ 1105730 ] Faster commonprefix in macpath, ntpath, etc. Index: riscospath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/plat-riscos/riscospath.py,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- riscospath.py 30 Aug 2004 10:19:55 -0000 1.11 +++ riscospath.py 3 Aug 2005 07:30:12 -0000 1.12 @@ -168,23 +168,16 @@ return split(p)[0] -def commonprefix(ps): - """ - Return the longest prefix of all list elements. Purely string-based; does not - separate any path parts. Why am I in os.path? - """ - if len(ps)==0: - return '' - prefix= ps[0] - for p in ps[1:]: - prefix= prefix[:len(p)] - for i in range(len(prefix)): - if prefix[i] <> p[i]: - prefix= prefix[:i] - if i==0: - return '' - break - return prefix +def commonprefix(m): + "Given a list of pathnames, returns the longest common leading component" + if not m: return '' + s1 = min(m) + s2 = max(m) + n = min(len(s1), len(s2)) + for i in xrange(n): + if s1[i] != s2[i]: + return s1[:i] + return s1[:n] ## File access functions. Why are we in os.path? From birkenfeld at users.sourceforge.net Wed Aug 3 09:30:14 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 03 Aug 2005 00:30:14 -0700 Subject: [Python-checkins] python/dist/src/Lib macpath.py, 1.50, 1.51 ntpath.py, 1.61, 1.62 os2emxpath.py, 1.13, 1.14 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26243/Lib Modified Files: macpath.py ntpath.py os2emxpath.py Log Message: patch [ 1105730 ] Faster commonprefix in macpath, ntpath, etc. Index: macpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/macpath.py,v retrieving revision 1.50 retrieving revision 1.51 diff -u -d -r1.50 -r1.51 --- macpath.py 30 Aug 2004 13:39:50 -0000 1.50 +++ macpath.py 3 Aug 2005 07:30:11 -0000 1.51 @@ -175,14 +175,14 @@ def commonprefix(m): "Given a list of pathnames, returns the longest common leading component" if not m: return '' - prefix = m[0] - for item in m: - for i in range(len(prefix)): - if prefix[:i+1] != item[:i+1]: - prefix = prefix[:i] - if i == 0: return '' - break - return prefix + s1 = min(m) + s2 = max(m) + n = min(len(s1), len(s2)) + for i in xrange(n): + if s1[i] != s2[i]: + return s1[:i] + return s1[:n] + def expandvars(path): """Dummy to retain interface-compatibility with other operating systems.""" Index: ntpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/ntpath.py,v retrieving revision 1.61 retrieving revision 1.62 diff -u -d -r1.61 -r1.62 --- ntpath.py 30 Aug 2004 10:19:55 -0000 1.61 +++ ntpath.py 3 Aug 2005 07:30:12 -0000 1.62 @@ -212,14 +212,13 @@ def commonprefix(m): "Given a list of pathnames, returns the longest common leading component" if not m: return '' - prefix = m[0] - for item in m: - for i in range(len(prefix)): - if prefix[:i+1] != item[:i+1]: - prefix = prefix[:i] - if i == 0: return '' - break - return prefix + s1 = min(m) + s2 = max(m) + n = min(len(s1), len(s2)) + for i in xrange(n): + if s1[i] != s2[i]: + return s1[:i] + return s1[:n] # Get size, mtime, atime of files. Index: os2emxpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/os2emxpath.py,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- os2emxpath.py 30 Aug 2004 10:19:55 -0000 1.13 +++ os2emxpath.py 3 Aug 2005 07:30:12 -0000 1.14 @@ -173,14 +173,13 @@ def commonprefix(m): "Given a list of pathnames, returns the longest common leading component" if not m: return '' - prefix = m[0] - for item in m: - for i in range(len(prefix)): - if prefix[:i+1] != item[:i+1]: - prefix = prefix[:i] - if i == 0: return '' - break - return prefix + s1 = min(m) + s2 = max(m) + n = min(len(s1), len(s2)) + for i in xrange(n): + if s1[i] != s2[i]: + return s1[:i] + return s1[:n] # Get size, mtime, atime of files. From pje at users.sourceforge.net Wed Aug 3 15:18:53 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Wed, 03 Aug 2005 06:18:53 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.55, 1.56 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21843 Modified Files: pkg_resources.py Log Message: Fix a problem with zip paths reported by Ashley Walsh. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.55 retrieving revision 1.56 diff -u -d -r1.55 -r1.56 --- pkg_resources.py 31 Jul 2005 16:31:17 -0000 1.55 +++ pkg_resources.py 3 Aug 2005 13:18:50 -0000 1.56 @@ -1122,7 +1122,7 @@ for path in self.zipinfo: parts = path.split(os.sep) while parts: - parent = '/'.join(parts[:-1]) + parent = os.sep.join(parts[:-1]) if parent in ind: ind[parent].append(parts[-1]) break From doerwalter at users.sourceforge.net Wed Aug 3 19:09:31 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Wed, 03 Aug 2005 10:09:31 -0700 Subject: [Python-checkins] python/dist/src/Lib/test test_textwrap.py, 1.28, 1.29 test_sys.py, 1.10, 1.11 test_isinstance.py, 1.9, 1.10 test_builtin.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-serv18683/Lib/test Modified Files: test_textwrap.py test_sys.py test_isinstance.py test_builtin.py Log Message: Disable a few other tests, that can't work if Python is compiled without Unicode support. Index: test_textwrap.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_textwrap.py,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- test_textwrap.py 5 Mar 2005 02:53:17 -0000 1.28 +++ test_textwrap.py 3 Aug 2005 17:09:02 -0000 1.29 @@ -328,17 +328,18 @@ self.check_wrap(text, 30, [" This is a sentence with", "leading whitespace."]) - def test_unicode(self): - # *Very* simple test of wrapping Unicode strings. I'm sure - # there's more to it than this, but let's at least make - # sure textwrap doesn't crash on Unicode input! - text = u"Hello there, how are you today?" - self.check_wrap(text, 50, [u"Hello there, how are you today?"]) - self.check_wrap(text, 20, [u"Hello there, how are", "you today?"]) - olines = self.wrapper.wrap(text) - assert isinstance(olines, list) and isinstance(olines[0], unicode) - otext = self.wrapper.fill(text) - assert isinstance(otext, unicode) + if test_support.have_unicode: + def test_unicode(self): + # *Very* simple test of wrapping Unicode strings. I'm sure + # there's more to it than this, but let's at least make + # sure textwrap doesn't crash on Unicode input! + text = u"Hello there, how are you today?" + self.check_wrap(text, 50, [u"Hello there, how are you today?"]) + self.check_wrap(text, 20, [u"Hello there, how are", "you today?"]) + olines = self.wrapper.wrap(text) + assert isinstance(olines, list) and isinstance(olines[0], unicode) + otext = self.wrapper.fill(text) + assert isinstance(otext, unicode) def test_split(self): # Ensure that the standard _split() method works as advertised Index: test_sys.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_sys.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- test_sys.py 15 Feb 2005 21:50:12 -0000 1.10 +++ test_sys.py 3 Aug 2005 17:09:03 -0000 1.11 @@ -247,7 +247,8 @@ self.assert_(isinstance(sys.executable, basestring)) self.assert_(isinstance(sys.hexversion, int)) self.assert_(isinstance(sys.maxint, int)) - self.assert_(isinstance(sys.maxunicode, int)) + if test.test_support.have_unicode: + self.assert_(isinstance(sys.maxunicode, int)) self.assert_(isinstance(sys.platform, basestring)) self.assert_(isinstance(sys.prefix, basestring)) self.assert_(isinstance(sys.version, basestring)) Index: test_isinstance.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_isinstance.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- test_isinstance.py 8 Jul 2004 04:22:19 -0000 1.9 +++ test_isinstance.py 3 Aug 2005 17:09:04 -0000 1.10 @@ -243,7 +243,8 @@ self.assertEqual(True, issubclass(NewSuper, (NewChild, (NewSuper,)))) self.assertEqual(True, issubclass(int, (long, (float, int)))) - self.assertEqual(True, issubclass(str, (unicode, (Child, NewChild, basestring)))) + if test_support.have_unicode: + self.assertEqual(True, issubclass(str, (unicode, (Child, NewChild, basestring)))) def test_subclass_recursion_limit(self): # make sure that issubclass raises RuntimeError before the C stack is Index: test_builtin.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_builtin.py,v retrieving revision 1.41 retrieving revision 1.42 diff -u -d -r1.41 -r1.42 --- test_builtin.py 26 Apr 2005 03:45:26 -0000 1.41 +++ test_builtin.py 3 Aug 2005 17:09:04 -0000 1.42 @@ -582,14 +582,16 @@ self.assertRaises(TypeError, getattr, sys, 1) self.assertRaises(TypeError, getattr, sys, 1, "foo") self.assertRaises(TypeError, getattr) - self.assertRaises(UnicodeError, getattr, sys, unichr(sys.maxunicode)) + if have_unicode: + self.assertRaises(UnicodeError, getattr, sys, unichr(sys.maxunicode)) def test_hasattr(self): import sys self.assert_(hasattr(sys, 'stdout')) self.assertRaises(TypeError, hasattr, sys, 1) self.assertRaises(TypeError, hasattr) - self.assertRaises(UnicodeError, hasattr, sys, unichr(sys.maxunicode)) + if have_unicode: + self.assertRaises(UnicodeError, hasattr, sys, unichr(sys.maxunicode)) def test_hash(self): hash(None) @@ -1101,7 +1103,8 @@ if have_unicode: self.assertEqual(ord(unichr(sys.maxunicode)), sys.maxunicode) self.assertRaises(TypeError, ord, 42) - self.assertRaises(TypeError, ord, unicode("12")) + if have_unicode: + self.assertRaises(TypeError, ord, unicode("12")) def test_pow(self): self.assertEqual(pow(0,0), 1) @@ -1494,11 +1497,17 @@ def test_inputtypes(self): s = 'abracadabra' - for T in [unicode, list, tuple]: + types = [list, tuple] + if have_unicode: + types.insert(0, unicode) + for T in types: self.assertEqual(sorted(s), sorted(T(s))) s = ''.join(dict.fromkeys(s).keys()) # unique letters only - for T in [unicode, set, frozenset, list, tuple, dict.fromkeys]: + types = [set, frozenset, list, tuple, dict.fromkeys] + if have_unicode: + types.insert(0, unicode) + for T in types: self.assertEqual(sorted(s), sorted(T(s))) def test_baddecorator(self): From tim_one at users.sourceforge.net Wed Aug 3 20:33:09 2005 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Wed, 03 Aug 2005 11:33:09 -0700 Subject: [Python-checkins] python/dist/src/Python compile.c,2.351,2.352 Message-ID: Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6288/Python Modified Files: compile.c Log Message: com_yield_expr(): Squash new compiler wng about unreferenced local. Index: compile.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/compile.c,v retrieving revision 2.351 retrieving revision 2.352 diff -u -d -r2.351 -r2.352 --- compile.c 2 Aug 2005 00:46:46 -0000 2.351 +++ compile.c 3 Aug 2005 18:33:05 -0000 2.352 @@ -3744,7 +3744,6 @@ static void com_yield_expr(struct compiling *c, node *n) { - int i; REQ(n, yield_expr); /* 'yield' testlist */ if (!c->c_infunction) { com_error(c, PyExc_SyntaxError, "'yield' outside function"); From gregorykjohnson at users.sourceforge.net Thu Aug 4 01:50:45 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Wed, 03 Aug 2005 16:50:45 -0700 Subject: [Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.5, 1.6 libmailbox.tex, 1.6, 1.7 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23486 Modified Files: mailbox.py libmailbox.tex Log Message: * Implement sequences and pack() for MH: * Simplify interface. Use only get_sequences() and set_sequences(). * Overhaul locking (and carefulness of other processes in general): * Fix various places where locking was not properly conceived (especially when overwriting or replacing files). * Introduce _create_carefully() to avoid clobbering new files. * Use .lock.time.pid.hostname suffix for pre-dotlocks, like pine. * Don't steal stale dotlocks, even though interactive MUAs do. * Carefully release locks in case of exceptions (also avoids deadlocks if some locks are successfully acquired but not others). Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- mailbox.py 2 Aug 2005 21:46:13 -0000 1.5 +++ mailbox.py 3 Aug 2005 23:50:43 -0000 1.6 @@ -190,6 +190,8 @@ else: raise TypeError, "Invalid message type" + + class Maildir(Mailbox): """A qmail-style Maildir mailbox.""" @@ -434,6 +436,7 @@ self._lookup() self._toc[self._next_key] = self._append_message(message) self._next_key += 1 + self._pending = True return self._next_key - 1 def remove(self, key): @@ -493,12 +496,21 @@ def flush(self): """Write any pending changes to disk.""" - if self._pending: - self._lookup() - dotlock_inode = _lock_file(self._file) + if not self._pending: + return + self._lookup() + _lock_file(self._file, self._path) + try: + os.rename(self._path, self._path + '~') + _lock_file(self._file, self._path + '~', system=False) + except: + _unlock_file(self._file, self._path) + raise + try: self._assert_mtime() - f = file(self._path + '.tmp', 'w') + f = _create_carefully(self._path) try: + _lock_file(f, self._path, dot=False) try: new_toc = {} for key in sorted(self._toc.keys()): @@ -508,29 +520,25 @@ new_start = f.tell() while True: buffer = self._file.read( - min(4096, stop - self._file.tell())) + min(4096, stop - self._file.tell())) if buffer == '': break f.write(buffer) new_toc[key] = (new_start, f.tell()) self._post_write_hook(f) finally: - f.close() - finally: - _unlock_file(self._file, dotlock_inode) - try: - os.rename(self._path + '.tmp', self._path) - except OSError, e: - if e.errno == errno.EEXIST: - # XXX: Is this the exception Windows raises? - os.remove(self._path) - os.rename(self._path + '.tmp', self._path) - else: - raise - self._file.flush() - self._set_mtime() - _unlock_file(self._file, dotlock_inode) - self._pending = False + _unlock_file(f, self._path) + except: + f.close() + raise + finally: + _unlock_file(self._file, self._path + '~') + self._file.close() + self._toc = new_toc + self._file = f + self._set_mtime() + os.remove(self._path + '~') + self._pending = False def close(self): """Flush and close the mailbox.""" @@ -544,7 +552,7 @@ if key is not None: try: return self._toc[key] - except IndexError: + except KeyError: raise KeyError, "No message with key '%s'" % key def _append_message(self, message): @@ -565,9 +573,9 @@ if from_line is None: from_line = 'From MAILER-DAEMON %s' % \ time.strftime('%a %b %d %H:%M:%S %Y', time.gmtime()) - dotlock_inode = _lock_file(self._file) - self._assert_mtime() + _lock_file(self._file, self._path) try: + self._assert_mtime() self._file.seek(0, 2) self._pre_write_hook(self._file) start = self._file.tell() @@ -578,15 +586,13 @@ self._file.flush() self._set_mtime() finally: - _unlock_file(self._file, dotlock_inode) + _unlock_file(self._file, self._path) return (start, stop) def _assert_mtime(self): """Raise an exception if the file has been externally modified.""" if self._mtime != os.fstat(self._file.fileno()).st_mtime: - raise Error, 'External modifications detected: use refresh(): ' \ - '%r vs %r' % (self._mtime, - os.fstat(self._file.fileno()).st_mtime) + raise Error, 'External modifications detected: use refresh()' def _set_mtime(self): """Store the current mtime.""" @@ -682,6 +688,8 @@ Mailbox.__init__(self, path, factory) if not os.path.exists(self._path): os.mkdir(self._path, 0700) + os.mknod(os.path.join(self._path, '.mh_sequences'), + 0600 | stat.S_IFREG) def add(self, message): """Add message and return assigned key.""" @@ -690,23 +698,18 @@ new_key = 1 else: new_key = max(keys) + 1 - fd = os.open(os.path.join(self._path, str(new_key)), - os.O_CREAT | os.O_EXCL | os.O_WRONLY) - f = os.fdopen(fd, 'w') + new_path = os.path.join(self._path, str(new_key)) + f = _create_carefully(new_path) try: + _lock_file(f, f.name) try: - dotlock_inode = _lock_file(f) - try: - self._dump_message(message, f) - # XXX: update sequences based on message - f.flush() - finally: - _unlock_file(f, dotlock_inode) + self._dump_message(message, f) + if isinstance(message, MHMessage): + self._dump_sequences(message, new_key) finally: - f.close() - except: - os.remove(os.path.join(self._path, str(new_key))) - raise + _unlock_file(f, f.name) + finally: + f.close() return new_key def remove(self, key): @@ -729,15 +732,17 @@ else: raise try: - dotlock_inode = _lock_file(f_r) + _lock_file(f_r, f_r.name) try: f_w = file(os.path.join(self._path, str(key)), 'w') try: self._dump_message(message, f_w) + if isinstance(message, MHMessage): + self._dump_sequences(message, key) finally: f_w.close() finally: - _unlock_file(f_r, dotlock_inode) + _unlock_file(f_r, f_r.name) finally: f_r.close() @@ -754,7 +759,9 @@ msg = MHMessage(f) finally: f.close() - # XXX: set sequences on msg + for name, key_list in self.get_sequences(): + if key in key_list: + msg.join_sequence(name) return msg def get_string(self, key): @@ -784,8 +791,8 @@ def iterkeys(self): """Return an iterator over keys.""" - for x in sorted(int(x) for x in os.listdir(self._path) if x.isdigit()): - yield int(x) + return iter(sorted(int(entry) for entry in os.listdir(self._path) + if entry.isdigit())) def has_key(self, key): """Return True if the keyed message exists, False otherwise.""" @@ -827,21 +834,106 @@ raise Error, "Folder '%s' is not empty" % self._path os.rmdir(path) - def list_sequences(self, name): - """Return a list of the names of sequences defined in the mailbox.""" - raise NotImplementedError, 'Method not yet implemented' - - def get_sequence(self, name): - """Return a list of the keys in sequence 'name'.""" - raise NotImplementedError, 'Method not yet implemented' + def get_sequences(self): + """Return a name-to-key-list dictionary to define each sequence.""" + results = {} + f = file(os.path.join(self._path, '.mh_sequences'), 'r') + try: + all_keys = set(self.keys()) + for line in f: + try: + name, contents = line.split(':') + keys = set() + for spec in contents.split(): + if spec.isdigit(): + keys.add(int(spec)) + else: + start, stop = (int(x) for x in spec.split('-')) + keys.update(range(start, stop + 1)) + results[name] = [key for key in sorted(keys) \ + if key in all_keys] + except ValueError: + raise Error, "Invalid sequence specification: '%s'" % \ + line.rstrip() + finally: + f.close() + return results - def set_sequence(self, name): - """Set the keys in sequence 'name'.""" - raise NotImplementedError, 'Method not yet implemented' + def set_sequences(self, sequences): + """Set sequences using the given name-to-key-list dictionary.""" + f = file(os.path.join(self._path, '.mh_sequences'), 'r+') + try: + _lock_file(f, f.name) + try: + # .truncate() is not portable, so re-open to truncate. + f_w = file(os.path.join(self._path, '.mh_sequences'), 'w') + try: + for name, keys in sequences.iteritems(): + if len(keys) == 0: + continue + f_w.write('%s:' % name) + prev = None + completing = False + for key in sorted(set(keys)): + if key - 1 == prev: + if not completing: + completing = True + f_w.write('-') + elif completing: + completing = False + f_w.write('%s %s' % (prev, key)) + else: + f_w.write(' %s' % key) + prev = key + if completing: + f_w.write('%s%s' % (prev, os.linesep)) + else: + f_w.write(os.linesep) + finally: + f_w.close() + finally: + _unlock_file(f, f.name) + finally: + f.close() def pack(self): - """Eliminate numbering gaps in message names. Invalidates keys.""" - raise NotImplementedError, 'Method not yet implemented' + """Re-name messages to eliminate numbering gaps. Invalidates keys.""" + sequences = self.get_sequences() + prev = 0 + changes = [] + for key in self.iterkeys(): + if key - 1 != prev: + changes.append((key, prev + 1)) + if hasattr(os, 'link'): + os.link(os.path.join(self._path, str(key)), + os.path.join(self._path, str(prev + 1))) + os.unlink(os.path.join(self._path, str(key))) + else: + os.rename(os.path.join(self._path, str(key)), + os.path.join(self._path, str(prev + 1))) + prev += 1 + if len(changes) == 0: + return + keys = self.keys() + for name, key_list in sequences.items(): + for old, new in changes: + if old in key_list: + key_list[key_list.index(old)] = new + self.set_sequences(sequences) + + def _dump_sequences(self, message, key): + """Inspect a new MHMessage and update sequences appropriately.""" + pending_sequences = message.list_sequences() + all_sequences = self.get_sequences() + for name, key_list in all_sequences.iteritems(): + if name in pending_sequences: + key_list.append(key) + elif key in key_list: + del key_list[key_list.index(key)] + for sequence in pending_sequences: + if sequence not in all_sequences: + all_sequences[sequence] = [new_key] + self.set_sequences(all_sequences) class Message(email.Message.Message): @@ -1327,79 +1419,71 @@ """Raised for module-specific errors.""" -def _lock_file(f): - """Use various means to lock file f. Return dotlock inode or None.""" - if 'fcntl' in globals(): - try: - fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB) - except IOError, e: - if e.errno == errno.EAGAIN: - raise Error, 'Exclusive lock cannot be acquired ' \ - 'using lockf: %s' % f.name - elif e.errno == errno.EBADF: - try: - fcntl.lockf(f, fcntl.LOCK_SH | fntl.LOCK_NB) - except IOError, e: - if e.errno == errno.EAGAIN: - raise Error, 'Shared lock cannot be acquired ' \ - 'using lockf: %s' % f.name - else: - raise - else: - raise - try: - fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) - except IOError, e: - if e.errno == errno.EWOULDBLOCK: - raise Error, 'Exclusive lock cannot be acquired ' \ - 'using flock: %s' % f.name - else: - raise - tmp_name = f.name + '.%s.%s' % (socket.gethostname(), os.getpid()) - try: - dotlock = os.open(tmp_name, os.O_WRONLY | os.O_EXCL | os.O_CREAT, 0600) - dotlock_inode = os.fstat(dotlock).st_ino - os.close(dotlock) - except IOError, e: - if e.errno == errno.EACCESS: - pass # Without write access, just skip dotlocking. - elif e.errno == errno.EEXIST: - raise Error, 'Failed to create unique file ' \ - 'for dot lock: %s' % tmp_name - else: - raise +def _lock_file(f, path, system=True, dot=True): + """Lock file f using lockf, flock, and dot locking.""" + lockf_done = flock_done = dotlock_done = False try: - if os.path.exists(f.name + '.lock') and \ - time.time() - os.getmtime(f.name + '.lock') > 300: + if system and 'fcntl' in globals(): try: - os.remove(f.name + '.lock') + fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB) + lockf_done = True + except IOError, e: + if e.errno == errno.EAGAIN: + raise Error, "lockf: lock unavailable: %s" % path + else: + raise + try: + fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) + flock_done = True + except IOError, e: + if e.errno == errno.EWOULDBLOCK: + raise Error, "flock: lock unavailable: %s" % path + else: + raise + if dot: + tmp = '%s.lock.%s.%s.%s' % (path, int(time.time()), + socket.gethostname(), os.getpid()) + try: + os.close(os.open(tmp, os.O_WRONLY | os.O_EXCL | os.O_CREAT, + 0600)) except IOError, e: if e.errno == errno.EACCESS: - raise Error, 'Stale dot lock cannot be removed: %s' \ - % f.name + '.lock' + return # Without write access, just skip dotlocking. else: raise - if hasattr(os, 'link'): - os.link(tmp_name, f.name + '.lock') - os.unlink(tmp_name) - else: - os.rename(tmp_name, f.name + '.lock') - except OSError, e: - if e.errno == errno.EEXIST: - raise Error, 'Dot lock exists and cannot be acquired: %s' % \ - f.name + '.lock' - else: - raise - else: - return dotlock_inode - return None - + try: + if hasattr(os, 'link'): + os.link(tmp, path + '.lock') + os.unlink(tmp) + else: + os.rename(tmp, path + '.lock') + dotlock_done = True + except OSError, e: + if e.errno == errno.EEXIST: + try: + os.remove(tmp) + except: + pass + raise Error, 'dot lock unavailable: %s' % path + else: + raise + except: + if lockf_done: + fcntl.lockf(f, fcntl.LOCK_UN) + if flock_done: + fcntl.flock(f, fcntl.LOCK_UN) + if dotlock_done: + os.remove(path + '.lock') + raise -def _unlock_file(f, dotlock_inode): - """Unlock file f by various means, given a dotlock_inode (or None).""" - if 'fcntl' in globals(): +def _unlock_file(f, path, system=True, dot=True): + """Unlock file f using lockf, flock, and dot locking.""" + if system and 'fcntl' in globals(): fcntl.lockf(f, fcntl.LOCK_UN) fcntl.flock(f, fcntl.LOCK_UN) - if dotlock_inode is not None and \ - dotlock_inode == os.stat(f.name + '.lock').st_ino: - os.remove(f.name + '.lock') + if dot and os.path.exists(path + '.lock'): + os.remove(path + '.lock') + +def _create_carefully(path): + """Create a file if it doesn't exist and open for reading and writing.""" + return os.fdopen(os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR), 'r+') Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- libmailbox.tex 2 Aug 2005 21:46:13 -0000 1.6 +++ libmailbox.tex 3 Aug 2005 23:50:43 -0000 1.7 @@ -435,24 +435,21 @@ will not be deleted. \end{methoddesc} -\begin{methoddesc}{list_sequences}{} -Return a list of the names of sequences defined in the mailbox. If there are no -sequences, the empty list is returned. -\end{methoddesc} - -\begin{methoddesc}{get_sequence}{name} -Return a list of keys in sequence \var{name}. +\begin{methoddesc}{get_sequences}{} +Return a dictionary of sequence names mapped to key lists. If there are no +sequences, the empty dictionary is returned. \end{methoddesc} -\begin{methoddesc}{set_sequence}{name, value} -Set to \var{value} the list of keys in sequence \var{name}. The sequence will -be created if it does not exist. If \var{value} is the empty list, sequence -\var{name} will be removed. +\begin{methoddesc}{set_sequences}{sequences} +Re-define the sequences that exist in the mailbox based upon \var{sequences}, a +dictionary of names mapped to key lists like returned by +\method{get_sequences()}. \end{methoddesc} \begin{methoddesc}{pack}{} Renames messages in the mailbox as necessary to eliminate gaps in numbering. -Already-issued keys are invalidated by this operation. +Entries in the sequences list are updated correspondingly. Already-issued keys +are invalidated by this operation. \end{methoddesc} Some \class{Mailbox} methods implemented by \class{MH} deserve special remarks: From bcannon at users.sourceforge.net Thu Aug 4 05:19:00 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed, 03 Aug 2005 20:19:00 -0700 Subject: [Python-checkins] python/nondist/peps pep-0348.txt,NONE,1.1 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5746 Added Files: pep-0348.txt Log Message: Initial checkin; essentially rev. 3; previous 2 sent to python-dev in July and August 2005, respectively. --- NEW FILE: pep-0348.txt --- PEP: 348 Title: Exception Reorganization for Python 3.0 Version: $Revision: 1.1 $ Last-Modified: $Date: 2005/08/04 03:18:57 $ Author: Brett Cannon Status: Draft Type: Standards Track Content-Type: text/x-rst Created: 28-Jul-2005 Post-History: 03-Aug-2005 Abstract ======== Python, as of version 2.4, has 38 exceptions (including warnings) in the built-in namespace in a rather shallow hierarchy. This list of classes has grown over the years without a chance to learn from mistakes and cleaning up the hierarchy. This PEP proposes doing a reorganization for Python 3.0 when backwards-compatibility is not an issue. Along with this reorganization, adding a requirement that all objects passed to a ``raise`` statement must inherit from a specific superclass is proposed. Lastly, bare ``except`` clauses will catch only exceptions inheriting from StandardError. Rationale ========= Exceptions are a critical part of Python. While exceptions are traditionally used to signal errors in a program, they have also grown to be used for flow control for things such as iterators. There importance is great. But the organization of the exception hierarchy is suboptimal to serve the multiple uses of exceptions. Mostly for backwards-compatibility reasons, the hierarchy has stayed very flat and old exceptions who usefulness have not been proven have been left in. Making exceptions more hierarchical would help facilitate exception handling by making catching exceptions using inheritance much more logical. This should also help lead to less errors from being too broad in what exceptions are caught in an ``except`` clause. A required superclass for all exceptions is also being proposed [Summary2004-08-01]_. By requiring any object that is used in a ``raise`` statement to inherit from a specific superclass, certain attributes (such as those laid out in PEP 344 [PEP344]_) can be guaranteed to exist. This also will lead to the planned removal of string exceptions. Lastly, bare ``except`` clauses are to catch only exceptions that inherit from Exception [python-dev3]_. While currently used to catch all exceptions, that use is rather far reaching and typically not desired. Catching only exceptions inheriting from StandardError allows exceptions that should not be caught unless explicitly desired to continue to propagate up the execution stack. Philosophy of Reorganization ============================ There are several goals in this reorganization that defined the philosophy used to guide the work. One goal was to prune out unneeded exceptions. Extraneous exceptions should not be left in since it just serves to clutter the built-in namespace. Unneeded exceptions also dilute the importance of other exceptions by splitting uses between several exceptions when all uses should have been under a single exception. Another goal was to introduce any exceptions that were deemed needed to fill any holes in the hierarchy. Most new exceptions were done to flesh out the inheritance hierarchy to make it easier to catch a category of exceptions with a simpler ``except`` clause. Changing inheritance to make it more reasonable was a goal. As stated above, having proper inheritance allows for more accurate ``except`` statements when catching exceptions based on the inheritance tree. Lastly, any renaming to make an exception's use more obvious from its name was done. Having to look up what an exception is meant to be used for because the name does not proper reflect its usage is annoying and slows down debugging. Having a proper name also makes debugging easier on new programmers. But for simplicity of existing user's and for transitioning to Python 3.0, only exceptions whose names were fairly out of alignment with their stated purpose have been renamed. New Hierarchy ============= .. note:: exceptions flagged as "stricter inheritance" means that the class no longer inherits from a certain class; "broader inheritance" means a class has been added to the exception's inheritance tree :: BaseException +-- CriticalError (new) +-- KeyboardInterrupt (stricter inheritance) +-- MemoryError (stricter inheritance) +-- SystemError (stricter inheritance) +-- ControlFlowException (new) +-- GeneratorExit (defined in PEP 342 [PEP342]_) +-- StopIteration (broader inheritance) +-- SystemExit (broader inheritance) +-- Exception +-- ArithmeticError +-- DivideByZeroError +-- FloatingPointError +-- OverflowError +-- AssertionError +-- AttributeError +-- EnvironmentError +-- IOError +-- EOFError (broader inheritance) +-- OSError +-- ImportError +-- LookupError +-- IndexError +-- KeyError +-- NamespaceError (rename of NameError) +-- UnboundFreeError (new) +-- UnboundGlobalError (new) +-- UnboundLocalError +-- NotImplementedError (stricter inheritance) +-- SyntaxError +-- IndentationError +-- TabError +-- TypeError +-- UserError (rename of RuntimeError) +-- UnicodeError +-- UnicodeDecodeError +-- UnicodeEncodeError +-- UnicodeTranslateError +-- ValueError +-- Warning (broader inheritance, including subclasses) +-- AnyDeprecationWarning (new; broader inheritance for subclasses) +-- PendingDeprecationWarning +-- DeprecationWarning +-- FutureWarning +-- SyntaxWarning +-- SemanticsWarning (rename of RuntimeWarning) +-- UserWarning +-- WeakReferenceError (rename of ReferenceError) Differences Compared to Python 2.4 ================================== Changes to exceptions from Python 2.4 can take shape in three forms: removal, renaming, or change in the inheritance tree. There are also new exceptions introduced in the proposed hierarchy. In terms of new exceptions, almost all are to flesh out the inheritance tree. Those that are leaf classes are to alleaviate overloading the use of another exception. Inheritance change can be broader or more restrictive. The broader inheritance typically occurred to allow for a more reasonable superclass to group related exceptions together. Stricter inheritance happened when the pre-existing inheritance was deemed incorrect and needed correction. New Exceptions -------------- CriticalError ''''''''''''' The superclass for exceptions for which a severe error has occurred that one would not want to recover from. The name is meant to reflect that these exceptions are raised asynchronously by the interpreter when a critical event has occured that one would most likely want the interpreter to halt over. ControlFlowException '''''''''''''''''''' This exception exists as a superclass for all exceptions that directly deal with control flow. Inheriting from Exception instead of StandardError prevents them from being caught accidently when one wants to catch errors. The name, by not mentioning "Error", does not lead to one to confuse the subclasses as errors. UnboundGlobalError '''''''''''''''''' Raised when a global variable was not found. UnboundFreeError '''''''''''''''' Raised when a free variable is not found. AnyDeprecationWarning ''''''''''''''''''''' A common superclass for all deprecation-related exceptions. While having DeprecationWarning inherit from PendingDeprecationWarning was suggested because a DeprecationWarning can be viewed as a PendingDeprecationWarning that is happening now, the logic was not agreed upon by a majority. But since the exceptions are related, creating a common superclass is warranted. Removed Exceptions ------------------ WindowsError '''''''''''' Too OS-specific to be kept in the built-in exception hierarchy. Renamed Exceptions ------------------ RuntimeError '''''''''''' Renamed UserError. Meant for use as a generic exception to be used when one does not want to create a new exception class but do not want to raise an exception that might be caught based on inheritance, RuntimeError is poorly named. It's name in Python 2.4 seems to suggest an error that occurred at runtime, possibly an error in the VM. Renaming the exception to UserError more clearly states the purpose for the exception as quick-and-dirty error exception for the user to use. The name also keeps it in line with UserWarning. If a user wants an exception that is not to be used as an error, raising Exception directly should be sufficient as StandardError, as UserError inherits from, is only used for errors. ReferenceError '''''''''''''' Renamed WeakReferenceError. ReferenceError was added to the built-in exception hierarchy in Python 2.2 [exceptions-stdlib]_. Taken directly from the ``weakref`` module, its name comes directly from its original name when it resided in the module. Unfortunately its name does not suggest its connection to weak references and thus deserves a renaming. NameError ''''''''' Renamed NamespaceError. While NameError suggests its common use, it is not entirely apparent. Making it more of a superclass for namespace-related exceptions warrants a renaming to make it abundantly clear its use. Plus the documentation of the exception module[exceptions-stdlib]_ states that it is actually meant for global names and not for just any exception. RuntimeWarning '''''''''''''' Renamed SemanticsWarning. RuntimeWarning is to represent semantic changes coming in the future. But while saying that affects "runtime" is true, flat-out stating it is a semantic change is much clearer, eliminating any possible association of "runtime" with the virtual machine specifically. Changed Inheritance ------------------- KeyboardInterrupt, MemoryError, and SystemError ''''''''''''''''''''''''''''''''''''''''''''''' Inherit from CriticalError instead of StandardError. The three above-mentioned exceptions are not standard errors by any means. They are raised asynchronously by the interpreter when something specific has occurred. Thus they warrant not inheriting from StandardError but from an entirely separate exception that will not be caught by a bare ``except`` clause. NotImplementedError ''''''''''''''''''' Inherits from StandardError instead of RuntimeError (renamed UserError). Originally inheriting from RuntimeError, NotImplementedError does not have any direct relation to the exception meant for use in user code as a quick-and-dirty exception. Thus it now directly inherits from StandardError. EOFError '''''''' Subclasses IOError. Since an EOF comes from I/O it only makes sense that it be considered an I/O error. Warning ''''''' Inherits from StandardError instead of Exception. In order for Warning to be caught by bare ``except`` clauses, it needs to inherit from StandardError as specified in this PEP. Required Superclass for ``raise`` ================================= By requiring all objects passed to a ``raise`` statement inherit from a specific superclass, one is guaranteed that all exceptions will have certain attributes. If PEP 342 [PEP344]_ is accepted, the attributes outlined there will be guaranteed to be on all exceptions raised. This should help facilitate debugging by making the querying of information from exceptions much easier. The proposed hierarchy has Exception as the required class that one must inherit from. Implementation -------------- Enforcement is straight-forward. Modifying ``RAISE_VARARGS`` to do an inheritance check first before raising an exception should be enough. For the C API, all functions that set an exception will have the same inheritance check. Bare ``except`` Clauses Catching StandardError Only =================================================== While Python does have its "explicit is better than implicit" tenant, it is not necessary if a default behavior is reasonable. In the case of a bare ``except`` clause, changing the behavior makes it quite reasonable to have around. In Python 2.4, a bare ``except`` clause will catch all exceptions. Typically, though, this is not what is truly desired. More often than not one wants to catch all error exceptions that do not signify a bad state of the interpreter. In the new exception hierarchy this is embodied by StandardError. Thus bare ``except`` clauses will catch only exceptions inheriting from StandardError. Implementation -------------- In the compiler, when a bare ``except`` clause is reached, the code for ``except StandardError`` will be emitted. Transition Plan =============== Exception Hierarchy Changes --------------------------- New Exceptions '''''''''''''' New exceptions can simply be added to the built-in namespace. Any pre-existing objects with the same name will mask the new exceptions, preserving backwards-compatibility. Renamed Exceptions '''''''''''''''''' Renamed exceptions will directly subclass the new names. When the old exceptions are instantiated (which occurs when an exception is caught, either by a ``try`` statement or by propagating to the top of the execution stack), a PendingDeprecationWarning will be raised. This should properly preserve backwards-compatibility as old usage won't change and the new names can be used to also catch exceptions using the old name. The warning of the deprecation is also kept simple. New Inheritance for Old Exceptions '''''''''''''''''''''''''''''''''' Using multiple inheritance to our advantage, exceptions whose inheritance is now more resrictive can be made backwards-compatible. By inheriting from both the new superclasses as well as the original superclasses existing ``except`` clauses will continue to work as before while allowing the new inheritance to be used for new clauses. A PendingDeprecationWarning will be raised based on whether the bytecode ``COMPARE_OP(10)`` results in an exception being caught that would not have under the new hierarchy. This will require hard-coding in the implementation of the bytecode. Removed Exceptions '''''''''''''''''' Exceptions scheduled for removal will be transitioned much like the old names of renamed exceptions. Upon instantiation a PendingDeprecationWarning will be raised stating the the exception is due to be removed by Python 3.0 . Required Superclass for ``raise`` --------------------------------- A SemanticsWarning will be raised when an object is passed to ``raise`` that does not have the proper inheritance. Removal of Bare ``except`` Clauses ---------------------------------- A SemanticsWarning will be raised for all bare ``except`` clauses. Rejected Ideas ============== Threads on python-dev discussing this PEP can be found at [python-dev-thread1]_, [python-dev-thread2]_ KeyboardInterrupt inheriting from ControlFlowException ------------------------------------------------------ KeyboardInterrupt has been a contentious point within this hierarchy. Some view the exception as more control flow being caused by the user. But with its asynchronous cause thanks to the user being able to trigger the exception at any point in code it has a more proper place inheriting from CriticalException. It also keeps the name of the exception from being "CriticalError". Renaming Exception to Raisable, StandardError to Exception ---------------------------------------------------------- While the naming makes sense and emphasizes the required superclass as what must be inherited from for raising an object, the naming is not required. Keeping the existing names minimizes code change to use the new names. It has been argued that changing StandardError to Exception might actually reflect how users use Exception more accurately, that has not been considered a strong enough argument. It entails guessing as to what users think in general and does technically lead to a change that is not backwards-compatible. DeprecationWarning Inheriting From PendingDeprecationWarning ------------------------------------------------------------ Originally proposed because a DeprecationWarning can be viewed as a PendingDeprecationWarning that is being removed in the next version. But enough people thought the inheritance could logically work the other way the idea was dropped. AttributeError Inheriting From TypeError or NameError ----------------------------------------------------- Viewing attributes as part of the interface of a type caused the idea of inheriting from TypeError. But that partially defeats the thinking of duck typing and thus was dropped. Inheriting from NameError was suggested because objects can be viewed as having their own namespace that the attributes lived in and when they are not found it is a namespace failure. This was also dropped as a possibility since not everyone shared this view. Removal of EnvironmentError --------------------------- Originally proposed based on the idea that EnvironmentError was an unneeded distinction, the BDFL overruled this idea [python-dev4]_. Introduction of MacError and UnixError -------------------------------------- Proposed to add symmetry to WindowsError, the BDFL said they won't be used enough [python-dev4]_. The idea of then removing WindowsError was proposed and accepted as reasonable, thus completely negating the idea of adding these exceptions. SystemError Subclassing SystemExit ---------------------------------- Proposed because a SystemError is meant to lead to a system exit, the idea was removed since CriticalException signifies this better. ControlFlowException Under StandardError ---------------------------------------- It has been suggested that ControlFlowException inherit from StandardError. This idea has been rejected based on the thinking that control flow exceptions are typically not desired to be caught in a generic fashion as StandardError will usually be used. Removal of Bare ``except`` Clauses ---------------------------------- The suggestion has been made to remove bare ``except`` clauses in the name of "explicit is better than implicit". But Guido has said this is too weak of an argument since other things in Python has default behavior [python-dev3]_. Open Issues =========== Remove ControlFlowException? ---------------------------- It has been suggested that ControlFlowException is not needed. Since the desire to catch any control flow exception will be atypical, the suggestion is to just remove the exception and let the exceptions that inherited from it inherit directly from Exception. This still preserves the seperation from StandardError which is one of the driving factors behind the introduction of the exception. Acknowledgements ================ Thanks to Robert Brewer, Josiah Carlson, Nick Coghlan, Timothy Delaney, Jack Diedrich, Fred L. Drake, Jr., Philip J. Eby, Greg Ewing, James Y. Knight, MA Lemburg, Guido van Rossum, Stephen J. Turnbull and everyone else I missed for participating in the discussion. References ========== .. [PEP342] PEP 342 (Coroutines via Enhanced Generators) (http://www.python.org/peps/pep-0342.html) .. [PEP344] PEP 344 (Exception Chaining and Embedded Tracebacks) (http://www.python.org/peps/pep-0344.html) .. [exceptionsmodules] 'exceptions' module (http://docs.python.org/lib/module-exceptions.html) .. [Summary2004-08-01] python-dev Summary (An exception is an exception, unless it doesn't inherit from Exception) (http://www.python.org/dev/summary/2004-08-01_2004-08-15.html#an-exception-is-an-exception-unless-it-doesn-t-inherit-from-exception) .. [Summary2004-09-01] python-dev Summary (Cleaning the Exception House) (http://www.python.org/dev/summary/2004-09-01_2004-09-15.html#cleaning-the-exception-house) .. [python-dev1] python-dev email (Exception hierarchy) (http://mail.python.org/pipermail/python-dev/2004-August/047908.html) .. [python-dev2] python-dev email (Dangerous exceptions) (http://mail.python.org/pipermail/python-dev/2004-September/048681.html) .. [python-dev3] python-dev email (PEP, take 2: Exception Reorganization for Python 3.0) (http://mail.python.org/pipermail/python-dev/2005-August/055116.html) .. [exceptions-stdlib] exceptions module (http://www.python.org/doc/2.4.1/lib/module-exceptions.html) .. [python-dev-thread1] python-dev thread (Pre-PEP: Exception Reorganization for Python 3.0) (http://mail.python.org/pipermail/python-dev/2005-July/055020.html , http://mail.python.org/pipermail/python-dev/2005-August/055065.html) .. [python-dev-thread2] python-dev thread (PEP, take 2: Exception Reorganization for Python 3.0) (http://mail.python.org/pipermail/python-dev/2005-August/055103.html) .. [python-dev4] python-dev email (Pre-PEP: Exception Reorganization for Python 3.0) (http://mail.python.org/pipermail/python-dev/2005-July/055019.html) Copyright ========= This document has been placed in the public domain. From bcannon at users.sourceforge.net Thu Aug 4 05:33:06 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed, 03 Aug 2005 20:33:06 -0700 Subject: [Python-checkins] python/nondist/peps pep-0348.txt,1.1,1.2 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9052 Modified Files: pep-0348.txt Log Message: Finish moving to BaseException/Exception naming. Also leave in StandardError so as to provide a base Error exception that inherits from Exception. Also allows Warning to inherit from Exception without being put at the same level as any *Error exceptions. Index: pep-0348.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0348.txt,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- pep-0348.txt 4 Aug 2005 03:18:57 -0000 1.1 +++ pep-0348.txt 4 Aug 2005 03:33:03 -0000 1.2 @@ -19,7 +19,7 @@ Along with this reorganization, adding a requirement that all objects passed to a ``raise`` statement must inherit from a specific superclass is proposed. Lastly, bare ``except`` clauses will catch only exceptions inheriting from -StandardError. +Exception. Rationale @@ -43,7 +43,7 @@ Exception [python-dev3]_. While currently used to catch all exceptions, that use is rather far reaching and typically not desired. -Catching only exceptions inheriting from StandardError allows exceptions that +Catching only exceptions inheriting from Exception allows exceptions that should not be caught unless explicitly desired to continue to propagate up the execution stack. @@ -66,6 +66,8 @@ Having to look up what an exception is meant to be used for because the name does not proper reflect its usage is annoying and slows down debugging. Having a proper name also makes debugging easier on new programmers. But for simplicity of existing user's and for transitioning to Python 3.0, only exceptions whose names were fairly out of alignment with their stated purpose have been renamed. +It was also made sure the exceptions dealing with errors had the "Error" +suffix. New Hierarchy ============= @@ -86,36 +88,37 @@ +-- StopIteration (broader inheritance) +-- SystemExit (broader inheritance) +-- Exception - +-- ArithmeticError - +-- DivideByZeroError - +-- FloatingPointError - +-- OverflowError - +-- AssertionError - +-- AttributeError - +-- EnvironmentError - +-- IOError - +-- EOFError (broader inheritance) - +-- OSError - +-- ImportError - +-- LookupError - +-- IndexError - +-- KeyError - +-- NamespaceError (rename of NameError) - +-- UnboundFreeError (new) - +-- UnboundGlobalError (new) - +-- UnboundLocalError - +-- NotImplementedError (stricter inheritance) - +-- SyntaxError - +-- IndentationError - +-- TabError - +-- TypeError - +-- UserError (rename of RuntimeError) - +-- UnicodeError - +-- UnicodeDecodeError - +-- UnicodeEncodeError - +-- UnicodeTranslateError - +-- ValueError - +-- Warning (broader inheritance, including subclasses) + +-- StandardError + +-- ArithmeticError + +-- DivideByZeroError + +-- FloatingPointError + +-- OverflowError + +-- AssertionError + +-- AttributeError + +-- EnvironmentError + +-- IOError + +-- EOFError (broader inheritance) + +-- OSError + +-- ImportError + +-- LookupError + +-- IndexError + +-- KeyError + +-- NamespaceError (rename of NameError) + +-- UnboundFreeError (new) + +-- UnboundGlobalError (new) + +-- UnboundLocalError + +-- NotImplementedError (stricter inheritance) + +-- SyntaxError + +-- IndentationError + +-- TabError + +-- TypeError + +-- UserError (rename of RuntimeError) + +-- UnicodeError + +-- UnicodeDecodeError + +-- UnicodeEncodeError + +-- UnicodeTranslateError + +-- ValueError + +-- Warning +-- AnyDeprecationWarning (new; broader inheritance for subclasses) +-- PendingDeprecationWarning +-- DeprecationWarning @@ -144,6 +147,12 @@ New Exceptions -------------- +BaseException +''''''''''''' + +The superclass that all exceptions must inherit from. + + CriticalError ''''''''''''' @@ -159,7 +168,7 @@ This exception exists as a superclass for all exceptions that directly deal with control flow. -Inheriting from Exception instead of StandardError prevents them from being caught accidently when one wants to catch errors. +Inheriting from BaseException instead of Exception prevents them from being caught accidently when one wants to catch errors. The name, by not mentioning "Error", does not lead to one to confuse the subclasses as errors. @@ -214,7 +223,7 @@ The name also keeps it in line with UserWarning. If a user wants an exception that is not to be used as an error, raising -Exception directly should be sufficient as StandardError, as UserError inherits +BaseException directly should be sufficient as Exception, as UserError inherits from, is only used for errors. @@ -255,11 +264,11 @@ KeyboardInterrupt, MemoryError, and SystemError ''''''''''''''''''''''''''''''''''''''''''''''' -Inherit from CriticalError instead of StandardError. +Inherit from CriticalError instead of Exception. The three above-mentioned exceptions are not standard errors by any means. They are raised asynchronously by the interpreter when something specific has -occurred. Thus they warrant not inheriting from StandardError but from an +occurred. Thus they warrant not inheriting from Exception but from an entirely separate exception that will not be caught by a bare ``except`` clause. @@ -267,11 +276,11 @@ NotImplementedError ''''''''''''''''''' -Inherits from StandardError instead of RuntimeError (renamed UserError). +Inherits from Exception instead of RuntimeError (renamed UserError). Originally inheriting from RuntimeError, NotImplementedError does not have any direct relation to the exception meant for use in user code as a -quick-and-dirty exception. Thus it now directly inherits from StandardError. +quick-and-dirty exception. Thus it now directly inherits from Exception. EOFError @@ -282,15 +291,6 @@ Since an EOF comes from I/O it only makes sense that it be considered an I/O error. -Warning -''''''' - -Inherits from StandardError instead of Exception. - -In order for Warning to be caught by bare ``except`` clauses, it needs to -inherit from StandardError as specified in this PEP. - - Required Superclass for ``raise`` ================================= @@ -298,7 +298,7 @@ If PEP 342 [PEP344]_ is accepted, the attributes outlined there will be guaranteed to be on all exceptions raised. This should help facilitate debugging by making the querying of information from exceptions much easier. -The proposed hierarchy has Exception as the required class that one must inherit from. +The proposed hierarchy has BaseException as the required class that one must inherit from. Implementation @@ -310,8 +310,8 @@ exception will have the same inheritance check. -Bare ``except`` Clauses Catching StandardError Only -=================================================== +Bare ``except`` Clauses Catching Exception Only +=============================================== While Python does have its "explicit is better than implicit" tenant, it is not necessary if a default behavior is reasonable. In the case of a bare @@ -322,15 +322,15 @@ though, this is not what is truly desired. More often than not one wants to catch all error exceptions that do not signify a bad state of the interpreter. In the new exception hierarchy this is -embodied by StandardError. Thus bare ``except`` clauses will catch only -exceptions inheriting from StandardError. +embodied by Exception. Thus bare ``except`` clauses will catch only +exceptions inheriting from Exception. Implementation -------------- In the compiler, when a bare ``except`` clause is reached, the code for -``except StandardError`` will be emitted. +``except Exception`` will be emitted. Transition Plan @@ -414,17 +414,14 @@ CriticalException. It also keeps the name of the exception from being "CriticalError". -Renaming Exception to Raisable, StandardError to Exception ----------------------------------------------------------- - -While the naming makes sense and emphasizes the required superclass as what -must be inherited from for raising an object, the naming is not required. -Keeping the existing names minimizes code change to use the new names. +Other Names for BaseException and Exception +------------------------------------------- -It has been argued that changing StandardError to Exception might actually -reflect how users use Exception more accurately, that has not been considered a -strong enough argument. It entails guessing as to what users think in general -and does technically lead to a change that is not backwards-compatible. +Alternative names for BaseException/Exception have been Raisable/Exception and +Exception/StandardError. The former has been rejected on the basis that +Raisable does not reflect how it is an exception well enough. The latter was +rejected based on the fact that it did not reflect current use as the chosen +names do. DeprecationWarning Inheriting From PendingDeprecationWarning @@ -472,12 +469,12 @@ removed since CriticalException signifies this better. -ControlFlowException Under StandardError ----------------------------------------- +ControlFlowException Under Exception +------------------------------------ -It has been suggested that ControlFlowException inherit from StandardError. +It has been suggested that ControlFlowException inherit from Exception. This idea has been rejected based on the thinking that control flow exceptions -are typically not desired to be caught in a generic fashion as StandardError +are typically not desired to be caught in a generic fashion as Exception will usually be used. @@ -498,8 +495,8 @@ It has been suggested that ControlFlowException is not needed. Since the desire to catch any control flow exception will be atypical, the suggestion is to just remove the exception and let the exceptions that -inherited from it inherit directly from Exception. This still preserves the -seperation from StandardError which is one of the driving factors behind the +inherited from it inherit directly from BaseException. This still preserves the +seperation from Exception which is one of the driving factors behind the introduction of the exception. From bcannon at users.sourceforge.net Thu Aug 4 05:35:22 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed, 03 Aug 2005 20:35:22 -0700 Subject: [Python-checkins] python/nondist/peps pep-0000.txt,1.335,1.336 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9941 Modified Files: pep-0000.txt Log Message: Add PEP 348. Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.335 retrieving revision 1.336 diff -u -d -r1.335 -r1.336 --- pep-0000.txt 28 Jun 2005 08:31:08 -0000 1.335 +++ pep-0000.txt 4 Aug 2005 03:35:19 -0000 1.336 @@ -103,6 +103,7 @@ S 341 Unifying try-except and try-finally Birkenfeld S 344 Exception Chaining and Embedded Tracebacks Yee S 345 Metadata for Python Software Packages 1.2 Jones + S 348 Exception Reorganization for Python 3.0 Cannon S 754 IEEE 754 Floating Point Special Values Warnes Finished PEPs (done, implemented in CVS) @@ -388,6 +389,7 @@ S 344 Exception Chaining and Embedded Tracebacks Yee S 345 Metadata for Python Software Packages 1.2 Jones SR 346 User Defined ("with") Statements Coghlan + S 348 Exception Reorganization for Python 3.0 Cannon SR 666 Reject Foolish Indentation Creighton S 754 IEEE 754 Floating Point Special Values Warnes I 3000 Python 3.0 Plans Kuchling, Cannon From bcannon at users.sourceforge.net Thu Aug 4 05:41:41 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Wed, 03 Aug 2005 20:41:41 -0700 Subject: [Python-checkins] python/nondist/peps pep-0348.txt,1.2,1.3 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11161 Modified Files: pep-0348.txt Log Message: Change note on StopIteration and SystemExit on how they now have stricter inheritance thanks to no longer inheriting from Exception. Index: pep-0348.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0348.txt,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- pep-0348.txt 4 Aug 2005 03:33:03 -0000 1.2 +++ pep-0348.txt 4 Aug 2005 03:41:38 -0000 1.3 @@ -85,8 +85,8 @@ +-- SystemError (stricter inheritance) +-- ControlFlowException (new) +-- GeneratorExit (defined in PEP 342 [PEP342]_) - +-- StopIteration (broader inheritance) - +-- SystemExit (broader inheritance) + +-- StopIteration (stricter inheritance) + +-- SystemExit (stricter inheritance) +-- Exception +-- StandardError +-- ArithmeticError @@ -273,6 +273,15 @@ clause. +StopIteration and SystemExit +'''''''''''''''''''''''''''' + +Inherit from ControlFlowException instead of Exception. + +By having these exceptions no longer inherit from Exception they will not be +accidentally caught by a bare ``except`` clause. + + NotImplementedError ''''''''''''''''''' From loewis at users.sourceforge.net Thu Aug 4 20:42:29 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 04 Aug 2005 11:42:29 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,NONE,1.1 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15169 Added Files: pep-0347.txt Log Message: Add PEP 347. --- NEW FILE: pep-0347.txt --- (This appears to be a binary file; contents omitted.) From goodger at users.sourceforge.net Fri Aug 5 01:55:04 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Thu, 04 Aug 2005 16:55:04 -0700 Subject: [Python-checkins] python/nondist/peps pep-0000.txt,1.336,1.337 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22464 Modified Files: pep-0000.txt Log Message: added PEP 347 Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.336 retrieving revision 1.337 diff -u -d -r1.336 -r1.337 --- pep-0000.txt 4 Aug 2005 03:35:19 -0000 1.336 +++ pep-0000.txt 4 Aug 2005 23:55:01 -0000 1.337 @@ -103,6 +103,7 @@ S 341 Unifying try-except and try-finally Birkenfeld S 344 Exception Chaining and Embedded Tracebacks Yee S 345 Metadata for Python Software Packages 1.2 Jones + S 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon S 754 IEEE 754 Floating Point Special Values Warnes @@ -389,6 +390,7 @@ S 344 Exception Chaining and Embedded Tracebacks Yee S 345 Metadata for Python Software Packages 1.2 Jones SR 346 User Defined ("with") Statements Coghlan + S 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon SR 666 Reject Foolish Indentation Creighton S 754 IEEE 754 Floating Point Special Values Warnes From rhettinger at users.sourceforge.net Fri Aug 5 02:01:26 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu, 04 Aug 2005 17:01:26 -0700 Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.39,1.40 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23091 Modified Files: setobject.c Log Message: * Move copyright notice to top and indicate derivation from sets.py and dictobject.c. * Have frozenset_hash() use entry->hash instead of re-computing each individual hash with PyObject_Hash(o); * Finalize the dummy entry before a system exit. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.39 retrieving revision 1.40 diff -u -d -r1.39 -r1.40 --- setobject.c 2 Aug 2005 03:45:14 -0000 1.39 +++ setobject.c 5 Aug 2005 00:01:15 -0000 1.40 @@ -1,15 +1,19 @@ +/* set object implementation + Written and maintained by Raymond D. Hettinger + Derived from Lib/sets.py and Objects/dictobject.c. -/* Set object implementation using a hash table - Functions adapted from dictobject.c + Copyright (c) 2003-5 Python Software Foundation. + All rights reserved. */ #include "Python.h" +#include "structmember.h" /* This must be >= 1. */ #define PERTURB_SHIFT 5 /* Object used as dummy key to fill deleted entries */ -static PyObject *dummy; /* Initialized by first call to make_new_set() */ +static PyObject *dummy = NULL; /* Initialized by first call to make_new_set() */ #define EMPTY_TO_MINSIZE(so) do { \ memset((so)->smalltable, 0, sizeof((so)->smalltable)); \ @@ -515,7 +519,7 @@ return key != NULL && key != dummy; } -/***** Set iterator types **********************************************/ +/***** Set iterator type ***********************************************/ static PyTypeObject PySetIter_Type; /* Forward */ @@ -558,7 +562,6 @@ static PySequenceMethods setiter_as_sequence = { (inquiry)setiter_len, /* sq_length */ - 0, /* sq_concat */ }; static PyObject *setiter_iternext(setiterobject *si) @@ -632,19 +635,6 @@ (iternextfunc)setiter_iternext, /* tp_iternext */ }; -/***** Derived functions (table accesses only done with above primitives *****/ - -#include "structmember.h" - -/* set object implementation - written and maintained by Raymond D. Hettinger - derived from sets.py written by Greg V. Wilson, Alex Martelli, - Guido van Rossum, Raymond Hettinger, and Tim Peters. - - Copyright (c) 2003-5 Python Software Foundation. - All rights reserved. -*/ - static int set_len(PyObject *so) { @@ -764,6 +754,7 @@ void PySet_Fini(void) { + Py_XDECREF(dummy); Py_XDECREF(emptyfrozenset); } @@ -1309,22 +1300,26 @@ static long frozenset_hash(PyObject *self) { - PyObject *key; PySetObject *so = (PySetObject *)self; - int pos = 0; long hash = 1927868237L; + int i, j; if (so->hash != -1) return so->hash; hash *= set_len(self) + 1; - while (set_next_internal(so, &pos, &key)) { + for (i=0, j=so->used ; j ; j--, i++) { + setentry *entry; + long h; + + while ((entry = &so->table[i])->key == NULL || entry->key==dummy) + i++; /* Work to increase the bit dispersion for closely spaced hash values. The is important because some use cases have many combinations of a small number of elements with nearby hashes so that many distinct combinations collapse to only a handful of distinct hash values. */ - long h = PyObject_Hash(key); + h = entry->hash; hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u; } hash = hash * 69069L + 907133923L; From goodger at users.sourceforge.net Fri Aug 5 02:16:53 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Thu, 04 Aug 2005 17:16:53 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.1,1.2 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26153 Modified Files: pep-0347.txt Log Message: light editing pass Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- pep-0347.txt 4 Aug 2005 18:42:26 -0000 1.1 +++ pep-0347.txt 5 Aug 2005 00:16:49 -0000 1.2 @@ -15,140 +15,165 @@ ======== The Python source code is currently managed in a CVS repository on -sourceforge.net. This PEP proposes to move it to a subversion repository -on svn.python.org. +sourceforge.net. This PEP proposes to move it to a subversion +repository on svn.python.org. + Rationale ========= -This change has two aspects: moving from CVS to subversion, and -moving from SourceForge to python.org. For each, a rationale will -be given. +This change has two aspects: moving from CVS to subversion, and moving +from SourceForge to python.org. For each, a rationale will be given. + Moving to Subversion -------------------- + CVS has a number of limitations that have been elimintation by -Subversion. For the development of Python, the most notable improvements -are: +Subversion. For the development of Python, the most notable +improvements are: + +- the ability to rename files and directories, and to remove + directories, while keeping the history of these files. -- ability to rename files and directories, and to remove directories, - while keeping the history of these files. - support for change sets (sets of correlated changes to multiple files) through global revision numbers. + - support for offline diffs, which is useful when creating patches. + Moving to python.org -------------------- + SourceForge has kindly provided an important infrastructure for the -past years. Unfortunately, the attention that SF received has also +past years. Unfortunately, the attention that SF received has also caused repeated overload situations in the past, to which the SF -operators could not always respond in a timely manner. In particular, +operators could not always respond in a timely manner. In particular, for CVS, they had to reduce the load on the primary CVS server by -introducing a second, read-only CVS server for anonymous access. -This server is regularly synchronized, but behind the the read-write -CVS repository between synchronizations. As a result, users without -commit access can see recent changes to the repository only with -a delay. +introducing a second, read-only CVS server for anonymous access. This +server is regularly synchronized, but lags behind the the read-write +CVS repository between synchronizations. As a result, users without +commit access can see recent changes to the repository only after a +delay. On python.org, it would be possible to make the repository accessible for anonymous access. + Migration Procedure =================== To move the Python CVS repository, the following steps need to be -executed. The steps are elaborated in more detail in the next -sections. +executed. The steps are elaborated upon in the following sections. + +1. Assign passwords for all current committers for use on + svn.python.org. User names on SF and svn.python.org should be + identical, unless some committer requests a different user name. -1. Assign passwords for all current committers for use on svn.python.org. - User names on SF and svn.python.org should be identical, unless some - committer requests a different user name. 2. At the beginning of the migration, announce that the repository on SourceForge closed. + 3. 24 hours after the last commit, download the CVS repository. -4. Convert the CVS repository into two subversion repositories, - one for distutils and one for Python. -5. Publish the repositories for write access for all committers, - and anonymous read access. + +4. Convert the CVS repository into two Subversion repositories, one + for Distutils and one for Python. + +5. Publish the repositories with write access for committers, and + read-only anonymous access. + 6. Disable CVS access on SF. + Assign Passwords -================ +---------------- Currently, access to Subversion on svn.python.org uses WebDAV over -https, using basic authentication. For this to work, authorized -users need to provide a password. This mechanism should be used, -atleast initially, for the Python CVS as well, since various committers -also have a username/password pair for the www SVN repository already. +https, using basic authentication. For this to work, authorized users +need to provide a password. This mechanism should be used, at least +initially, for the Python CVS as well, since various committers also +have a username/password pair for the www SVN repository already. Alternatives to password-based access include: - Subversion over SSH, using SSH key pairs. This would require - to give committers accounts on the machine, which currently is + committers to be given accounts on the machine, which currently is ruled out by the administration policy of svn.python.org. -- Subversion over WebDAV, using SSL client certificates. This - would work, but would require to administrate a certificate - authority. + +- Subversion over WebDAV, using SSL client certificates. This would + work, but would require to administrate a certificate authority. + Downloading the CVS Repository -============================== +------------------------------ The CVS repository can be downloaded from -http://cvs.sourceforge.net/cvstarballs/python-cvsroot.tar.bz2 + http://cvs.sourceforge.net/cvstarballs/python-cvsroot.tar.bz2 + +Since this tarball is generated only once a day, some time must pass +after the repository freeze before the tarball can be picked up. It +should be verified that the last commit, as recorded on the +python-commits mailing list, is indeed included in the tarball. -Since this tarball is generated only once a day, some time after -the repository freeze must pass before the tarball can be picked -up. It should be verified that the last commit, as recorded on -the python-commits mailing list, is indeed included in the tarball. Converting the CVS Repository -============================= +----------------------------- -The Python CVS repository contains two modules: distutils and -python. Keeping them together will produce quite long repository -URLs, so it is more convenient if the Python CVS and the distutils -CVS are converted into two separate repositories. +The Python CVS repository contains two modules: distutils and python. +Keeping them together will produce quite long repository URLs, so it +is more convenient if the Python CVS and the Distutils CVS are +converted into two separate repositories. -As the repository format, fsfs should be used (requires Subversion 1.1). -fsfs has the advantage of being more backup-friendly, as it allows to -backup a repository incrementally, without requiring to run any dump -commands. +Fsfs should be used as the repository format (requires Subversion +1.1). Fsfs has the advantage of being more backup-friendly, as it +allows incremental repository backups, without requiring any dump +commands to be run. -The conversion should be done using cvs2svn utility, available e.g. -in the cvs2svn Debian package. The command for converting the Python -repository is +The conversion should be done using the cvs2svn utility, available +e.g. in the cvs2svn Debian package. The command for converting the +Python repository is :: -cvs2svn -q --encoding=latin1 --force-branch=cnri-16-start ---force-branch=descr-branch --force-branch=release152p1-patches ---force-tag=r16b1 --fs-type=fsfs -s py.svn.new python/python + cvs2svn -q --encoding=latin1 --force-branch=cnri-16-start \ + --force-branch=descr-branch --force-branch=release152p1-patches \ + --force-tag=r16b1 --fs-type=fsfs -s py.svn.new python/python -The command to convert the distutils repository is +The command to convert the distutils repository is :: -cvs2svn -q --encoding=latin1 --fs-type=fsfs -s dist.svn.new python/distutils + cvs2svn -q --encoding=latin1 --fs-type=fsfs -s dist.svn.new python/distutils Sample results of this conversion are available at -http://www.dcl.hpi.uni-potsdam.de/python/ -http://www.dcl.hpi.uni-potsdam.de/distutils/ + | http://www.dcl.hpi.uni-potsdam.de/python/ + | http://www.dcl.hpi.uni-potsdam.de/distutils/ + Publish the Repositories -======================== +------------------------ The repositories should be published at https://svn.python.org/python -and https://svn.python.org/distutils. Read-write should be granted -through basic authentication to all current SF committers; read-only -access should be granted anonymously. As an option, websvn (available -e.g. from the Debian websvn package) could be provided. +and https://svn.python.org/distutils. Read-write access should be +granted through basic authentication to all current SF committers; +read-only anonymous access should also be granted. As an option, +websvn (available e.g. from the Debian websvn package) could be +provided. The current SF project admins should get write access to the password file, in order to create or delete new users. + Disable CVS -=========== +----------- -It appears that CVS cannot be disabled entirely. Only the user interface -can be removed from the project page; the repository itself remains -available. If desired, write access to the python and distutils modules -can be disabled through a commitinfo entry. +It appears that CVS cannot be disabled entirely. Only the user +interface can be removed from the project page; the repository itself +remains available. If desired, write access to the python and +distutils modules can be disabled through a CVS commitinfo entry. + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + End: From goodger at users.sourceforge.net Fri Aug 5 02:18:59 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Thu, 04 Aug 2005 17:18:59 -0700 Subject: [Python-checkins] python/nondist/peps pep-0000.txt,1.337,1.338 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27112 Modified Files: pep-0000.txt Log Message: changed PEP 347's type to reflect the PEP itself Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.337 retrieving revision 1.338 diff -u -d -r1.337 -r1.338 --- pep-0000.txt 4 Aug 2005 23:55:01 -0000 1.337 +++ pep-0000.txt 5 Aug 2005 00:18:51 -0000 1.338 @@ -103,7 +103,7 @@ S 341 Unifying try-except and try-finally Birkenfeld S 344 Exception Chaining and Embedded Tracebacks Yee S 345 Metadata for Python Software Packages 1.2 Jones - S 347 Migrating the Python CVS to Subversion von Lwis + I 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon S 754 IEEE 754 Floating Point Special Values Warnes @@ -390,7 +390,7 @@ S 344 Exception Chaining and Embedded Tracebacks Yee S 345 Metadata for Python Software Packages 1.2 Jones SR 346 User Defined ("with") Statements Coghlan - S 347 Migrating the Python CVS to Subversion von Lwis + I 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon SR 666 Reject Foolish Indentation Creighton S 754 IEEE 754 Floating Point Special Values Warnes From nascheme at users.sourceforge.net Fri Aug 5 04:59:02 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Thu, 04 Aug 2005 19:59:02 -0700 Subject: [Python-checkins] python/nondist/peps pep-0349.txt, NONE, 1.1 pep-0000.txt, 1.338, 1.339 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23371 Modified Files: pep-0000.txt Added Files: pep-0349.txt Log Message: Add PEP 349. --- NEW FILE: pep-0349.txt --- PEP: 349 Title: Generalised String Coercion Version: $Revision: 1.1 $ Last-Modified: $Date: 2005/08/05 02:59:00 $ Author: Neil Schemenauer Status: Draft Type: Standards Track Content-Type: text/plain Created: 02-Aug-2005 Post-History: Python-Version: 2.5 Abstract This PEP proposes the introduction of a new built-in function, text(), that provides a way of generating a string representation of an object. This function would make it easier to write library code that processes string data without forcing the use of a particular string type. Rationale Python has had a Unicode string type for some time now but use of it is not yet widespread. There is a large amount of Python code that assumes that string data is represented as str instances. The long term plan for Python is to phase out the str type and use unicode for all string data. Clearly, a smooth migration path must be provided. We need to upgrade existing libraries, written for str instances, to be made capable of operating in an all-unicode string world. We can't change to an all-unicode world until all essential libraries are made capable for it. Upgrading the libraries in one shot does not seem feasible. A more realistic strategy is to individually make the libraries capable of operating on unicode strings while preserving their current all-str environment behaviour. First, we need to be able to write code that can accept unicode instances without attempting to coerce them to str instances. Let us label such code as Unicode-safe. Unicode-safe libraries can be used in an all-unicode world. Second, we need to be able to write code that, when provided only str instances, will not create unicode results. Let us label such code as str-stable. Libraries that are str-stable can be used by libraries and applications that are not yet Unicode-safe. Sometimes it is simple to write code that is both str-stable and Unicode-safe. For example, the following function just works: def appendx(s): return s + 'x' That's not too surprising since the unicode type is designed to make the task easier. The principle is that when str and unicode instances meet, the result is a unicode instance. One notable difficulty arises when code requires a string representation of an object; an operation traditionally accomplished by using the str() built-in function. Using str() makes the code not Unicode-safe. Replacing a str() call with a unicode() call makes the code not str-stable. Using a string format almost accomplishes the goal but not quite. Consider the following code: def text(obj): return '%s' % obj It behaves as desired except if 'obj' is not a basestring instance and needs to return a Unicode representation of itself. In that case, the string format will attempt to coerce the result of __str__ to a str instance. Defining a __unicode__ method does not help since it will only be called if the right-hand operand is a unicode instance. Using a unicode instance for the right-hand operand does not work because the function is no longer str-stable (i.e. it will coerce everything to unicode). Specification A Python implementation of the text() built-in follows: def text(s): """Return a nice string representation of the object. The return value is a basestring instance. """ if isinstance(s, basestring): return s r = s.__str__() if not isinstance(s, basestring): raise TypeError('__str__ returned non-string') return r Note that it is currently possible, although not very useful, to write __str__ methods that return unicode instances. The %s format specifier for str objects would be changed to call text() on the argument. Currently it calls str() unless the argument is a unicode instance (in which case the object is substituted as is and the % operation returns a unicode instance). The following function would be added to the C API and would be the equivalent of the text() function: PyObject *PyObject_Text(PyObject *o); A reference implementation is available on Sourceforge [1] as a patch. Backwards Compatibility The change to the %s format specifier would result in some % operations returning a unicode instance rather than raising a UnicodeDecodeError exception. It seems unlikely that the change would break currently working code. Alternative Solutions Rather than adding the text() built-in, if PEP 246 were implemented then adapt(s, basestring) could be equivalent to text(s). The advantage would be one less built-in function. The problem is that PEP 246 is not implemented. Fredrik Lundh has suggested [2] that perhaps a new slot should be added (e.g. __text__), that could return any kind of string that's compatible with Python's text model. That seems like an attractive idea but many details would still need to be worked out. Instead of providing the text() built-in, the %s format specifier could be changed and a string format could be used instead of calling text(). However, it seems like the operation is important enough to justify a built-in. Instead of providing the text() built-in, the basestring type could be changed to provide the same functionality. That would possibly be confusing behaviour for an abstract base type. Some people have suggested [3] that an easier migration path would be to change the default encoding to be UTF-8. Code that is not Unicode safe would then encode Unicode strings as UTF-8 and operate on them as str instances, rather than raising a UnicodeDecodeError exception. Other code would assume that str instances were encoded using UTF-8 and decode them if necessary. While that solution may work for some applications, it seems unsuitable as a general solution. For example, some applications get string data from many different sources and assuming that all str instances were encoded using UTF-8 could easily introduce subtle bugs. References [1] http://www.python.org/sf/1159501 [2] http://mail.python.org/pipermail/python-dev/2004-September/048755.html [3] http://blog.ianbicking.org/illusive-setdefaultencoding.html Copyright This document has been placed in the public domain. Local Variables: mode: indented-text indent-tabs-mode: nil sentence-end-double-space: t fill-column: 70 End: Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.338 retrieving revision 1.339 diff -u -d -r1.338 -r1.339 --- pep-0000.txt 5 Aug 2005 00:18:51 -0000 1.338 +++ pep-0000.txt 5 Aug 2005 02:59:00 -0000 1.339 @@ -105,6 +105,7 @@ S 345 Metadata for Python Software Packages 1.2 Jones I 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon + S 349 Generalized String Coercion Schemenauer S 754 IEEE 754 Floating Point Special Values Warnes Finished PEPs (done, implemented in CVS) @@ -392,6 +393,7 @@ SR 346 User Defined ("with") Statements Coghlan I 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon + S 349 Generalized String Coercion Schemenauer SR 666 Reject Foolish Indentation Creighton S 754 IEEE 754 Floating Point Special Values Warnes I 3000 Python 3.0 Plans Kuchling, Cannon From goodger at users.sourceforge.net Fri Aug 5 07:31:46 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Thu, 04 Aug 2005 22:31:46 -0700 Subject: [Python-checkins] python/nondist/peps pep-0348.txt,1.3,1.4 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11195 Modified Files: pep-0348.txt Log Message: editing pass Index: pep-0348.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0348.txt,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- pep-0348.txt 4 Aug 2005 03:41:38 -0000 1.3 +++ pep-0348.txt 5 Aug 2005 05:31:44 -0000 1.4 @@ -13,135 +13,157 @@ Abstract ======== -Python, as of version 2.4, has 38 exceptions (including warnings) in the built-in namespace in a rather shallow hierarchy. -This list of classes has grown over the years without a chance to learn from mistakes and cleaning up the hierarchy. -This PEP proposes doing a reorganization for Python 3.0 when backwards-compatibility is not an issue. -Along with this reorganization, adding a requirement that all objects passed to -a ``raise`` statement must inherit from a specific superclass is proposed. -Lastly, bare ``except`` clauses will catch only exceptions inheriting from -Exception. +Python, as of version 2.4, has 38 exceptions (including warnings) in +the built-in namespace in a rather shallow hierarchy. This list of +classes has grown over the years without a chance to learn from +mistakes and clean up the hierarchy. This PEP proposes doing a +reorganization for Python 3.0 when backwards-compatibility is not an +issue. Along with this reorganization, adding a requirement that all +objects passed to a ``raise`` statement must inherit from a specific +superclass is proposed. Lastly, bare ``except`` clauses will catch +only exceptions inheriting from Exception. Rationale ========= -Exceptions are a critical part of Python. -While exceptions are traditionally used to signal errors in a program, they have also grown to be used for flow control for things such as iterators. -There importance is great. +Exceptions are a critical part of Python. While exceptions are +traditionally used to signal errors in a program, they have also grown +to be used for flow control for things such as iterators. Their +importance is great. -But the organization of the exception hierarchy is suboptimal to serve the -multiple uses of exceptions. -Mostly for backwards-compatibility reasons, the hierarchy has stayed very flat and old exceptions who usefulness have not been proven have been left in. -Making exceptions more hierarchical would help facilitate exception handling by making catching exceptions using inheritance much more logical. -This should also help lead to less errors from being too broad in what exceptions are caught in an ``except`` clause. +But the organization of the exception hierarchy is suboptimal to serve +the multiple uses of exceptions. Mostly for backwards-compatibility +reasons, the hierarchy has stayed very flat and old exceptions whose +usefulness has not been proven have been left in. Making exceptions +more hierarchical would help facilitate exception handling by making +exception catching using inheritance much more logical. This should +also help lead to fewer errors from overly broad exception catching in +``except`` clauses. -A required superclass for all exceptions is also being proposed [Summary2004-08-01]_. -By requiring any object that is used in a ``raise`` statement to inherit from a specific superclass, certain attributes (such as those laid out in PEP 344 [PEP344]_) can be guaranteed to exist. -This also will lead to the planned removal of string exceptions. +A mandatory superclass for all exceptions is also being proposed +[#Summary2004-08-01]_. By requiring any object that is used in a +``raise`` statement to inherit from a specific superclass, certain +attributes (such as those laid out in PEP 344 [#PEP344]_) can be +guaranteed to exist. This also will lead to the planned removal of +string exceptions. -Lastly, bare ``except`` clauses are to catch only exceptions that inherit from -Exception [python-dev3]_. -While currently used to catch all exceptions, that use is rather far reaching -and typically not desired. -Catching only exceptions inheriting from Exception allows exceptions that -should not be caught unless explicitly desired to continue to propagate up the -execution stack. +Lastly, bare ``except`` clauses are to catch only exceptions that +inherit from ``Exception`` [#python-dev3]_. While currently used to +catch all exceptions, that use is too far-reaching and typically not +desired. Catching only exceptions that inherit from ``Exception`` +allows other exceptions (those that should not be caught unless +explicitly desired) to continue to propagate up the execution stack. Philosophy of Reorganization ============================ -There are several goals in this reorganization that defined the philosophy used to guide the work. -One goal was to prune out unneeded exceptions. -Extraneous exceptions should not be left in since it just serves to clutter the built-in namespace. -Unneeded exceptions also dilute the importance of other exceptions by splitting uses between several exceptions when all uses should have been under a single exception. +There are several goals in this reorganization that defined the +philosophy used to guide the work. One goal was to prune out unneeded +exceptions. Extraneous exceptions should not be left in since they +just serve to clutter the built-in namespace. Unneeded exceptions +also dilute the importance of other exceptions by splitting uses +between several exceptions when all uses should have been under a +single exception. -Another goal was to introduce any exceptions that were deemed needed to fill any holes in the hierarchy. -Most new exceptions were done to flesh out the inheritance hierarchy to make it easier to catch a category of exceptions with a simpler ``except`` clause. +Another goal was to introduce exceptions that were deemed necessary to +fill holes in the hierarchy. Most new exceptions were added to flesh +out the inheritance hierarchy to make it easier to catch a category of +exceptions with a simpler ``except`` clause. -Changing inheritance to make it more reasonable was a goal. -As stated above, having proper inheritance allows for more accurate ``except`` statements when catching exceptions based on the inheritance tree. +Changing inheritance to make the hierarchy more reasonable was a goal. +As stated above, having proper inheritance allows for more accurate +``except`` statements when catching exceptions based on the +inheritance tree. + +Lastly, some renaming was done to make the usage of certain exceptions +more obvious. Having to look up an exception due to the name not +accurately reflecting its intended use is annoying and slows down +debugging. Having accurate names also makes debugging easier for new +programmers. But for simplicity, for the convenience of existing +users, and for the sake of transitioning to Python 3.0, only +exceptions whose names were significantly out of alignment with their +stated purpose have been renamed. All exceptions dealing with errors +will be named with an "Error" suffix. -Lastly, any renaming to make an exception's use more obvious from its name was done. -Having to look up what an exception is meant to be used for because the name does not proper reflect its usage is annoying and slows down debugging. -Having a proper name also makes debugging easier on new programmers. -But for simplicity of existing user's and for transitioning to Python 3.0, only exceptions whose names were fairly out of alignment with their stated purpose have been renamed. -It was also made sure the exceptions dealing with errors had the "Error" -suffix. New Hierarchy ============= -.. note:: exceptions flagged as "stricter inheritance" means that the class no - longer inherits from a certain class; "broader inheritance" means a class has - been added to the exception's inheritance tree +.. Note:: Exceptions flagged with "stricter inheritance" will no + longer inherit from a certain class. A "broader inheritance" flag + means a class has been added to the exception's inheritance tree. -:: +.. parsed-literal:: - BaseException - +-- CriticalError (new) - +-- KeyboardInterrupt (stricter inheritance) - +-- MemoryError (stricter inheritance) - +-- SystemError (stricter inheritance) - +-- ControlFlowException (new) - +-- GeneratorExit (defined in PEP 342 [PEP342]_) - +-- StopIteration (stricter inheritance) - +-- SystemExit (stricter inheritance) - +-- Exception - +-- StandardError - +-- ArithmeticError - +-- DivideByZeroError - +-- FloatingPointError - +-- OverflowError - +-- AssertionError - +-- AttributeError - +-- EnvironmentError - +-- IOError - +-- EOFError (broader inheritance) - +-- OSError - +-- ImportError - +-- LookupError - +-- IndexError - +-- KeyError - +-- NamespaceError (rename of NameError) - +-- UnboundFreeError (new) - +-- UnboundGlobalError (new) - +-- UnboundLocalError - +-- NotImplementedError (stricter inheritance) - +-- SyntaxError - +-- IndentationError - +-- TabError - +-- TypeError - +-- UserError (rename of RuntimeError) - +-- UnicodeError - +-- UnicodeDecodeError - +-- UnicodeEncodeError - +-- UnicodeTranslateError - +-- ValueError - +-- Warning - +-- AnyDeprecationWarning (new; broader inheritance for subclasses) - +-- PendingDeprecationWarning - +-- DeprecationWarning - +-- FutureWarning - +-- SyntaxWarning - +-- SemanticsWarning (rename of RuntimeWarning) - +-- UserWarning - +-- WeakReferenceError (rename of ReferenceError) + BaseException + +-- CriticalError (new) + +-- KeyboardInterrupt (stricter inheritance) + +-- MemoryError (stricter inheritance) + +-- SystemError (stricter inheritance) + +-- ControlFlowException (new) + +-- GeneratorExit (defined in PEP 342 [#PEP342]_) + +-- StopIteration (stricter inheritance) + +-- SystemExit (stricter inheritance) + +-- Exception + +-- StandardError + +-- ArithmeticError + +-- DivideByZeroError + +-- FloatingPointError + +-- OverflowError + +-- AssertionError + +-- AttributeError + +-- EnvironmentError + +-- IOError + +-- EOFError (broader inheritance) + +-- OSError + +-- ImportError + +-- LookupError + +-- IndexError + +-- KeyError + +-- NamespaceError (renamed from NameError) + +-- UnboundFreeError (new) + +-- UnboundGlobalError (new) + +-- UnboundLocalError + +-- NotImplementedError (stricter inheritance) + +-- SyntaxError + +-- IndentationError + +-- TabError + +-- TypeError + +-- UserError (renamed from RuntimeError) + +-- UnicodeError + +-- UnicodeDecodeError + +-- UnicodeEncodeError + +-- UnicodeTranslateError + +-- ValueError + +-- Warning + +-- AnyDeprecationWarning (new; broader inheritance for subclasses) + +-- PendingDeprecationWarning + +-- DeprecationWarning + +-- FutureWarning + +-- SyntaxWarning + +-- SemanticsWarning (renamed from RuntimeWarning) + +-- UserWarning + +-- WeakReferenceError (renamed from ReferenceError) Differences Compared to Python 2.4 ================================== -Changes to exceptions from Python 2.4 can take shape in three forms: removal, renaming, or change in the inheritance tree. -There are also new exceptions introduced in the proposed hierarchy. +Changes to exceptions from Python 2.4 can take shape in three forms: +removal, renaming, or change of position in the hierarchy. There are +also new exceptions introduced in the proposed hierarchy. -In terms of new exceptions, almost all are to flesh out the inheritance tree. -Those that are leaf classes are to alleaviate overloading the use of another exception. +In terms of new exceptions, almost all are added to flesh out the +inheritance tree. Those that are leaf classes are added to alleviate +the overloading of another exception. -Inheritance change can be broader or more restrictive. The broader inheritance -typically occurred to allow for a more reasonable superclass to group related -exceptions together. Stricter inheritance happened when the pre-existing -inheritance was deemed incorrect and needed correction. +Positional changes result in either broader or more restrictive +inheritance. The broader inheritance typically occurred to allow for +a more reasonable superclass to group related exceptions together. +Stricter inheritance happened when the pre-existing inheritance was +deemed incorrect and needed correction. New Exceptions @@ -156,20 +178,20 @@ CriticalError ''''''''''''' -The superclass for exceptions for which a severe error has occurred that one -would not want to recover from. -The name is meant to reflect that these exceptions are raised asynchronously by -the interpreter when a critical event has occured that one would most likely -want the interpreter to halt over. +The superclass for severe error exceptions; typically, one would not +want to recover from such an exception. The name is meant to reflect +that these exceptions are raised asynchronously by the interpreter +when a critical event has occured. ControlFlowException '''''''''''''''''''' -This exception exists as a superclass for all exceptions that directly deal -with control flow. -Inheriting from BaseException instead of Exception prevents them from being caught accidently when one wants to catch errors. -The name, by not mentioning "Error", does not lead to one to confuse the subclasses as errors. +This exception exists as a superclass for all exceptions that directly +deal with control flow. Inheriting from BaseException instead of +Exception prevents them from being caught accidently when one wants to +catch errors. The name, by not mentioning "Error", does not lead to +one to confuse the subclasses as errors. UnboundGlobalError @@ -187,13 +209,12 @@ AnyDeprecationWarning ''''''''''''''''''''' -A common superclass for all deprecation-related exceptions. -While having DeprecationWarning inherit from PendingDeprecationWarning was -suggested because a DeprecationWarning can be viewed as a -PendingDeprecationWarning that is happening now, the logic was not agreed upon -by a majority. -But since the exceptions are related, creating a common superclass is -warranted. +A common superclass for all deprecation-related exceptions. While +having DeprecationWarning inherit from PendingDeprecationWarning was +suggested (a DeprecationWarning can be viewed as a +PendingDeprecationWarning that is happening now), the logic was not +agreed upon by a majority. But since the exceptions are related, +creating a common superclass is warranted. Removed Exceptions @@ -211,85 +232,91 @@ RuntimeError '''''''''''' -Renamed UserError. +Renamed to UserError. -Meant for use as a generic exception to be used when one does not want to -create a new exception class but do not want to raise an exception that might -be caught based on inheritance, RuntimeError is poorly named. -It's name in Python 2.4 seems to suggest an error that occurred at runtime, -possibly an error in the VM. -Renaming the exception to UserError more clearly states the purpose for -the exception as quick-and-dirty error exception for the user to use. -The name also keeps it in line with UserWarning. +Meant as a generic exception for use when neither a new exception +class nor inheritance-based exception catching is desired, +RuntimeError is poorly named. Its name in Python 2.4 seems to suggest +an error that occurred at runtime, possibly an error in the VM. +Renaming the exception to UserError more clearly states the purpose of +the exception as a quick-and-dirty error exception. The name also +keeps it in line with UserWarning. -If a user wants an exception that is not to be used as an error, raising -BaseException directly should be sufficient as Exception, as UserError inherits -from, is only used for errors. +If a user wants an non-error exception, raising BaseException directly +should be sufficient since Exception, which UserError inherits from, +is only used for errors. ReferenceError '''''''''''''' -Renamed WeakReferenceError. +Renamed to WeakReferenceError. -ReferenceError was added to the built-in exception hierarchy in Python 2.2 -[exceptions-stdlib]_. -Taken directly from the ``weakref`` module, its name comes directly from its original name when it resided in the module. -Unfortunately its name does not suggest its connection to weak references and thus deserves a renaming. +ReferenceError was added to the built-in exception hierarchy in Python +2.2 [#exceptions-stdlib]_. Its name comes directly from the time when +it resided in the ``weakref`` module. Unfortunately its name does not +suggest its connection to weak references and thus deserves a +renaming. NameError ''''''''' -Renamed NamespaceError. +Renamed to NamespaceError. While NameError suggests its common use, it is not entirely apparent. -Making it more of a superclass for namespace-related exceptions warrants a -renaming to make it abundantly clear its use. -Plus the documentation of the exception module[exceptions-stdlib]_ states that it is actually meant for global names and not for just any exception. +Making it a superclass for namespace-related exceptions warrants a +renaming to make its use abundantly clear. Plus the documentation of +the exception module [#exceptions-stdlib]_ states that it was actually +meant for global names and not for just any exception. RuntimeWarning '''''''''''''' -Renamed SemanticsWarning. +Renamed to SemanticsWarning. -RuntimeWarning is to represent semantic changes coming in the future. -But while saying that affects "runtime" is true, flat-out stating it is a semantic change is much clearer, eliminating any possible association of "runtime" with the virtual machine specifically. +RuntimeWarning is supposed to represent semantic changes coming in the +future. But while saying that it affects the "runtime" is true, +flat-out stating that it is a semantic change is much clearer, +eliminating any possible association of the term "runtime" with the +virtual machine. -Changed Inheritance -------------------- +Change of Position in the Exception Hierarchy +--------------------------------------------- KeyboardInterrupt, MemoryError, and SystemError ''''''''''''''''''''''''''''''''''''''''''''''' -Inherit from CriticalError instead of Exception. +Inherit from CriticalError instead of from Exception. -The three above-mentioned exceptions are not standard errors by any means. -They are raised asynchronously by the interpreter when something specific has +These three exceptions are not standard errors by any means. They are +raised asynchronously by the interpreter when something specific has occurred. Thus they warrant not inheriting from Exception but from an -entirely separate exception that will not be caught by a bare ``except`` -clause. +entirely separate exception that will not be caught by a bare +``except`` clause. StopIteration and SystemExit '''''''''''''''''''''''''''' -Inherit from ControlFlowException instead of Exception. +Inherit from ControlFlowException instead of from Exception. -By having these exceptions no longer inherit from Exception they will not be -accidentally caught by a bare ``except`` clause. +By having these exceptions no longer inherit from Exception they will +not be accidentally caught by a bare ``except`` clause. NotImplementedError ''''''''''''''''''' -Inherits from Exception instead of RuntimeError (renamed UserError). +Inherits from Exception instead of from RuntimeError (renamed to +UserError). -Originally inheriting from RuntimeError, NotImplementedError does not have any -direct relation to the exception meant for use in user code as a -quick-and-dirty exception. Thus it now directly inherits from Exception. +Originally inheriting from RuntimeError, NotImplementedError does not +have any direct relation to the exception meant for use in user code +as a quick-and-dirty exception. Thus it now directly inherits from +Exception. EOFError @@ -297,49 +324,53 @@ Subclasses IOError. -Since an EOF comes from I/O it only makes sense that it be considered an I/O error. +Since an EOF comes from I/O it only makes sense that it be considered +an I/O error. Required Superclass for ``raise`` ================================= -By requiring all objects passed to a ``raise`` statement inherit from a specific superclass, one is guaranteed that all exceptions will have certain attributes. -If PEP 342 [PEP344]_ is accepted, the attributes outlined there will be guaranteed to be on all exceptions raised. -This should help facilitate debugging by making the querying of information from exceptions much easier. +By requiring all objects passed to a ``raise`` statement to inherit +from a specific superclass, all exceptions are guaranteed to have +certain attributes. If PEP 344 [#PEP344]_ is accepted, the attributes +outlined there will be guaranteed to be on all exceptions raised. +This should help facilitate debugging by making the querying of +information from exceptions much easier. -The proposed hierarchy has BaseException as the required class that one must inherit from. +The proposed hierarchy has BaseException as the required base class. Implementation -------------- -Enforcement is straight-forward. -Modifying ``RAISE_VARARGS`` to do an inheritance check first before raising -an exception should be enough. For the C API, all functions that set an -exception will have the same inheritance check. +Enforcement is straightforward. Modifying ``RAISE_VARARGS`` to do an +inheritance check first before raising an exception should be enough. +For the C API, all functions that set an exception will have the same +inheritance check applied. -Bare ``except`` Clauses Catching Exception Only -=============================================== +Bare ``except`` Clauses Catching ``Exception`` Only +=================================================== -While Python does have its "explicit is better than implicit" tenant, it is not -necessary if a default behavior is reasonable. In the case of a bare -``except`` clause, changing the behavior makes it quite reasonable to have -around. +While Python does have its "explicit is better than implicit" tenant, +it is not necessary if there is a reasonable default behavior. +Changing the behavior of a bare ``except`` clause makes its existance +quite reasonable. -In Python 2.4, a bare ``except`` clause will catch all exceptions. Typically, -though, this is not what is truly desired. -More often than not one wants to catch all error exceptions that do not signify -a bad state of the interpreter. In the new exception hierarchy this is -embodied by Exception. Thus bare ``except`` clauses will catch only -exceptions inheriting from Exception. +In Python 2.4, a bare ``except`` clause will catch any and all +exceptions. Typically, though, this is not what is truly desired. +More often than not one wants to catch all error exceptions that do +not signify a "bad" interpreter state. In the new exception hierarchy +this is condition is embodied by Exception. Thus bare ``except`` +clauses will catch only exceptions inheriting from Exception. Implementation -------------- -In the compiler, when a bare ``except`` clause is reached, the code for -``except Exception`` will be emitted. +In the compiler, when a bare ``except`` clause is reached, the code +for ``except Exception`` will be emitted. Transition Plan @@ -351,53 +382,54 @@ New Exceptions '''''''''''''' -New exceptions can simply be added to the built-in namespace. -Any pre-existing objects with the same name will mask the new exceptions, +New exceptions can simply be added to the built-in namespace. Any +pre-existing objects with the same name will mask the new exceptions, preserving backwards-compatibility. Renamed Exceptions '''''''''''''''''' -Renamed exceptions will directly subclass the new names. -When the old exceptions are instantiated (which occurs when an exception is -caught, either by a ``try`` statement or by propagating to the top of the +Renamed exceptions will directly subclass the new names. When the old +exceptions are instantiated (which occurs when an exception is caught, +either by a ``try`` statement or by propagating to the top of the execution stack), a PendingDeprecationWarning will be raised. -This should properly preserve backwards-compatibility as old usage won't change -and the new names can be used to also catch exceptions using the old name. -The warning of the deprecation is also kept simple. +This should properly preserve backwards-compatibility as old usage +won't change and the new names can also be used to catch exceptions +using the old names. The warning of the deprecation is also kept +simple. New Inheritance for Old Exceptions '''''''''''''''''''''''''''''''''' -Using multiple inheritance to our advantage, exceptions whose inheritance is -now more resrictive can be made backwards-compatible. +Using multiple inheritance to our advantage, exceptions whose +inheritance is now more resrictive can be made backwards-compatible. By inheriting from both the new superclasses as well as the original -superclasses existing ``except`` clauses will continue to work as before while -allowing the new inheritance to be used for new clauses. +superclasses, existing ``except`` clauses will continue to work as +before while allowing the new inheritance to be used for new code. -A PendingDeprecationWarning will be raised based on whether the bytecode -``COMPARE_OP(10)`` results in an exception being caught that would not have -under the new hierarchy. This will require hard-coding in the implementation -of the bytecode. +A PendingDeprecationWarning will be raised based on whether the +bytecode ``COMPARE_OP(10)`` results in an exception being caught that +would not have under the new hierarchy. This will require hard-coding +in the implementation of the bytecode. Removed Exceptions '''''''''''''''''' -Exceptions scheduled for removal will be transitioned much like the old names -of renamed exceptions. -Upon instantiation a PendingDeprecationWarning will be raised stating the the -exception is due to be removed by Python 3.0 . +Exceptions scheduled for removal will be transitioned much like the +old names of renamed exceptions. Upon instantiation a +PendingDeprecationWarning will be raised stating the the exception is +due for removal in Python 3.0. Required Superclass for ``raise`` --------------------------------- -A SemanticsWarning will be raised when an object is passed to ``raise`` that -does not have the proper inheritance. +A SemanticsWarning will be raised when an object is passed to +``raise`` that does not have the proper inheritance. Removal of Bare ``except`` Clauses @@ -410,89 +442,91 @@ ============== Threads on python-dev discussing this PEP can be found at -[python-dev-thread1]_, [python-dev-thread2]_ +[#python-dev-thread1]_ and [#python-dev-thread2]_ KeyboardInterrupt inheriting from ControlFlowException ------------------------------------------------------ KeyboardInterrupt has been a contentious point within this hierarchy. -Some view the exception as more control flow being caused by the user. -But with its asynchronous cause thanks to the user being able to trigger the -exception at any point in code it has a more proper place inheriting from -CriticalException. It also keeps the name of the exception from being "CriticalError". +Some view the exception more as control flow being caused by the user. +But with its asynchronous cause (the user is able to trigger the +exception at any point in code) its proper place is inheriting from +CriticalException. It also keeps the name of the exception from being +"CriticalError". Other Names for BaseException and Exception ------------------------------------------- -Alternative names for BaseException/Exception have been Raisable/Exception and -Exception/StandardError. The former has been rejected on the basis that -Raisable does not reflect how it is an exception well enough. The latter was -rejected based on the fact that it did not reflect current use as the chosen -names do. +Alternative names for BaseException and Exception have been +Raisable/Exception and Exception/StandardError. The former +alternatives were rejected because "Raisable" does not reflect its +exception nature well enough. The latter alternatives were rejected +because they do not reflect current use. DeprecationWarning Inheriting From PendingDeprecationWarning ------------------------------------------------------------ -Originally proposed because a DeprecationWarning can be viewed as a -PendingDeprecationWarning that is being removed in the next version. -But enough people thought the inheritance could logically work the other way -the idea was dropped. +This was originally proposed because a DeprecationWarning can be +viewed as a PendingDeprecationWarning that is being removed in the +next version. But since enough people thought the inheritance could +logically work the other way around, the idea was dropped. AttributeError Inheriting From TypeError or NameError ----------------------------------------------------- -Viewing attributes as part of the interface of a type caused the idea of -inheriting from TypeError. -But that partially defeats the thinking of duck typing and thus was dropped. +Viewing attributes as part of the interface of a type caused the idea +of inheriting from TypeError. But that partially defeats the thinking +of duck typing and thus the idea was dropped. -Inheriting from NameError was suggested because objects can be viewed as having -their own namespace that the attributes lived in and when they are not found it -is a namespace failure. This was also dropped as a possibility since not -everyone shared this view. +Inheriting from NameError was suggested because objects can be viewed +as having their own namespace where the attributes live and when an +attribute is not found it is a namespace failure. This was also +dropped as a possibility since not everyone shared this view. Removal of EnvironmentError --------------------------- -Originally proposed based on the idea that EnvironmentError was an unneeded -distinction, the BDFL overruled this idea [python-dev4]_. +Originally proposed based on the idea that EnvironmentError was an +unneeded distinction, the BDFL overruled this idea [#python-dev4]_. Introduction of MacError and UnixError -------------------------------------- -Proposed to add symmetry to WindowsError, the BDFL said they won't be used -enough [python-dev4]_. The idea of then removing WindowsError was proposed and -accepted as reasonable, thus completely negating the idea of adding these -exceptions. +Proposed to add symmetry to WindowsError, the BDFL said they won't be +used enough [#python-dev4]_. The idea of then removing WindowsError +was proposed and accepted as reasonable, thus completely negating the +idea of adding these exceptions. SystemError Subclassing SystemExit ---------------------------------- -Proposed because a SystemError is meant to lead to a system exit, the idea was -removed since CriticalException signifies this better. +Proposed because a SystemError is meant to lead to a system exit, the +idea was removed since CriticalException indicates this better. ControlFlowException Under Exception ------------------------------------ -It has been suggested that ControlFlowException inherit from Exception. -This idea has been rejected based on the thinking that control flow exceptions -are typically not desired to be caught in a generic fashion as Exception -will usually be used. +It has been suggested that ControlFlowException should inherit from +Exception. This idea has been rejected based on the thinking that +control flow exceptions typically should not be caught by bare +``except`` clauses, whereas Exception subclasses should be. Removal of Bare ``except`` Clauses ---------------------------------- -The suggestion has been made to remove bare ``except`` clauses in the name of -"explicit is better than implicit". But Guido has said this is too weak of an -argument since other things in Python has default behavior [python-dev3]_. +The suggestion has been made to remove bare ``except`` clauses +altogether, in the name of "explicit is better than implicit". But +Guido has said this is too weak of an argument since other areas of +Python have default behavior [#python-dev3]_. Open Issues @@ -501,63 +535,76 @@ Remove ControlFlowException? ---------------------------- -It has been suggested that ControlFlowException is not needed. -Since the desire to catch any control flow exception will be atypical, the +It has been suggested that ControlFlowException is not needed. Since +the desire to catch any control flow exception will be atypical, the suggestion is to just remove the exception and let the exceptions that -inherited from it inherit directly from BaseException. This still preserves the -seperation from Exception which is one of the driving factors behind the -introduction of the exception. +inherited from it inherit directly from BaseException. This still +preserves the seperation from Exception which is one of the driving +factors behind the introduction of ControlFlowException. Acknowledgements ================ -Thanks to Robert Brewer, Josiah Carlson, Nick Coghlan, Timothy Delaney, Jack Diedrich, Fred L. Drake, Jr., Philip J. Eby, Greg Ewing, James Y. Knight, MA Lemburg, Guido van Rossum, Stephen J. Turnbull and everyone else I missed for participating in the discussion. +Thanks to Robert Brewer, Josiah Carlson, Nick Coghlan, Timothy +Delaney, Jack Diedrich, Fred L. Drake, Jr., Philip J. Eby, Greg Ewing, +James Y. Knight, MA Lemburg, Guido van Rossum, Stephen J. Turnbull and +everyone else I missed for participating in the discussion. References ========== -.. [PEP342] PEP 342 (Coroutines via Enhanced Generators) - (http://www.python.org/peps/pep-0342.html) - -.. [PEP344] PEP 344 (Exception Chaining and Embedded Tracebacks) - (http://www.python.org/peps/pep-0344.html) +.. [#PEP342] PEP 342 (Coroutines via Enhanced Generators) + (http://www.python.org/peps/pep-0342.html) -.. [exceptionsmodules] 'exceptions' module - (http://docs.python.org/lib/module-exceptions.html) +.. [#PEP344] PEP 344 (Exception Chaining and Embedded Tracebacks) + (http://www.python.org/peps/pep-0344.html) -.. [Summary2004-08-01] python-dev Summary (An exception is an exception, unless it doesn't inherit from Exception) - (http://www.python.org/dev/summary/2004-08-01_2004-08-15.html#an-exception-is-an-exception-unless-it-doesn-t-inherit-from-exception) +.. [#Summary2004-08-01] python-dev Summary (An exception is an + exception, unless it doesn't inherit from Exception) + (http://www.python.org/dev/summary/2004-08-01_2004-08-15.html#an-exception-is-an-exception-unless-it-doesn-t-inherit-from-exception) -.. [Summary2004-09-01] python-dev Summary (Cleaning the Exception House) - (http://www.python.org/dev/summary/2004-09-01_2004-09-15.html#cleaning-the-exception-house) +.. [#Summary2004-09-01] python-dev Summary (Cleaning the Exception House) + (http://www.python.org/dev/summary/2004-09-01_2004-09-15.html#cleaning-the-exception-house) -.. [python-dev1] python-dev email (Exception hierarchy) - (http://mail.python.org/pipermail/python-dev/2004-August/047908.html) +.. [#python-dev1] python-dev email (Exception hierarchy) + (http://mail.python.org/pipermail/python-dev/2004-August/047908.html) -.. [python-dev2] python-dev email (Dangerous exceptions) - (http://mail.python.org/pipermail/python-dev/2004-September/048681.html) +.. [#python-dev2] python-dev email (Dangerous exceptions) + (http://mail.python.org/pipermail/python-dev/2004-September/048681.html) -.. [python-dev3] python-dev email (PEP, take 2: Exception Reorganization for Python 3.0) - (http://mail.python.org/pipermail/python-dev/2005-August/055116.html) +.. [#python-dev3] python-dev email (PEP, take 2: Exception + Reorganization for Python 3.0) + (http://mail.python.org/pipermail/python-dev/2005-August/055116.html) -.. [exceptions-stdlib] exceptions module - (http://www.python.org/doc/2.4.1/lib/module-exceptions.html) +.. [#exceptions-stdlib] exceptions module + (http://docs.python.org/lib/module-exceptions.html) -.. [python-dev-thread1] python-dev thread (Pre-PEP: Exception Reorganization for Python 3.0) - (http://mail.python.org/pipermail/python-dev/2005-July/055020.html - , - http://mail.python.org/pipermail/python-dev/2005-August/055065.html) +.. [#python-dev-thread1] python-dev thread (Pre-PEP: Exception + Reorganization for Python 3.0) + (http://mail.python.org/pipermail/python-dev/2005-July/055020.html, + http://mail.python.org/pipermail/python-dev/2005-August/055065.html) -.. [python-dev-thread2] python-dev thread (PEP, take 2: Exception Reorganization for Python 3.0) - (http://mail.python.org/pipermail/python-dev/2005-August/055103.html) +.. [#python-dev-thread2] python-dev thread (PEP, take 2: Exception + Reorganization for Python 3.0) + (http://mail.python.org/pipermail/python-dev/2005-August/055103.html) -.. [python-dev4] python-dev email (Pre-PEP: Exception Reorganization for Python 3.0) - (http://mail.python.org/pipermail/python-dev/2005-July/055019.html) +.. [#python-dev4] python-dev email (Pre-PEP: Exception Reorganization + for Python 3.0) + (http://mail.python.org/pipermail/python-dev/2005-July/055019.html) Copyright ========= This document has been placed in the public domain. + + +.. + Local Variables: + mode: indented-text + indent-tabs-mode: nil + sentence-end-double-space: t + fill-column: 70 + End: From loewis at users.sourceforge.net Fri Aug 5 09:26:35 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Fri, 05 Aug 2005 00:26:35 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.2,1.3 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26233 Modified Files: pep-0347.txt Log Message: Add copyright. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- pep-0347.txt 5 Aug 2005 00:16:49 -0000 1.2 +++ pep-0347.txt 5 Aug 2005 07:26:32 -0000 1.3 @@ -169,6 +169,11 @@ remains available. If desired, write access to the python and distutils modules can be disabled through a CVS commitinfo entry. +Copyright +--------- + +This document has been placed in the public domain. + .. Local Variables: From gregorykjohnson at users.sourceforge.net Fri Aug 5 18:34:48 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Fri, 05 Aug 2005 09:34:48 -0700 Subject: [Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.6, 1.7 test_mailbox.py, 1.5, 1.6 libmailbox.tex, 1.7, 1.8 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27444 Modified Files: mailbox.py test_mailbox.py libmailbox.tex Log Message: * Implement Babyl, except labels. Needs more tests. * Introduce _singlefileMailbox class and refactor much of _mboxMMDF into it for use by Babyl. * Make various tweaks and rearrangements in mbox, MMDF, and _mboxMMDF. Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- mailbox.py 3 Aug 2005 23:50:43 -0000 1.6 +++ mailbox.py 5 Aug 2005 16:34:45 -0000 1.7 @@ -12,6 +12,7 @@ import email.Message import email.Generator import rfc822 +import StringIO try: import fnctl except ImportError: @@ -190,8 +191,6 @@ else: raise TypeError, "Invalid message type" - - class Maildir(Mailbox): """A qmail-style Maildir mailbox.""" @@ -410,11 +409,11 @@ raise KeyError, "No message with key '%s'" % key -class _mboxMMDF(Mailbox): - """An mbox or MMDF mailbox.""" +class _singlefileMailbox(Mailbox): + """A single-file mailbox.""" def __init__(self, path, factory=None): - """Initialize an mbox or MMDF mailbox.""" + """Initialize a single-file mailbox.""" Mailbox.__init__(self, path, factory) try: f = file(self._path, 'r+') @@ -447,37 +446,9 @@ def __setitem__(self, key, message): """Replace the keyed message; raise KeyError if it doesn't exist.""" self._lookup(key) - start, stop = self._append_message(message) - self._toc[key] = (start, stop) + self._toc[key] = self._append_message(message) self._pending = True - def get_message(self, key): - start, stop = self._lookup(key) - self._assert_mtime() - self._file.seek(start) - from_line = self._file.readline() - msg = self._message_factory(self._file.read(stop - self._file.tell())) - msg.set_from(from_line[5:-1]) - return msg - - def get_string(self, key, from_=False): - """Return a string representation or raise a KeyError.""" - start, stop = self._lookup(key) - self._assert_mtime() - self._file.seek(start) - if not from_: - self._file.readline() - return self._file.read(stop - self._file.tell()) - - def get_file(self, key, from_=False): - """Return a file-like representation or raise a KeyError.""" - start, stop = self._lookup(key) - self._assert_mtime() - self._file.seek(start) - if not from_: - self._file.readline() - return _PartialFile(self._file, self._file.tell(), stop) - def iterkeys(self): """Return an iterator over keys.""" self._lookup() @@ -512,11 +483,12 @@ try: _lock_file(f, self._path, dot=False) try: + self._pre_mailbox_hook(f) new_toc = {} for key in sorted(self._toc.keys()): - start, stop = self._toc[key] + start, stop = self._toc[key][:2] self._file.seek(start) - self._pre_write_hook(f) + self._pre_message_hook(f) new_start = f.tell() while True: buffer = self._file.read( @@ -524,8 +496,9 @@ if buffer == '': break f.write(buffer) - new_toc[key] = (new_start, f.tell()) - self._post_write_hook(f) + new_toc[key] = (new_start, f.tell()) + \ + self._toc[key][2:] # XXX: Wrong! + self._post_message_hook(f) finally: _unlock_file(f, self._path) except: @@ -536,17 +509,30 @@ self._file.close() self._toc = new_toc self._file = f + self._file.flush() self._set_mtime() os.remove(self._path + '~') self._pending = False + def _pre_mailbox_hook(self, f): + """Called before writing the mailbox to file f.""" + return + + def _pre_message_hook(self, f): + """Called before writing each message to file f.""" + return + + def _post_message_hook(self, f): + """Called after writing each message to file f.""" + return + def close(self): """Flush and close the mailbox.""" self.flush() self._file.close() def _lookup(self, key=None): - """Return (start, stop) for given key, or raise a KeyError.""" + """Return (start, stop), possibly with more info, or raise KeyError.""" if self._toc is None: self._generate_toc() if key is not None: @@ -555,8 +541,64 @@ except KeyError: raise KeyError, "No message with key '%s'" % key + def _assert_mtime(self): + """Raise an exception if the file has been externally modified.""" + if self._mtime != os.fstat(self._file.fileno()).st_mtime: + raise Error, 'External modifications detected: use refresh()' + + def _set_mtime(self): + """Store the current mtime.""" + self._mtime = os.fstat(self._file.fileno()).st_mtime + def _append_message(self, message): - """Append message to mailbox and return (start, stop) offset.""" + """Append message to mailbox and return (start, stop, ...) offsets.""" + _lock_file(self._file, self._path) + try: + self._assert_mtime() + self._file.seek(0, 2) + self._pre_message_hook(self._file) + offsets = self._install_message(message) + self._post_message_hook(self._file) + self._file.flush() + self._set_mtime() + finally: + _unlock_file(self._file, self._path) + return offsets + + +class _mboxMMDF(_singlefileMailbox): + """An mbox or MMDF mailbox.""" + + def get_message(self, key): + """Return a Message representation or raise a KeyError.""" + start, stop = self._lookup(key) + self._assert_mtime() + self._file.seek(start) + from_line = self._file.readline() + msg = self._message_factory(self._file.read(stop - self._file.tell())) + msg.set_from(from_line[5:-1]) + return msg + + def get_string(self, key, from_=False): + """Return a string representation or raise a KeyError.""" + start, stop = self._lookup(key) + self._assert_mtime() + self._file.seek(start) + if not from_: + self._file.readline() + return self._file.read(stop - self._file.tell()) + + def get_file(self, key, from_=False): + """Return a file-like representation or raise a KeyError.""" + start, stop = self._lookup(key) + self._assert_mtime() + self._file.seek(start) + if not from_: + self._file.readline() + return _PartialFile(self._file, self._file.tell(), stop) + + def _install_message(self, message): + """Format a message and blindly write to self._file.""" from_line = None if isinstance(message, str) and message[:5] == 'From ': newline = message.find(os.linesep) @@ -569,36 +611,16 @@ elif isinstance(message, _mboxMMDFMessage): from_line = 'From ' + message.get_from() elif isinstance(message, email.Message.Message): - from_line = message.get_unixfrom() + from_line = message.get_unixfrom() # May be None. if from_line is None: from_line = 'From MAILER-DAEMON %s' % \ time.strftime('%a %b %d %H:%M:%S %Y', time.gmtime()) - _lock_file(self._file, self._path) - try: - self._assert_mtime() - self._file.seek(0, 2) - self._pre_write_hook(self._file) - start = self._file.tell() - self._file.write('%s%s' % (from_line, os.linesep)) - self._dump_message(message, self._file) - stop = self._file.tell() - self._post_write_hook(self._file) - self._file.flush() - self._set_mtime() - finally: - _unlock_file(self._file, self._path) + start = self._file.tell() + self._file.write('%s%s' % (from_line, os.linesep)) + self._dump_message(message, self._file) + stop = self._file.tell() return (start, stop) - def _assert_mtime(self): - """Raise an exception if the file has been externally modified.""" - if self._mtime != os.fstat(self._file.fileno()).st_mtime: - raise Error, 'External modifications detected: use refresh()' - - def _set_mtime(self): - """Store the current mtime.""" - self._mtime = os.fstat(self._file.fileno()).st_mtime - - class mbox(_mboxMMDF): """A classic mbox mailbox.""" @@ -608,34 +630,26 @@ self._message_factory = mboxMessage _mboxMMDF.__init__(self, path, factory) - def _pre_write_hook(self, f): - """Called by close before writing each message.""" + def _pre_message_hook(self, f): + """Called before writing each message to file f.""" if f.tell() != 0: f.write(os.linesep) - def _post_write_hook(self, f): - """Called by close after writing each message.""" - return - def _generate_toc(self): """Generate key-to-(start, stop) table of contents.""" starts, stops = [], [] - self._assert_mtime() self._file.seek(0) - prev_line = '' + self._assert_mtime() while True: - pos = self._file.tell() + line_pos = self._file.tell() line = self._file.readline() if line[:5] == 'From ': - starts.append(pos) - # The preceeding newline is part of the separator, e.g., - # "\nFrom .*\n", not part of the previous message. Ignore it. - if prev_line != '': - stops.append(pos - len(os.linesep)) + if len(stops) < len(starts): + stops.append(line_pos - len(os.linesep)) + starts.append(line_pos) elif line == '': - stops.append(pos) + stops.append(line_pos) break - prev_line = line self._toc = dict(enumerate(zip(starts, stops))) self._next_key = len(self._toc) @@ -648,31 +662,35 @@ self._message_factory = MMDFMessage _mboxMMDF.__init__(self, path, factory) - def _pre_write_hook(self, f): - """Called by close before writing each message.""" + def _pre_message_hook(self, f): + """Called before writing each message to file f.""" f.write('\001\001\001\001\n') - def _post_write_hook(self, f): - """Called by close after writing each message.""" + def _post_message_hook(self, f): + """Called after writing each message to file f.""" f.write('\n\001\001\001\001\n') def _generate_toc(self): """Generate key-to-(start, stop) table of contents.""" starts, stops = [], [] - self._assert_mtime() self._file.seek(0) + next_pos = 0 + self._assert_mtime() while True: + line_pos = next_pos line = self._file.readline() + next_pos = self._file.tell() if line[:4 + len(os.linesep)] == '\001\001\001\001' + os.linesep: - starts.append(self._file.tell()) + starts.append(next_pos) while True: - pos = self._file.tell() + line_pos = next_pos line = self._file.readline() + next_pos = self._file.tell() if line == '\001\001\001\001' + os.linesep: - stops.append(pos - len(os.linesep)) + stops.append(line_pos - len(os.linesep)) break elif line == '': - stops.append(pos) + stops.append(line_pos) break elif line == '': break @@ -912,6 +930,7 @@ os.rename(os.path.join(self._path, str(key)), os.path.join(self._path, str(prev + 1))) prev += 1 + self._next_key = prev + 1 if len(changes) == 0: return keys = self.keys() @@ -936,6 +955,160 @@ self.set_sequences(all_sequences) +class Babyl(_singlefileMailbox): + """An Rmail-style Babyl mailbox.""" + + def get_message(self, key): + """Return a Message representation or raise a KeyError.""" + start, stop = self._lookup(key) + self._assert_mtime() + self._file.seek(start) + self._file.readline() # XXX: parse this '1,' line for labels + original_headers = StringIO.StringIO() + while True: + line = self._file.readline() + if line == '*** EOOH ***' + os.linesep or line == '': + break + original_headers.write(line) + visible_headers = StringIO.StringIO() + while True: + line = self._file.readline() + if line == os.linesep or line == '': + break + visible_headers.write(line) + body = self._file.read(stop - self._file.tell()) + msg = BabylMessage(original_headers.getvalue() + body) + msg.set_visible(visible_headers.getvalue()) + return msg + + def get_string(self, key): + """Return a string representation or raise a KeyError.""" + start, stop = self._lookup(key) + self._assert_mtime() + self._file.seek(start) + self._file.readline() # Skip '1,' line. + original_headers = StringIO.StringIO() + while True: + line = self._file.readline() + if line == '*** EOOH ***' + os.linesep or line == '': + break + original_headers.write(line) + while True: + line = self._file.readline() + if line == os.linesep or line == '': + break + return original_headers.getvalue() + \ + self._file.read(stop - self._file.tell()) + + def get_file(self, key): + """Return a file-like representation or raise a KeyError.""" + return StringIO.StringIO(self.get_string(key)) + + def list_labels(self): + """Return a list of user-defined labels in the mailbox.""" + raise NotImplementedError, 'Method not yet implemented' + + def _generate_toc(self): + """Generate key-to-(start, stop, eooh, body) table of contents.""" + starts, stops = [], [] + self._file.seek(0) + next_pos = 0 + self._assert_mtime() + while True: + line_pos = next_pos + line = self._file.readline() + next_pos = self._file.tell() + if line == '\037\014' + os.linesep: + if len(stops) < len(starts): + stops.append(line_pos - len(os.linesep)) + starts.append(next_pos) + elif line == '\037' or line == '\037' + os.linesep: + if len(stops) < len(starts): + stops.append(line_pos - len(os.linesep)) + elif line == '': + stops.append(line_pos - len(os.linesep)) + break + self._toc = dict(enumerate(zip(starts, stops))) + self._next_key = len(self._toc) + + def _pre_mailbox_hook(self, f): + """Called before writing the mailbox to file f.""" + f.write('BABYL OPTIONS:%sVersion: 5%s\037' % (os.linesep, os.linesep)) + # XXX: write "Labels:" line too + + def _pre_message_hook(self, f): + """Called before writing each message to file f.""" + f.write('\014\n') + + def _post_message_hook(self, f): + """Called after writing each message to file f.""" + f.write('\n\037') + + def _install_message(self, message): + """Write message contents and return (start, stop, ...).""" + start = self._file.tell() + self._file.write('1,,\n') # XXX: check for labels and add them + if isinstance(message, email.Message.Message): + pseudofile = StringIO.StringIO() + ps_generator = email.Generator.Generator(pseudofile, False, 0) + ps_generator.flatten(message) + pseudofile.seek(0) + while True: + line = pseudofile.readline() + self._file.write(line) + if line == os.linesep or line == '': + break + self._file.write('*** EOOH ***' + os.linesep) + if isinstance(message, BabylMessage): + generator = email.Generator.Generator(self._file, False, 0) + generator.flatten(message.get_visible()) + else: + pseudofile.seek(0) + while True: + line = pseudofile.readline() + self._file.write(line) + if line == os.linesep or line == '': + break + while True: + buffer = pseudofile.read(4069) # Buffer size is arbitrary. + if buffer == '': + break + self._file.write(buffer) + elif isinstance(message, str): + body_start = message.find(os.linesep + os.linesep) + \ + 2 * len(os.linesep) + if body_start - 2 != -1: + self._file.write(message[:body_start]) + self._file.write('*** EOOH ***' + os.linesep) + self._file.write(message[:body_start]) + self._file.write(message[body_start:]) + else: + self._file.write('*** EOOH ***%s%s' % (os.linesep, os.linesep)) + self._file.write(message) + elif hasattr(message, 'readline'): + original_pos = message.tell() + first_pass = True + while True: + line = message.readline() + self._file.write(line) + if line == os.linesep or line == '': + self._file.write('*** EOOH ***' + os.linesep) + if first_pass: + first_pass = False + message.seek(original_pos) + else: + break + while True: + buffer = message.read(4096) # Buffer size is arbitrary. + if buffer == '': + break + self._file.write(buffer) + else: + raise TypeError, "Invalid message type" + stop = self._file.tell() + return (start, stop) + + class Message(email.Message.Message): """Message with mailbox-format-specific properties.""" Index: test_mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- test_mailbox.py 2 Aug 2005 21:46:13 -0000 1.5 +++ test_mailbox.py 5 Aug 2005 16:34:45 -0000 1.6 @@ -675,6 +675,11 @@ _factory = lambda self, path, factory=None: mailbox.MH(path, factory) +class TestBabyl(TestMailbox): + + _factory = lambda self, path, factory=None: mailbox.Babyl(path, factory) + + class TestMessage(TestBase): _factory = mailbox.Message # Overridden by subclasses to reuse tests @@ -1445,7 +1450,7 @@ def test_main(): - tests = (TestMaildir, TestMbox, TestMMDF, TestMH, TestMessage, + tests = (TestMaildir, TestMbox, TestMMDF, TestMH, TestBabyl, TestMessage, TestMaildirMessage, TestMboxMessage, TestMHMessage, TestBabylMessage, TestMMDFMessage, TestMessageConversion, TestProxyFile, TestPartialFile) Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- libmailbox.tex 3 Aug 2005 23:50:43 -0000 1.7 +++ libmailbox.tex 5 Aug 2005 16:34:45 -0000 1.8 @@ -506,19 +506,34 @@ \method{open()} function. \end{classdesc} -Babyl is a single-file mailbox format invented for use with the Rmail mail -reading application that ships with Emacs. A Babyl mailbox begins with a -so-called options section that indicates the format of the mailbox. Messages -follow the options section, with the beginning and end of each message -indicated by control characters. Each message in a Babyl mailbox has an -accompanying list of \dfn{labels}, or short strings that record extra -information about the message. +Babyl is a single-file mailbox format invented for the \program{Rmail} mail +reading application included with Emacs. A Babyl mailbox begins with an options +section that indicates the format of the mailbox and contains a list of +user-defined labels that appear in the mailbox. Messages follow the options +section. The beginning of a message is indicated by a line containing exactly +two control characters, namely Control-Underscore +(\character{\textbackslash037}) followed by Control-L +(\character{\textbackslash014}). The end of a message is indicated by the start +of the next message or, in the case of the last message, a line containing only +a Control-Underscore (\character{\textbackslash037}) character. Each message in +a Babyl mailbox has an accompanying list of \dfn{labels}, or short strings that +record extra information about the message. + +\class{Babyl} instances have all of the methods of \class{Mailbox} in addition +to the following: + +\begin{methoddesc}{list_labels}{} +Return a list of all user-defined labels in the mailbox. +\end{methoddesc} Some \class{Mailbox} methods implemented by \class{Babyl} deserve special remarks: \begin{methoddesc}{get_file}{key} -XXX +In Babyl mailboxes, the headers of a message are not stored contiguously with +the body of the message. To generate a file-like representation, they are +copied together into a \class{StringIO} instance (from the \module{StringIO} +module), which may be used like a file. \end{methoddesc} \begin{seealso} @@ -941,7 +956,7 @@ Each message in a Babyl mailbox has two sets of headers, original headers and visible headers. Visible headers are typically a subset of the original -headers reformatted to be more attractive. By default, \program{rmail} displays +headers reformatted to be more attractive. By default, \program{Rmail} displays only visible headers. \class{BabylMessage} uses the original headers because they are more complete, though the visible headers may be accessed explicitly if desired. From rhettinger at users.sourceforge.net Fri Aug 5 19:19:57 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri, 05 Aug 2005 10:19:57 -0700 Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.40,1.41 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3308/Objects Modified Files: setobject.c Log Message: * Improve a variable name: entry0 --> table. * Give set_lookkey_string() a fast alternate path when no dummy entries are present. * Have set_swap_bodies() reset the hash field to -1 whenever either of bodies is not a frozenset. Maintains the invariant of regular sets always having -1 in the hash field; otherwise, any mutation would make the hash value invalid. * Use an entry pointer to simplify the code in frozenset_hash(). Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.40 retrieving revision 1.41 diff -u -d -r1.40 -r1.41 --- setobject.c 5 Aug 2005 00:01:15 -0000 1.40 +++ setobject.c 5 Aug 2005 17:19:54 -0000 1.41 @@ -46,7 +46,7 @@ register unsigned int perturb; register setentry *freeslot; register unsigned int mask = so->mask; - setentry *entry0 = so->table; + setentry *table = so->table; register setentry *entry; register int restore_error; register int checked_error; @@ -55,7 +55,7 @@ PyObject *startkey; i = hash & mask; - entry = &entry0[i]; + entry = &table[i]; if (entry->key == NULL || entry->key == key) return entry; @@ -74,7 +74,7 @@ cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); if (cmp < 0) PyErr_Clear(); - if (entry0 == so->table && entry->key == startkey) { + if (table == so->table && entry->key == startkey) { if (cmp > 0) goto Done; } @@ -93,7 +93,7 @@ least likely outcome, so test for that last. */ for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { i = (i << 2) + i + perturb + 1; - entry = &entry0[i & mask]; + entry = &table[i & mask]; if (entry->key == NULL) { if (freeslot != NULL) entry = freeslot; @@ -114,7 +114,7 @@ cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); if (cmp < 0) PyErr_Clear(); - if (entry0 == so->table && entry->key == startkey) { + if (table == so->table && entry->key == startkey) { if (cmp > 0) break; } @@ -153,7 +153,7 @@ register unsigned int perturb; register setentry *freeslot; register unsigned int mask = so->mask; - setentry *entry0 = so->table; + setentry *table = so->table; register setentry *entry; /* Make sure this function doesn't have to handle non-string keys, @@ -165,31 +165,47 @@ return set_lookkey(so, key, hash); } i = hash & mask; - entry = &entry0[i]; + entry = &table[i]; if (entry->key == NULL || entry->key == key) return entry; - if (entry->key == dummy) - freeslot = entry; - else { - if (entry->hash == hash && _PyString_Eq(entry->key, key)) - return entry; - freeslot = NULL; - } + if (so->fill != so->used) { + if (entry->key == dummy) + freeslot = entry; + else { + if (entry->hash == hash && _PyString_Eq(entry->key, key)) + return entry; + freeslot = NULL; + } - /* In the loop, key == dummy is by far (factor of 100s) the - least likely outcome, so test for that last. */ - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { - i = (i << 2) + i + perturb + 1; - entry = &entry0[i & mask]; - if (entry->key == NULL) - return freeslot == NULL ? entry : freeslot; - if (entry->key == key - || (entry->hash == hash - && entry->key != dummy - && _PyString_Eq(entry->key, key))) + /* In the loop, key == dummy is by far (factor of 100s) the + least likely outcome, so test for that last. */ + for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + i = (i << 2) + i + perturb + 1; + entry = &table[i & mask]; + if (entry->key == NULL) + return freeslot == NULL ? entry : freeslot; + if (entry->key == key + || (entry->hash == hash + && entry->key != dummy + && _PyString_Eq(entry->key, key))) + return entry; + if (entry->key == dummy && freeslot == NULL) + freeslot = entry; + } + } else { + /* Simplified loop that can assume are no dummy entries */ + if (entry->hash == hash && _PyString_Eq(entry->key, key)) return entry; - if (entry->key == dummy && freeslot == NULL) - freeslot = entry; + for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + i = (i << 2) + i + perturb + 1; + entry = &table[i & mask]; + if (entry->key == NULL) + return entry; + if (entry->key == key + || (entry->hash == hash + && _PyString_Eq(entry->key, key))) + return entry; + } } } @@ -377,10 +393,8 @@ setentry small_copy[PySet_MINSIZE]; #ifdef Py_DEBUG int i, n; -#endif - assert (PyAnySet_Check(so)); -#ifdef Py_DEBUG + n = so->mask + 1; i = 0; #endif @@ -841,7 +855,13 @@ memcpy(b->smalltable, tab, sizeof(tab)); } - h = a->hash; a->hash = b->hash; b->hash = h; + if (PyType_IsSubtype(a->ob_type, &PyFrozenSet_Type) && + PyType_IsSubtype(b->ob_type, &PyFrozenSet_Type)) { + h = a->hash; a->hash = b->hash; b->hash = h; + } else { + a->hash = -1; + b->hash = -1; + } } static int @@ -1301,19 +1321,18 @@ frozenset_hash(PyObject *self) { PySetObject *so = (PySetObject *)self; - long hash = 1927868237L; - int i, j; + long h, hash = 1927868237L; + setentry *entry; + int i; if (so->hash != -1) return so->hash; hash *= set_len(self) + 1; - for (i=0, j=so->used ; j ; j--, i++) { - setentry *entry; - long h; - - while ((entry = &so->table[i])->key == NULL || entry->key==dummy) - i++; + entry = &so->table[0]; + for (i=so->used ; i ; entry++, i--) { + while (entry->key == NULL || entry->key==dummy) + entry++; /* Work to increase the bit dispersion for closely spaced hash values. The is important because some use cases have many combinations of a small number of elements with nearby From birkenfeld at users.sourceforge.net Fri Aug 5 23:02:00 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 05 Aug 2005 14:02:00 -0700 Subject: [Python-checkins] python/dist/src/Doc/lib libpoplib.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-serv19402/Doc/lib Modified Files: libpoplib.tex Log Message: bug [ 1252706 ] poplib list() docstring fix (and docs too) Index: libpoplib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libpoplib.tex,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- libpoplib.tex 11 Jan 2004 23:00:16 -0000 1.17 +++ libpoplib.tex 5 Aug 2005 21:01:57 -0000 1.18 @@ -108,8 +108,8 @@ \begin{methoddesc}{list}{\optional{which}} Request message list, result is in the form -\code{(\var{response}, ['mesg_num octets', ...])}. If \var{which} is -set, it is the message to list. +\code{(\var{response}, ['mesg_num octets', ...], \var{octets})}. +If \var{which} is set, it is the message to list. \end{methoddesc} \begin{methoddesc}{retr}{which} From birkenfeld at users.sourceforge.net Fri Aug 5 23:02:00 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 05 Aug 2005 14:02:00 -0700 Subject: [Python-checkins] python/dist/src/Lib poplib.py,1.23,1.24 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19402/Lib Modified Files: poplib.py Log Message: bug [ 1252706 ] poplib list() docstring fix (and docs too) Index: poplib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/poplib.py,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- poplib.py 12 Feb 2004 17:35:06 -0000 1.23 +++ poplib.py 5 Aug 2005 21:01:58 -0000 1.24 @@ -219,7 +219,7 @@ """Request listing, return result. Result without a message number argument is in form - ['response', ['mesg_num octets', ...]]. + ['response', ['mesg_num octets', ...], octets]. Result when a message number argument is given is a single response: the "scan listing" for that message. From birkenfeld at users.sourceforge.net Fri Aug 5 23:02:45 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 05 Aug 2005 14:02:45 -0700 Subject: [Python-checkins] python/dist/src/Doc/lib libpoplib.tex, 1.17, 1.17.4.1 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19559/dist/src/Doc/lib Modified Files: Tag: release24-maint libpoplib.tex Log Message: backport patch [ 1252706 ] poplib list() docstring fix (and docs too) Index: libpoplib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libpoplib.tex,v retrieving revision 1.17 retrieving revision 1.17.4.1 diff -u -d -r1.17 -r1.17.4.1 --- libpoplib.tex 11 Jan 2004 23:00:16 -0000 1.17 +++ libpoplib.tex 5 Aug 2005 21:02:43 -0000 1.17.4.1 @@ -108,8 +108,8 @@ \begin{methoddesc}{list}{\optional{which}} Request message list, result is in the form -\code{(\var{response}, ['mesg_num octets', ...])}. If \var{which} is -set, it is the message to list. +\code{(\var{response}, ['mesg_num octets', ...], \var{octets})}. +If \var{which} is set, it is the message to list. \end{methoddesc} \begin{methoddesc}{retr}{which} From birkenfeld at users.sourceforge.net Fri Aug 5 23:02:45 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 05 Aug 2005 14:02:45 -0700 Subject: [Python-checkins] python/dist/src/Lib poplib.py,1.23,1.23.4.1 Message-ID: Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19559/dist/src/Lib Modified Files: Tag: release24-maint poplib.py Log Message: backport patch [ 1252706 ] poplib list() docstring fix (and docs too) Index: poplib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/poplib.py,v retrieving revision 1.23 retrieving revision 1.23.4.1 diff -u -d -r1.23 -r1.23.4.1 --- poplib.py 12 Feb 2004 17:35:06 -0000 1.23 +++ poplib.py 5 Aug 2005 21:02:43 -0000 1.23.4.1 @@ -219,7 +219,7 @@ """Request listing, return result. Result without a message number argument is in form - ['response', ['mesg_num octets', ...]]. + ['response', ['mesg_num octets', ...], octets]. Result when a message number argument is given is a single response: the "scan listing" for that message. From pje at users.sourceforge.net Sat Aug 6 04:30:55 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Fri, 05 Aug 2005 19:30:55 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.56, 1.57 setuptools.txt, 1.24, 1.25 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4617 Modified Files: pkg_resources.py setuptools.txt Log Message: Performance boosts: don't create environment during require()/resolve() if all requirements can be met with items already in the working set. Don't eagerly determine whether a path is a directory. Avoid redundant path operations, etc. These changes dropped the test suite runtime from over 3.4 seconds to around .34 seconds. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.56 retrieving revision 1.57 diff -u -d -r1.56 -r1.57 --- pkg_resources.py 3 Aug 2005 13:18:50 -0000 1.56 +++ pkg_resources.py 6 Aug 2005 02:30:52 -0000 1.57 @@ -460,8 +460,6 @@ already-installed distribution; it should return a ``Distribution`` or ``None``. """ - if env is None: - env = AvailableDistributions(self.entries) requirements = list(requirements)[::-1] # set up the stack processed = {} # set of processed requirements @@ -477,6 +475,8 @@ dist = best.get(req.key) if dist is None: # Find the best distribution and add it to the map + if env is None: + env = AvailableDistributions(self.entries) dist = best[req.key] = env.best_match(req, self, installer) if dist is None: raise DistributionNotFound(req) # XXX put more info here @@ -1232,8 +1232,6 @@ """PEP 302 Importer that wraps Python's "normal" import algorithm""" def __init__(self, path=None): - if path is not None and not os.path.isdir(path): - raise ImportError self.path = path def find_module(self, fullname, path=None): @@ -1269,6 +1267,8 @@ return mod + + def get_importer(path_item): """Retrieve a PEP 302 "importer" for the given path item @@ -1357,9 +1357,8 @@ def find_on_path(importer, path_item, only=False): """Yield distributions accessible on a sys.path directory""" - if not os.path.exists(path_item): - return path_item = normalize_path(path_item) + if os.path.isdir(path_item): if path_item.lower().endswith('.egg'): # unpacked egg @@ -1370,10 +1369,10 @@ ) else: # scan for .egg and .egg-info in directory - for entry in os.listdir(path_item): - fullpath = os.path.join(path_item, entry) + for entry in os.listdir(path_item): lower = entry.lower() if lower.endswith('.egg-info'): + fullpath = os.path.join(path_item, entry) if os.path.isdir(fullpath): # development egg metadata = PathMetadata(path_item, fullpath) @@ -1382,16 +1381,17 @@ path_item, metadata, project_name=dist_name ) elif not only and lower.endswith('.egg'): - for dist in find_distributions(fullpath): + for dist in find_distributions(os.path.join(path_item, entry)): yield dist elif not only and lower.endswith('.egg-link'): - for line in file(fullpath): + for line in file(os.path.join(path_item, entry)): if not line.strip(): continue for item in find_distributions(line.rstrip()): yield item register_finder(ImpWrapper,find_on_path) + _namespace_handlers = {} _namespace_packages = {} Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- setuptools.txt 25 Jul 2005 03:12:51 -0000 1.24 +++ setuptools.txt 6 Aug 2005 02:30:52 -0000 1.25 @@ -1597,6 +1597,10 @@ containing ``setup.py``, not the highest revision number in the project. * Added ``eager_resources`` setup argument + + * Enhanced performance of ``require()`` and related operations when all + requirements are already in the working set, and enhanced performance of + directory scanning for distributions. * Fixed some problems using ``pkg_resources`` w/PEP 302 loaders other than ``zipimport``, and the previously-broken "eager resource" support. From nascheme at users.sourceforge.net Sat Aug 6 06:05:51 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Fri, 05 Aug 2005 21:05:51 -0700 Subject: [Python-checkins] python/nondist/peps pep-0349.txt,1.1,1.2 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16556 Modified Files: pep-0349.txt Log Message: Mention %s change in abstract. Fix bug in code (found by Osvaldo Santana Neto). Index: pep-0349.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0349.txt,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- pep-0349.txt 5 Aug 2005 02:59:00 -0000 1.1 +++ pep-0349.txt 6 Aug 2005 04:05:48 -0000 1.2 @@ -15,9 +15,12 @@ This PEP proposes the introduction of a new built-in function, text(), that provides a way of generating a string representation - of an object. This function would make it easier to write library - code that processes string data without forcing the use of a - particular string type. + of an object without forcing the result to be a particular string + type. In addition, the behavior %s format specifier would be + changed to call text() on the argument. These two changes would + make it easier to write library code that can be used by + applications that use only the str type and by others that also use + the unicode type. Rationale @@ -90,7 +93,7 @@ if isinstance(s, basestring): return s r = s.__str__() - if not isinstance(s, basestring): + if not isinstance(r, basestring): raise TypeError('__str__ returned non-string') return r From rhettinger at users.sourceforge.net Sat Aug 6 07:43:41 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri, 05 Aug 2005 22:43:41 -0700 Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.41,1.42 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29185 Modified Files: setobject.c Log Message: Factor away a redundant clear() function. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.41 retrieving revision 1.42 diff -u -d -r1.41 -r1.42 --- setobject.c 5 Aug 2005 17:19:54 -0000 1.41 +++ setobject.c 6 Aug 2005 05:43:39 -0000 1.42 @@ -384,7 +384,7 @@ return DISCARD_FOUND; } -static void +static int set_clear_internal(PySetObject *so) { setentry *entry, *table; @@ -406,7 +406,7 @@ /* This is delicate. During the process of clearing the set, * decrefs can cause the set to mutate. To avoid fatal confusion * (voice of experience), we have to make the set empty before - * clearing the slots, and never refer to anything via mp->ref while + * clearing the slots, and never refer to anything via so->ref while * clearing. */ fill = so->fill; @@ -445,6 +445,8 @@ if (table_is_malloced) PyMem_DEL(table); + so->hash = -1; + return 0; } /* @@ -1433,20 +1435,11 @@ set_clear(PySetObject *so) { set_clear_internal(so); - so->hash = -1; Py_RETURN_NONE; } PyDoc_STRVAR(clear_doc, "Remove all elements from this set."); -static int -set_tp_clear(PySetObject *so) -{ - set_clear_internal(so); - so->hash = -1; - return 0; -} - static PyObject * set_add(PySetObject *so, PyObject *key) { @@ -1727,7 +1720,7 @@ Py_TPFLAGS_BASETYPE, /* tp_flags */ set_doc, /* tp_doc */ (traverseproc)set_traverse, /* tp_traverse */ - (inquiry)set_tp_clear, /* tp_clear */ + (inquiry)set_clear_internal, /* tp_clear */ (richcmpfunc)set_richcompare, /* tp_richcompare */ offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */ (getiterfunc)set_iter, /* tp_iter */ @@ -1822,7 +1815,7 @@ Py_TPFLAGS_BASETYPE, /* tp_flags */ frozenset_doc, /* tp_doc */ (traverseproc)set_traverse, /* tp_traverse */ - 0, /* tp_clear */ + (inquiry)set_clear_internal, /* tp_clear */ (richcmpfunc)set_richcompare, /* tp_richcompare */ offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */ (getiterfunc)set_iter, /* tp_iter */ From pje at users.sourceforge.net Sat Aug 6 18:26:46 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 09:26:46 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command sdist.py, 1.4, 1.5 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17185/setuptools/command Modified Files: sdist.py Log Message: Fix wrongly including files that Subversion has marked deleted. Index: sdist.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/sdist.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- sdist.py 9 Jul 2005 04:21:22 -0000 1.4 +++ sdist.py 6 Aug 2005 16:26:43 -0000 1.5 @@ -84,7 +84,11 @@ (convert_path('CVS/Entries'), re_finder(re.compile(r"^\w?/([^/]+)/", re.M))), (convert_path('.svn/entries'), - re_finder(re.compile(r'name="([^"]+)"'), unescape)), + re_finder( + re.compile(r'name="([^"]+)"(?![^>]+deleted="true")', re.I), + unescape + ) + ), (convert_path('.svn/dir-props'), externals_finder), ] @@ -117,7 +121,3 @@ - - - - From pje at users.sourceforge.net Sat Aug 6 18:26:46 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 09:26:46 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools setuptools.txt, 1.25, 1.26 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17185 Modified Files: setuptools.txt Log Message: Fix wrongly including files that Subversion has marked deleted. Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- setuptools.txt 6 Aug 2005 02:30:52 -0000 1.25 +++ setuptools.txt 6 Aug 2005 16:26:44 -0000 1.26 @@ -1601,6 +1601,9 @@ * Enhanced performance of ``require()`` and related operations when all requirements are already in the working set, and enhanced performance of directory scanning for distributions. + + * The ``sdist`` command now recognizes Subversion "deleted file" entries and + does not include them in source distributions. * Fixed some problems using ``pkg_resources`` w/PEP 302 loaders other than ``zipimport``, and the previously-broken "eager resource" support. From pje at users.sourceforge.net Sat Aug 6 19:54:58 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 10:54:58 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.49, 1.50 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31364 Modified Files: EasyInstall.txt Log Message: Change dependency processing algorithm for less redundancy in the common case, and more thoroughness in the --always-copy case. Index: EasyInstall.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v retrieving revision 1.49 retrieving revision 1.50 diff -u -d -r1.49 -r1.50 --- EasyInstall.txt 25 Jul 2005 03:12:50 -0000 1.49 +++ EasyInstall.txt 6 Aug 2005 17:54:55 -0000 1.50 @@ -685,6 +685,11 @@ OS X upgrades (such as 10.4.1 to 10.4.2) do not cause eggs built with a previous OS version to become obsolete. + * easy_install's dependency processing algorithms have changed. When using + ``--always-copy``, it now ensures that dependencies are copied too. When + not using ``--always-copy``, it tries to use a single resolution loop, + rather than recursing. + * Fixed installing extra ``.pyc`` or ``.pyo`` files for scripts with ``.py`` extensions. From pje at users.sourceforge.net Sat Aug 6 19:54:57 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 10:54:57 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command easy_install.py, 1.18, 1.19 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31364/setuptools/command Modified Files: easy_install.py Log Message: Change dependency processing algorithm for less redundancy in the common case, and more thoroughness in the --always-copy case. Index: easy_install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/easy_install.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- easy_install.py 24 Jul 2005 05:51:07 -0000 1.18 +++ easy_install.py 6 Aug 2005 17:54:55 -0000 1.19 @@ -97,6 +97,7 @@ self.delete_conflicting = None self.ignore_conflicts_at_my_risk = None self.site_dirs = None + self.installed_projects = {} def delete_blockers(self, blockers): for filename in blockers: @@ -120,7 +121,6 @@ - def finalize_options(self): # If a non-default installation directory was specified, default the # script directory to match it. @@ -222,7 +222,7 @@ for link in self.find_links: self.package_index.scan_url(link) for spec in self.args: - self.easy_install(spec) + self.easy_install(spec, True) if self.record: from distutils import file_util self.execute( @@ -285,7 +285,7 @@ - def easy_install(self, spec): + def easy_install(self, spec, deps=False): tmpdir = tempfile.mkdtemp(prefix="easy_install-") download = None @@ -295,12 +295,12 @@ # It's a url, download it to tmpdir and process self.not_editable(spec) download = self.package_index.download(spec, tmpdir) - return self.install_item(None, download, tmpdir, True) + return self.install_item(None, download, tmpdir, deps, True) elif os.path.exists(spec): # Existing file or directory, just process it directly self.not_editable(spec) - return self.install_item(None, spec, tmpdir, True) + return self.install_item(None, spec, tmpdir, deps, True) else: spec = parse_requirement_arg(spec) @@ -314,7 +314,7 @@ "Could not find distribution for %r" % spec ) - return self.install_item(spec, download, tmpdir) + return self.install_item(spec, download, tmpdir, deps) finally: if os.path.exists(tmpdir): @@ -326,46 +326,87 @@ - def install_item(self, spec, download, tmpdir, install_needed=False): + def install_item(self, spec, download, tmpdir, deps, install_needed=False): + # Installation is also needed if file in tmpdir or is not an egg install_needed = install_needed or os.path.dirname(download) == tmpdir install_needed = install_needed or not download.endswith('.egg') + log.info("Processing %s", os.path.basename(download)) + if install_needed or self.always_copy: dists = self.install_eggs(spec, download, tmpdir) for dist in dists: - self.process_distribution(spec, dist) + self.process_distribution(spec, dist, deps) else: dists = [self.check_conflicts(self.egg_distribution(download))] - self.process_distribution(spec, dists[0], "Using") + self.process_distribution(spec, dists[0], deps, "Using") + if spec is not None: for dist in dists: if dist in spec: return dist - def process_distribution(self, requirement, dist, *info): + + + + + + + + + + + + + + + + + + + + + def process_distribution(self, requirement, dist, deps=True, *info): self.update_pth(dist) self.package_index.add(dist) self.local_index.add(dist) self.install_egg_scripts(dist) + self.installed_projects[dist.key] = dist log.warn(self.installation_report(dist, *info)) + if requirement is None: requirement = dist.as_requirement() - if dist in requirement: + + if dist not in requirement: + return + + if deps or self.always_copy: log.info("Processing dependencies for %s", requirement) - try: - WorkingSet(self.shadow_path).resolve( - [requirement], self.local_index, self.easy_install - ) - except DistributionNotFound, e: - raise DistutilsError( - "Could not find required distribution %s" % e.args - ) - except VersionConflict, e: - raise DistutilsError( - "Installed distribution %s conflicts with requirement %s" - % e.args - ) + else: + return + + if self.always_copy: + # Recursively install *all* dependencies + for req in dist.requires(requirement.extras): + if req.key not in self.installed_projects: + self.easy_install(req) + return + + try: + WorkingSet(self.shadow_path).resolve( + [requirement], self.local_index, self.easy_install + ) + except DistributionNotFound, e: + raise DistutilsError( + "Could not find required distribution %s" % e.args + ) + except VersionConflict, e: + raise DistutilsError( + "Installed distribution %s conflicts with requirement %s" + % e.args + ) + def install_egg_scripts(self, dist): if self.exclude_scripts or not dist.metadata_isdir('scripts'): From pje at users.sourceforge.net Sat Aug 6 19:57:08 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 10:57:08 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.57, 1.58 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31572 Modified Files: pkg_resources.py Log Message: Allow specifying an environment and/or installer for entry-point loading. This will be used by setuptools to automatically install eggs that may be needed as part of a build process, or to invoke a particular command. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.57 retrieving revision 1.58 diff -u -d -r1.57 -r1.58 --- pkg_resources.py 6 Aug 2005 02:30:52 -0000 1.57 +++ pkg_resources.py 6 Aug 2005 17:56:58 -0000 1.58 @@ -1622,8 +1622,8 @@ def __repr__(self): return "EntryPoint.parse(%r)" % str(self) - def load(self, require=True): - if require: self.require() + def load(self, require=True, env=None, installer=None): + if require: self.require(env, installer) entry = __import__(self.module_name, globals(),globals(), ['__name__']) for attr in self.attrs: try: @@ -1632,11 +1632,11 @@ raise ImportError("%r has no %r attribute" % (entry,attr)) return entry - def require(self): + def require(self, env=None, installer=None): if self.extras and not self.dist: raise UnknownExtra("Can't require() without a distribution", self) map(working_set.add, - working_set.resolve(self.dist.requires(self.extras))) + working_set.resolve(self.dist.requires(self.extras),env,installer)) #@classmethod def parse(cls, src, dist=None): From rhettinger at users.sourceforge.net Sat Aug 6 20:31:27 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 06 Aug 2005 11:31:27 -0700 Subject: [Python-checkins] python/dist/src/Include pyerrors.h,2.67,2.68 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5206/Include Modified Files: pyerrors.h Log Message: * set_new() doesn't need to zero the structure a second time after tp_alloc has already done the job. * Use a macro form of PyErr_Occurred() inside the set_lookkey() function. Index: pyerrors.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/pyerrors.h,v retrieving revision 2.67 retrieving revision 2.68 diff -u -d -r2.67 -r2.68 --- pyerrors.h 2 Aug 2005 00:46:42 -0000 2.67 +++ pyerrors.h 6 Aug 2005 18:31:24 -0000 2.68 @@ -15,6 +15,12 @@ PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **); PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *); +#ifdef Py_DEBUG +#define _PyErr_OCCURRED() PyErr_Occurred() +#else +#define _PyErr_OCCURRED() (_PyThreadState_Current->curexc_type) +#endif + /* Error testing and normalization */ PyAPI_FUNC(int) PyErr_GivenExceptionMatches(PyObject *, PyObject *); PyAPI_FUNC(int) PyErr_ExceptionMatches(PyObject *); From rhettinger at users.sourceforge.net Sat Aug 6 20:31:28 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 06 Aug 2005 11:31:28 -0700 Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.42,1.43 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5206/Objects Modified Files: setobject.c Log Message: * set_new() doesn't need to zero the structure a second time after tp_alloc has already done the job. * Use a macro form of PyErr_Occurred() inside the set_lookkey() function. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.42 retrieving revision 1.43 diff -u -d -r1.42 -r1.43 --- setobject.c 6 Aug 2005 05:43:39 -0000 1.42 +++ setobject.c 6 Aug 2005 18:31:24 -0000 1.43 @@ -66,7 +66,7 @@ if (entry->hash == hash) { /* error can't have been checked yet */ checked_error = 1; - if (PyErr_Occurred()) { + if (_PyErr_OCCURRED()) { restore_error = 1; PyErr_Fetch(&err_type, &err_value, &err_tb); } @@ -104,7 +104,7 @@ if (entry->hash == hash && entry->key != dummy) { if (!checked_error) { checked_error = 1; - if (PyErr_Occurred()) { + if (_PyErr_OCCURRED()) { restore_error = 1; PyErr_Fetch(&err_type, &err_value, &err_tb); @@ -720,7 +720,10 @@ if (so == NULL) return NULL; - EMPTY_TO_MINSIZE(so); + /* tp_alloc has already zeroed the structure */ + assert(so->table == NULL && so->fill == 0 && so->used == 0); + so->table = so->smalltable; + so->mask = PySet_MINSIZE - 1; so->lookup = set_lookkey_string; so->hash = -1; so->weakreflist = NULL; From pje at users.sourceforge.net Sat Aug 6 20:46:30 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 11:46:30 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command egg_info.py, 1.9, 1.10 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8052/setuptools/command Modified Files: egg_info.py Log Message: Enhanced setuptools infrastructure to support distutils extensions that can be plugged in at setup() time to define new setup() arguments or distutils commands. This allows modularization and reuse of distutils extensions in a way that was previously not possible. Index: egg_info.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/egg_info.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- egg_info.py 24 Jul 2005 22:47:06 -0000 1.9 +++ egg_info.py 6 Aug 2005 18:46:28 -0000 1.10 @@ -9,7 +9,6 @@ from distutils import log from pkg_resources import parse_requirements, safe_name, \ safe_version, yield_lines, EntryPoint -from setuptools.dist import iter_distribution_names class egg_info(Command): @@ -39,6 +38,7 @@ + def finalize_options (self): self.egg_name = safe_name(self.distribution.get_name()) self.egg_version = self.tagged_version() @@ -149,7 +149,7 @@ def write_toplevel_names(self): pkgs = dict.fromkeys( [k.split('.',1)[0] - for k in iter_distribution_names(self.distribution) + for k in self.distribution.iter_distribution_names() ] ) toplevel = os.path.join(self.egg_info, "top_level.txt") @@ -164,12 +164,8 @@ def write_or_delete_dist_arg(self, argname, filename=None): value = getattr(self.distribution, argname, None) - if value is None: - return - filename = filename or argname+'.txt' filename = os.path.join(self.egg_info,filename) - if value: log.info("writing %s", filename) if not self.dry_run: @@ -177,8 +173,12 @@ f.write('\n'.join(value)) f.write('\n') f.close() - elif os.path.exists(filename): + if value is None: + log.warn( + "%s not set in setup(), but %s exists", argname, filename + ) + return log.info("deleting %s", filename) if not self.dry_run: os.unlink(filename) From pje at users.sourceforge.net Sat Aug 6 20:46:30 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 11:46:30 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools.egg-info entry_points.txt, 1.1, 1.2 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8052/setuptools.egg-info Modified Files: entry_points.txt Log Message: Enhanced setuptools infrastructure to support distutils extensions that can be plugged in at setup() time to define new setup() arguments or distutils commands. This allows modularization and reuse of distutils extensions in a way that was previously not possible. Index: entry_points.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info/entry_points.txt,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- entry_points.txt 24 Jul 2005 22:47:06 -0000 1.1 +++ entry_points.txt 6 Aug 2005 18:46:28 -0000 1.2 @@ -1,13 +1,22 @@ +[distutils.setup_keywords] +entry_points = setuptools.dist:check_entry_points +extras_require = setuptools.dist:check_extras +namespace_packages = setuptools.dist:check_nsp +test_suite = setuptools.dist:check_test_suite +eager_resources = setuptools.dist:assert_string_list +zip_safe = setuptools.dist:assert_bool + [distutils.commands] rotate = setuptools.command.rotate:rotate develop = setuptools.command.develop:develop setopt = setuptools.command.setopt:setopt +build_py = setuptools.command.build_py:build_py saveopts = setuptools.command.saveopts:saveopts egg_info = setuptools.command.egg_info:egg_info -depends = setuptools.command.depends:depends +easy_install = setuptools.command.easy_install:easy_install upload = setuptools.command.upload:upload alias = setuptools.command.alias:alias -easy_install = setuptools.command.easy_install:easy_install +depends = setuptools.command.depends:depends bdist_egg = setuptools.command.bdist_egg:bdist_egg install = setuptools.command.install:install test = setuptools.command.test:test From pje at users.sourceforge.net Sat Aug 6 20:46:29 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 11:46:29 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools setup.py, 1.34, 1.35 setuptools.txt, 1.26, 1.27 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8052 Modified Files: setup.py setuptools.txt Log Message: Enhanced setuptools infrastructure to support distutils extensions that can be plugged in at setup() time to define new setup() arguments or distutils commands. This allows modularization and reuse of distutils extensions in a way that was previously not possible. Index: setup.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setup.py,v retrieving revision 1.34 retrieving revision 1.35 diff -u -d -r1.34 -r1.35 --- setup.py 31 Jul 2005 16:31:18 -0000 1.34 +++ setup.py 6 Aug 2005 18:46:27 -0000 1.35 @@ -46,8 +46,18 @@ "%(cmd)s = setuptools.command.%(cmd)s:%(cmd)s" % locals() for cmd in SETUP_COMMANDS if cmd!="build_py" or sys.version<"2.4" ], + "distutils.setup_keywords": [ + "eager_resources = setuptools.dist:assert_string_list", + "namespace_packages = setuptools.dist:check_nsp", + "extras_require = setuptools.dist:check_extras", + "entry_points = setuptools.dist:check_entry_points", + "test_suite = setuptools.dist:check_test_suite", + "zip_safe = setuptools.dist:assert_bool", + ] }, + setup_requires = ['setuptools>=0.6a0'], + classifiers = [f.strip() for f in """ Development Status :: 3 - Alpha Intended Audience :: Developers @@ -78,5 +88,3 @@ - - Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- setuptools.txt 6 Aug 2005 16:26:44 -0000 1.26 +++ setuptools.txt 6 Aug 2005 18:46:27 -0000 1.27 @@ -64,7 +64,11 @@ ========================= Download `ez_setup.py`_ and run it; this will download and install the -appropriate egg for your Python version. +appropriate egg for your Python version. (Note: if you are behind +an NTLM-based firewall that prevents Python programs from accessing the net +directly, you may wish to install and use the `APS proxy server +`_, which lets you get past such firewalls in the same +way that your web browser(s) do.) .. _ez_setup.py: `bootstrap module`_ @@ -80,6 +84,16 @@ You can then install it using the usual "setup.py install" incantation. +Note that ``setuptools`` *must* be installed as an egg directory; it will not +operate correctly otherwise. If you are unable to install to a valid +``site-packages`` directory (e.g. a "non-root install"), you will therefore +need to manually add the setuptools egg to your ``PYTHONPATH``. (You won't +need to do this for every egg you install, because the ``pkg_resources`` module +can automatically find eggs and add them to ``sys.path`` at runtime. It's just +that the ``setuptools`` egg contains ``pkg_resources`` and therefore has to +be manually bootstrapped if you can't install it to a ``site-packages`` +directory.) + Basic Use ========= @@ -175,6 +189,15 @@ installed to support those features. See the section below on `Declaring Dependencies`_ for details and examples of the format of this argument. +``setup_requires`` + A string or list of strings specifying what other distributions need to + be present in order for the *setup script* to run. ``setuptools`` will + attempt to obtain these (even going so far as to download them using + ``EasyInstall``) before processing the rest of the setup script or commands. + This argument is needed if you are using distutils extensions as part of + your build process; for example, extensions that process setup() arguments + and turn them into EGG-INFO metadata files. + ``namespace_packages`` A list of strings naming the project's "namespace packages". A namespace package is a package that may be split across multiple project @@ -1517,19 +1540,28 @@ Extending and Reusing ``setuptools`` ------------------------------------ -Sorry, this section isn't written yet, and neither is a lot of what's below -this point, except for the change log. You might want to `subscribe to changes -in this page `_ to see when new documentation is -added or updated. +Creating ``distutils`` Extensions +================================= + +It can be hard to add new commands or setup arguments to the distutils. But +the ``setuptools`` package makes it a bit easier, by allowing you to distribute +a distutils extension as a separate project, and then have projects that need +the extension just refer to it in their ``setup_requires`` argument. + +With ``setuptools``, your distutils extension projects can hook in new +commands and ``setup()`` arguments just by defining "entry points". These +are mappings from command or argument names to a specification of where to +import a handler from. (See the section on `Dynamic Discovery of Services and +Plugins`_ above for some more background on entry points.) Adding Commands -=============== +--------------- -You can create add-on packages that extend setuptools with additional commands -by defining entry points in the ``distutils.commands`` group. For example, if -you wanted to add a ``foo`` command, you might add something like this to your -setup script:: +You can add new ``setup`` commands by defining entry points in the +``distutils.commands`` group. For example, if you wanted to add a ``foo`` +command, you might add something like this to your distutils extension +project's setup script:: setup( # ... @@ -1540,8 +1572,8 @@ }, ) -Assuming, of course, that the ``foo`` class in ``mypackage.some_module`` is -a ``setuptools.Command`` subclass. +(Assuming, of course, that the ``foo`` class in ``mypackage.some_module`` is +a ``setuptools.Command`` subclass.) Once a project containing such entry points has been activated on ``sys.path``, (e.g. by running "install" or "develop" with a site-packages installation @@ -1550,18 +1582,76 @@ to monkeypatch the ``distutils.command`` package to install your commands; ``setuptools`` automatically adds a wrapper to the distutils to search for entry points in the active distributions on ``sys.path``. In fact, this is -how setuptools' own commands are installed: the setuptools setup script defines -entry points for them. +how setuptools' own commands are installed: the setuptools project's setup +script defines entry points for them! + + +Adding ``setup()`` Arguments +---------------------------- + +Sometimes, your commands may need additional arguments to the ``setup()`` +script. You can enable this by defining entry points in the +``distutils.setup_keywords`` group. For example, if you wanted a ``setup()`` +argument called ``bar_baz``, you might add something like this to your +distutils extension project's setup script:: + + setup( + # ... + entry_points = { + "distutils.commands": [ + "foo = mypackage.some_module:foo", + ], + "distutils.setup_keywords": [ + "bar_baz = mypackage.some_module:validate_bar_baz", + ], + }, + ) + +The idea here is that the entry point defines a function that will be called +to validate the ``setup()`` argument, if it's supplied. The ``Distribution`` +object will have the initial value of the attribute set to ``None``, and the +validation function will only be called if the ``setup()`` call sets it to +a non-None value. Here's an example validation function:: + + def assert_bool(dist, attr, value): + """Verify that value is True, False, 0, or 1""" + if bool(value) != value: + raise DistutilsSetupError( + "%r must be a boolean value (got %r)" % (attr,value) + ) + +Your function should accept three arguments: the ``Distribution`` object, +the attribute name, and the attribute value. It should raise a +``DistutilsSetupError`` (from the ``distutils.error`` module) if the argument +is invalid. Remember, your function will only be called with non-None values, +and the default value of arguments defined this way is always None. So, your +commands should always be prepared for the possibility that the attribute will +be ``None`` when they access it later. + +If more than one active distribution defines an entry point for the same +``setup()`` argument, *all* of them will be called. This allows multiple +distutils extensions to define a common argument, as long as they agree on +what values of that argument are valid. + +Also note that as with commands, it is not necessary to subclass or monkeypatch +the distutils ``Distribution`` class in order to add your arguments; it is +sufficient to define the entry points in your extension, as long as the setup +script lists your extension in its ``setup_requires`` argument. Subclassing ``Command`` ----------------------- +Sorry, this section isn't written yet, and neither is a lot of what's below +this point, except for the change log. You might want to `subscribe to changes +in this page `_ to see when new documentation is +added or updated. + XXX -Utility Modules -=============== +Reusing ``setuptools`` Code +=========================== ``ez_setup`` ------------ @@ -1604,14 +1694,24 @@ * The ``sdist`` command now recognizes Subversion "deleted file" entries and does not include them in source distributions. - + + * ``setuptools`` now embeds itself more thoroughly into the distutils, so that + other distutils extensions (e.g. py2exe, py2app) will subclass setuptools' + versions of things, rather than the native distutils ones. + * Fixed some problems using ``pkg_resources`` w/PEP 302 loaders other than ``zipimport``, and the previously-broken "eager resource" support. * Fixed ``pkg_resources.resource_exists()`` not working correctly, along with some other resource API bugs. - * Added ``entry_points`` argument to ``setup()`` + * Added ``entry_points`` and ``setup_requires`` arguments to ``setup()``; + ``setup_requires`` allows you to automatically find and download packages + that are needed in order to *build* your project (as opposed to running it). + + * ``setuptools`` now finds its commands and ``setup()`` argument validators + using entry points, so that they are extensible by third-party packages. + See `Creating distutils Extensions`_ above for more details. * Many ``pkg_resources`` API changes and enhancements: From pje at users.sourceforge.net Sat Aug 6 20:46:30 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 11:46:30 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools __init__.py, 1.21, 1.22 dist.py, 1.17, 1.18 extension.py, 1.1, 1.2 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8052/setuptools Modified Files: __init__.py dist.py extension.py Log Message: Enhanced setuptools infrastructure to support distutils extensions that can be plugged in at setup() time to define new setup() arguments or distutils commands. This allows modularization and reuse of distutils extensions in a way that was previously not possible. Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/__init__.py,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- __init__.py 18 Jul 2005 02:06:15 -0000 1.21 +++ __init__.py 6 Aug 2005 18:46:27 -0000 1.22 @@ -1,6 +1,6 @@ """Extensions to the 'distutils' for large or complex distributions""" +from setuptools.dist import Distribution, Feature, _get_unpatched import distutils.core, setuptools.command -from setuptools.dist import Distribution, Feature from setuptools.extension import Extension from setuptools.depends import Require from distutils.core import Command as _Command @@ -39,17 +39,9 @@ out = [item for item in out if not fnmatchcase(item,pat)] return out -def setup(**attrs): - """Do package setup - - This function takes the same arguments as 'distutils.core.setup()', except - that the default distribution class is 'setuptools.dist.Distribution'. See - that class' documentation for details on the new keyword arguments that it - makes available via this function. - """ - attrs.setdefault("distclass",Distribution) - return distutils.core.setup(**attrs) +setup = distutils.core.setup +_Command = _get_unpatched(_Command) class Command(_Command): __doc__ = _Command.__doc__ @@ -68,6 +60,14 @@ setattr(cmd,k,v) # update command with keywords return cmd +import distutils.core +distutils.core.Command = Command # we can't patch distutils.cmd, alas + + + + + + Index: dist.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/dist.py,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- dist.py 25 Jul 2005 03:12:51 -0000 1.17 +++ dist.py 6 Aug 2005 18:46:27 -0000 1.18 @@ -9,36 +9,118 @@ from setuptools.command.install_lib import install_lib from distutils.errors import DistutilsOptionError, DistutilsPlatformError from distutils.errors import DistutilsSetupError -import setuptools, pkg_resources - -def get_command_class(self, command): - """Pluggable version of get_command_class()""" - if command in self.cmdclass: - return self.cmdclass[command] +import setuptools, pkg_resources, distutils.core, distutils.dist, distutils.cmd +import os - for ep in pkg_resources.iter_entry_points('distutils.commands',command): - self.cmdclass[command] = cmdclass = ep.load() - return cmdclass - else: - return _old_get_command_class(self, command) +def _get_unpatched(cls): + """Protect against re-patching the distutils if reloaded -def print_commands(self): - for ep in pkg_resources.iter_entry_points('distutils.commands'): - if ep.name not in self.cmdclass: - cmdclass = ep.load(False) # don't require extras, we're not running - self.cmdclass[ep.name] = cmdclass - return _old_print_commands(self) + Also ensures that no other distutils extension monkeypatched the distutils + first. + """ + while cls.__module__.startswith('setuptools'): + cls, = cls.__bases__ + if not cls.__module__.startswith('distutils'): + raise AssertionError( + "distutils has already been patched by %r" % cls + ) + return cls -for meth in 'print_commands', 'get_command_class': - if getattr(_Distribution,meth).im_func.func_globals is not globals(): - globals()['_old_'+meth] = getattr(_Distribution,meth) - setattr(_Distribution, meth, globals()[meth]) +_Distribution = _get_unpatched(_Distribution) sequence = tuple, list + + + + + + +def assert_string_list(dist, attr, value): + """Verify that value is a string list or None""" + try: + assert ''.join(value)!=value + except (TypeError,ValueError,AttributeError,AssertionError): + raise DistutilsSetupError( + "%r must be a list of strings (got %r)" % (attr,value) + ) + +def check_nsp(dist, attr, value): + """Verify that namespace packages are valid""" + assert_string_list(dist,attr,value) + + for nsp in value: + for name in dist.iter_distribution_names(): + if name.startswith(nsp+'.'): break + else: + raise DistutilsSetupError( + "Distribution contains no modules or packages for " + + "namespace package %r" % nsp + ) + +def check_extras(dist, attr, value): + """Verify that extras_require mapping is valid""" + try: + for k,v in value.items(): + list(pkg_resources.parse_requirements(v)) + except (TypeError,ValueError,AttributeError): + raise DistutilsSetupError( + "'extras_require' must be a dictionary whose values are " + "strings or lists of strings containing valid project/version " + "requirement specifiers." + ) + +def assert_bool(dist, attr, value): + """Verify that value is True, False, 0, or 1""" + if bool(value) != value: + raise DistutilsSetupError( + "%r must be a boolean value (got %r)" % (attr,value) + ) + +def check_install_requires(dist, attr, value): + """Verify that install_requires is a valid requirements list""" + try: + list(pkg_resources.parse_requirements(value)) + except (TypeError,ValueError): + raise DistutilsSetupError( + "'install_requires' must be a string or list of strings " + "containing valid project/version requirement specifiers" + ) + +def check_entry_points(dist, attr, value): + """Verify that entry_points map is parseable""" + try: + pkg_resources.EntryPoint.parse_map(value) + except ValueError, e: + raise DistutilsSetupError(e) + + +def check_test_suite(dist, attr, value): + if not isinstance(value,basestring): + raise DistutilsSetupError("test_suite must be a string") + + + + + + + + + + + + + + + + + + + + class Distribution(_Distribution): """Distribution with support for features, tests, and package data @@ -125,16 +207,19 @@ have_package_data = hasattr(self, "package_data") if not have_package_data: self.package_data = {} + self.features = {} - self.test_suite = None self.requires = [] - self.install_requires = [] - self.extras_require = {} self.dist_files = [] - self.zip_safe = None - self.namespace_packages = None - self.eager_resources = None - self.entry_points = None + + if attrs and 'setup_requires' in attrs: + # Make sure we have any eggs needed to interpret 'attrs' + self.fetch_build_eggs(attrs.pop('setup_requires')) + + for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): + if not hasattr(self,ep.name): + setattr(self,ep.name,None) + _Distribution.__init__(self,attrs) @@ -145,20 +230,17 @@ self._finalize_features() return result - def _feature_attrname(self,name): """Convert feature name to corresponding option attribute name""" return 'with_'+name.replace('-','_') - - - - - - - - - + def fetch_build_eggs(self, requires): + """Resolve pre-setup requirements""" + from pkg_resources import working_set, parse_requirements + for dist in working_set.resolve( + parse_requirements(requires), installer=self.fetch_build_egg + ): + working_set.add(dist) @@ -174,49 +256,34 @@ "setuptools. Please remove it from your setup script." ) - try: - list(pkg_resources.parse_requirements(self.install_requires)) - except (TypeError,ValueError): - raise DistutilsSetupError( - "'install_requires' must be a string or list of strings " - "containing valid project/version requirement specifiers" - ) + for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): + value = getattr(self,ep.name,None) + if value is not None: + ep.require(installer=self.fetch_build_egg) + ep.load()(self, ep.name, value) + + def fetch_build_egg(self, req): + """Fetch an egg needed for building""" try: - for k,v in self.extras_require.items(): - list(pkg_resources.parse_requirements(v)) - except (TypeError,ValueError,AttributeError): - raise DistutilsSetupError( - "'extras_require' must be a dictionary whose values are " - "strings or lists of strings containing valid project/version " - "requirement specifiers." + cmd = self._egg_fetcher + except AttributeError: + from setuptools.command.easy_install import easy_install + cmd = easy_install( + self.__class__({'script_args':['easy_install']}), + args="x", install_dir=os.curdir, exclude_scripts=True, + always_copy=False, build_directory=None, editable=False, + upgrade=False ) + cmd.ensure_finalized() + cmd.zip_ok = None # override any setup.cfg setting for these + cmd.build_directory = None + self._egg_fetcher = cmd - for attr in 'namespace_packages','eager_resources': - value = getattr(self,attr,None) - if value is not None: - try: - assert ''.join(value)!=value - except (TypeError,ValueError,AttributeError,AssertionError): - raise DistutilsSetupError( - "%r must be a list of strings (got %r)" % (attr,value) - ) + return cmd.easy_install(req) - for nsp in self.namespace_packages or (): - for name in iter_distribution_names(self): - if name.startswith(nsp+'.'): break - else: - raise DistutilsSetupError( - "Distribution contains no modules or packages for " + - "namespace package %r" % nsp - ) - if self.entry_points is not None: - try: - pkg_resources.EntryPoint.parse_map(self.entry_points) - except ValueError, e: - raise DistutilsSetupError(e) def _set_global_opts_from_features(self): """Add --with-X/--without-X options based on optional features""" @@ -244,22 +311,7 @@ - def _finalize_features(self): - """Add/remove features and resolve dependencies between them""" - # First, flag all the enabled items (and thus their dependencies) - for name,feature in self.features.items(): - enabled = self.feature_is_included(name) - if enabled or (enabled is None and feature.include_by_default()): - feature.include_in(self) - self._set_feature(name,1) - - # Then disable the rest, so that off-by-default features don't - # get flagged as errors when they're required by an enabled feature - for name,feature in self.features.items(): - if not self.feature_is_included(name): - feature.exclude_from(self) - self._set_feature(name,0) @@ -274,12 +326,42 @@ + def _finalize_features(self): + """Add/remove features and resolve dependencies between them""" + # First, flag all the enabled items (and thus their dependencies) + for name,feature in self.features.items(): + enabled = self.feature_is_included(name) + if enabled or (enabled is None and feature.include_by_default()): + feature.include_in(self) + self._set_feature(name,1) + # Then disable the rest, so that off-by-default features don't + # get flagged as errors when they're required by an enabled feature + for name,feature in self.features.items(): + if not self.feature_is_included(name): + feature.exclude_from(self) + self._set_feature(name,0) + def get_command_class(self, command): + """Pluggable version of get_command_class()""" + if command in self.cmdclass: + return self.cmdclass[command] + for ep in pkg_resources.iter_entry_points('distutils.commands',command): + ep.require(installer=self.fetch_build_egg) + self.cmdclass[command] = cmdclass = ep.load() + return cmdclass + else: + return _Distribution.get_command_class(self, command) + def print_commands(self): + for ep in pkg_resources.iter_entry_points('distutils.commands'): + if ep.name not in self.cmdclass: + cmdclass = ep.load(False) # don't require extras, we're not running + self.cmdclass[ep.name] = cmdclass + return _Distribution.print_commands(self) @@ -572,25 +654,25 @@ return d -def iter_distribution_names(distribution): - """Yield all packages, modules, and extensions declared by distribution""" - - for pkg in distribution.packages or (): - yield pkg - - for module in distribution.py_modules or (): - yield module - - for ext in distribution.ext_modules or (): - if isinstance(ext,tuple): - name,buildinfo = ext - yield name - else: - yield ext.name + def iter_distribution_names(self): + """Yield all packages, modules, and extension names in distribution""" + for pkg in self.packages or (): + yield pkg + for module in self.py_modules or (): + yield module + for ext in self.ext_modules or (): + if isinstance(ext,tuple): + name,buildinfo = ext + yield name + else: + yield ext.name +# Install it throughout the distutils +for module in distutils.dist, distutils.core, distutils.cmd: + module.Distribution = Distribution Index: extension.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/extension.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- extension.py 19 Mar 2004 20:53:14 -0000 1.1 +++ extension.py 6 Aug 2005 18:46:27 -0000 1.2 @@ -7,6 +7,9 @@ # Pyrex isn't around, so fix up the sources + from dist import _get_unpatched + _Extension = _get_unpatched(_Extension) + class Extension(_Extension): """Extension that uses '.c' files in place of '.pyx' files""" @@ -21,7 +24,14 @@ sources.append(s) self.sources = sources + import sys, distutils.core, distutils.extension + distutils.core.Extension = Extension + distutils.extension.Extension = Extension + if 'distutils.command.build_ext' in sys.modules: + sys.modules['distutils.command.build_ext'].Extension = Extension + else: # Pyrex is here, just use regular extension type Extension = _Extension + From rhettinger at users.sourceforge.net Sat Aug 6 20:57:21 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 06 Aug 2005 11:57:21 -0700 Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.43,1.44 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10101 Modified Files: setobject.c Log Message: * Removed checked_error flag which no longer provides any benefit. * Have issubset() control its own loop instead of using set_next_internal(). Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.43 retrieving revision 1.44 diff -u -d -r1.43 -r1.44 --- setobject.c 6 Aug 2005 18:31:24 -0000 1.43 +++ setobject.c 6 Aug 2005 18:57:13 -0000 1.44 @@ -49,7 +49,6 @@ setentry *table = so->table; register setentry *entry; register int restore_error; - register int checked_error; register int cmp; PyObject *err_type, *err_value, *err_tb; PyObject *startkey; @@ -59,13 +58,11 @@ if (entry->key == NULL || entry->key == key) return entry; - restore_error = checked_error = 0; + restore_error = 0; if (entry->key == dummy) freeslot = entry; else { if (entry->hash == hash) { - /* error can't have been checked yet */ - checked_error = 1; if (_PyErr_OCCURRED()) { restore_error = 1; PyErr_Fetch(&err_type, &err_value, &err_tb); @@ -102,13 +99,10 @@ if (entry->key == key) break; if (entry->hash == hash && entry->key != dummy) { - if (!checked_error) { - checked_error = 1; - if (_PyErr_OCCURRED()) { - restore_error = 1; - PyErr_Fetch(&err_type, &err_value, - &err_tb); - } + if (_PyErr_OCCURRED()) { + restore_error = 1; + PyErr_Fetch(&err_type, &err_value, + &err_tb); } startkey = entry->key; cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -1267,8 +1261,8 @@ set_issubset(PySetObject *so, PyObject *other) { PyObject *tmp, *result; - PyObject *key; - int pos = 0; + register setentry *entry; + register int i; if (!PyAnySet_Check(other)) { tmp = make_new_set(&PySet_Type, other); @@ -1281,8 +1275,11 @@ if (set_len((PyObject *)so) > set_len(other)) Py_RETURN_FALSE; - while (set_next_internal(so, &pos, &key)) { - if (!set_contains_internal((PySetObject *)other, key)) + entry = &so->table[0]; + for (i=so->used ; i ; entry++, i--) { + while (entry->key == NULL || entry->key==dummy) + entry++; + if (!set_contains_internal((PySetObject *)other, entry->key)) Py_RETURN_FALSE; } Py_RETURN_TRUE; From pje at users.sourceforge.net Sat Aug 6 21:29:51 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 12:29:51 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools setuptools.txt, 1.27, 1.28 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15840 Modified Files: setuptools.txt Log Message: Got rid of the no-longer meaningful "depends" command. Consolidated the replacement of the "install" command so that installation is always via easy_install, but doesn't use the previous kludgy intereception technique. Allow ``extra_path`` to be set, but ignore it, so that when easy_install wraps a package that uses it, there won't be any confusion as to the desired installation location. Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- setuptools.txt 6 Aug 2005 18:46:27 -0000 1.27 +++ setuptools.txt 6 Aug 2005 19:29:48 -0000 1.28 @@ -1713,6 +1713,10 @@ using entry points, so that they are extensible by third-party packages. See `Creating distutils Extensions`_ above for more details. + * The vestigial ``depends`` command has been removed. It was never finished + or documented, and never would have worked without EasyInstall - which it + pre-dated and was never compatible with. + * Many ``pkg_resources`` API changes and enhancements: * Added ``EntryPoint``, ``get_entry_map``, ``load_entry_point``, and @@ -1918,9 +1922,7 @@ see the ``setuptools.dist.Distribution`` class. * Setup scripts using setuptools now always install using ``easy_install`` - internally, for ease of uninstallation and upgrading. Note: you *must* - remove any ``extra_path`` argument from your setup script, as it conflicts - with the proper functioning of the ``easy_install`` command. + internally, for ease of uninstallation and upgrading. * ``pkg_resources.AvailableDistributions.resolve()`` and related methods now accept an ``installer`` argument: a callable taking one argument, a From pje at users.sourceforge.net Sat Aug 6 21:29:51 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 12:29:51 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools dist.py, 1.18, 1.19 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15840/setuptools Modified Files: dist.py Log Message: Got rid of the no-longer meaningful "depends" command. Consolidated the replacement of the "install" command so that installation is always via easy_install, but doesn't use the previous kludgy intereception technique. Allow ``extra_path`` to be set, but ignore it, so that when easy_install wraps a package that uses it, there won't be any confusion as to the desired installation location. Index: dist.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/dist.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- dist.py 6 Aug 2005 18:46:27 -0000 1.18 +++ dist.py 6 Aug 2005 19:29:49 -0000 1.19 @@ -207,9 +207,8 @@ have_package_data = hasattr(self, "package_data") if not have_package_data: self.package_data = {} - + self.requires = [] # XXX self.features = {} - self.requires = [] self.dist_files = [] if attrs and 'setup_requires' in attrs: @@ -244,18 +243,13 @@ + def finalize_options(self): _Distribution.finalize_options(self) if self.features: self._set_global_opts_from_features() - if self.extra_path: - raise DistutilsSetupError( - "The 'extra_path' parameter is not needed when using " - "setuptools. Please remove it from your setup script." - ) - for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): value = getattr(self,ep.name,None) if value is not None: @@ -285,6 +279,12 @@ + + + + + + def _set_global_opts_from_features(self): """Add --with-X/--without-X options based on optional features""" @@ -572,47 +572,6 @@ - def has_dependencies(self): - return not not self.requires - - def run_commands(self): - for cmd in self.commands: - if cmd=='install' and not cmd in self.have_run: - self.install_eggs() - else: - self.run_command(cmd) - - def install_eggs(self): - from setuptools.command.easy_install import easy_install - cmd = easy_install(self, args="x", ignore_conflicts_at_my_risk=1) - cmd.ensure_finalized() # finalize before bdist_egg munges install cmd - - self.run_command('bdist_egg') - args = [self.get_command_obj('bdist_egg').egg_output] - - if setuptools.bootstrap_install_from: - # Bootstrap self-installation of setuptools - args.insert(0, setuptools.bootstrap_install_from) - - cmd.args = args - cmd.run() - self.have_run['install'] = 1 - setuptools.bootstrap_install_from = None - - - - - - - - - - - - - - - def get_cmdline_options(self): """Return a '{cmd: {opt:val}}' map of all command-line options From pje at users.sourceforge.net Sat Aug 6 21:29:51 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 12:29:51 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command __init__.py, 1.7, 1.8 install.py, 1.2, 1.3 depends.py, 1.4, NONE Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15840/setuptools/command Modified Files: __init__.py install.py Removed Files: depends.py Log Message: Got rid of the no-longer meaningful "depends" command. Consolidated the replacement of the "install" command so that installation is always via easy_install, but doesn't use the previous kludgy intereception technique. Allow ``extra_path`` to be set, but ignore it, so that when easy_install wraps a package that uses it, there won't be any confusion as to the desired installation location. Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/__init__.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- __init__.py 24 Jul 2005 22:47:06 -0000 1.7 +++ __init__.py 6 Aug 2005 19:29:49 -0000 1.8 @@ -1,5 +1,5 @@ __all__ = [ - 'alias', 'bdist_egg', 'build_ext', 'build_py', 'depends', 'develop', + 'alias', 'bdist_egg', 'build_ext', 'build_py', 'develop', 'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts', 'sdist', 'setopt', 'test', 'upload', ] Index: install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/install.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- install.py 5 Apr 2004 20:02:45 -0000 1.2 +++ install.py 6 Aug 2005 19:29:49 -0000 1.3 @@ -1,9 +1,31 @@ +import setuptools from distutils.command.install import install as _install class install(_install): """Build dependencies before installation""" - def has_dependencies(self): - return self.distribution.has_dependencies() + def handle_extra_path(self): + # We always ignore extra_path, because we always install eggs + # (you can always use install_* commands directly if needed) + self.path_file = None + self.extra_dirs = '' + + def run(self): + from setuptools.command.easy_install import easy_install + cmd = easy_install( + self.distribution, args="x", ignore_conflicts_at_my_risk=1 + ) + cmd.ensure_finalized() # finalize before bdist_egg munges install cmd + + self.run_command('bdist_egg') + args = [self.distribution.get_command_obj('bdist_egg').egg_output] + + if setuptools.bootstrap_install_from: + # Bootstrap self-installation of setuptools + args.insert(0, setuptools.bootstrap_install_from) + + cmd.args = args + cmd.run() + setuptools.bootstrap_install_from = None + - sub_commands = [('depends', has_dependencies)] + _install.sub_commands --- depends.py DELETED --- From pje at users.sourceforge.net Sat Aug 6 21:29:51 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 12:29:51 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/tests __init__.py, 1.8, 1.9 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/tests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15840/setuptools/tests Modified Files: __init__.py Log Message: Got rid of the no-longer meaningful "depends" command. Consolidated the replacement of the "install" command so that installation is always via easy_install, but doesn't use the previous kludgy intereception technique. Allow ``extra_path`` to be set, but ignore it, so that when easy_install wraps a package that uses it, there won't be any confusion as to the desired installation location. Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/tests/__init__.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- __init__.py 18 Jul 2005 01:39:45 -0000 1.8 +++ __init__.py 6 Aug 2005 19:29:49 -0000 1.9 @@ -121,47 +121,6 @@ - def testDependsCmd(self): - path = convert_path('foo/bar/baz') - - dist = makeSetup( - script_args=['install','--install-lib',path] - ) - - cmd = dist.get_command_obj('depends') - cmd.ensure_finalized() - - self.assertEqual(cmd.temp, dist.get_command_obj('build').build_temp) - self.assertEqual(cmd.search_path, [path+os.path.sep,path]+sys.path) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class DistroTests(TestCase): def setUp(self): From pje at users.sourceforge.net Sat Aug 6 21:29:51 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 12:29:51 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools.egg-info entry_points.txt, 1.2, 1.3 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15840/setuptools.egg-info Modified Files: entry_points.txt Log Message: Got rid of the no-longer meaningful "depends" command. Consolidated the replacement of the "install" command so that installation is always via easy_install, but doesn't use the previous kludgy intereception technique. Allow ``extra_path`` to be set, but ignore it, so that when easy_install wraps a package that uses it, there won't be any confusion as to the desired installation location. Index: entry_points.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info/entry_points.txt,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- entry_points.txt 6 Aug 2005 18:46:28 -0000 1.2 +++ entry_points.txt 6 Aug 2005 19:29:49 -0000 1.3 @@ -13,10 +13,9 @@ build_py = setuptools.command.build_py:build_py saveopts = setuptools.command.saveopts:saveopts egg_info = setuptools.command.egg_info:egg_info -easy_install = setuptools.command.easy_install:easy_install upload = setuptools.command.upload:upload alias = setuptools.command.alias:alias -depends = setuptools.command.depends:depends +easy_install = setuptools.command.easy_install:easy_install bdist_egg = setuptools.command.bdist_egg:bdist_egg install = setuptools.command.install:install test = setuptools.command.test:test From pje at users.sourceforge.net Sat Aug 6 22:54:03 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 13:54:03 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.58, 1.59 api_tests.txt, 1.4, 1.5 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28726 Modified Files: pkg_resources.py api_tests.txt Log Message: Fix WorkingSet yielding the same distribution more than once if more than one path entry points to it. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.58 retrieving revision 1.59 diff -u -d -r1.58 -r1.59 --- pkg_resources.py 6 Aug 2005 17:56:58 -0000 1.58 +++ pkg_resources.py 6 Aug 2005 20:54:01 -0000 1.59 @@ -367,16 +367,6 @@ - def __iter__(self): - """Yield distributions for non-duplicate projects in the working set - - The yield order is the order in which the items' path entries were - added to the working set. - """ - for item in self.entries: - for key in self.entry_keys[item]: - yield self.by_key[key] - def find(self, req): """Find a distribution matching requirement `req` @@ -408,6 +398,29 @@ elif name in entries: yield entries[name] + + + + + + + + + + + def __iter__(self): + """Yield distributions for non-duplicate projects in the working set + + The yield order is the order in which the items' path entries were + added to the working set. + """ + seen = {} + for item in self.entries: + for key in self.entry_keys[item]: + if key not in seen: + seen[key]=1 + yield self.by_key[key] + def add(self, dist, entry=None): """Add `dist` to working set, associated with `entry` @@ -431,24 +444,11 @@ self.by_key[dist.key] = dist keys = self.entry_keys[entry] - if dist.key not in keys: keys.append(dist.key) self._added_new(dist) - - - - - - - - - - - - def resolve(self, requirements, env=None, installer=None): """List all distributions needed to (recursively) meet `requirements` Index: api_tests.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/api_tests.txt,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- api_tests.txt 21 Jul 2005 16:11:34 -0000 1.4 +++ api_tests.txt 6 Aug 2005 20:54:01 -0000 1.5 @@ -192,6 +192,7 @@ But even if a distribution is found under multiple path entries, it still only shows up once when iterating the working set: + >>> ws.add_entry(ws.entries[0]) >>> list(ws) [Bar 0.9 (http://example.com/something)] From pje at users.sourceforge.net Sat Aug 6 23:17:52 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 14:17:52 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools.egg-info entry_points.txt, 1.3, 1.4 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32399/setuptools.egg-info Modified Files: entry_points.txt Log Message: Allow distutils extensions to define new kinds of metadata that can be written to EGG-INFO. Extensible applications and frameworks can thus make it possible for plugin projects to supply setup() metadata that can then be used by the application or framework. Index: entry_points.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info/entry_points.txt,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- entry_points.txt 6 Aug 2005 19:29:49 -0000 1.3 +++ entry_points.txt 6 Aug 2005 21:17:50 -0000 1.4 @@ -1,11 +1,21 @@ [distutils.setup_keywords] entry_points = setuptools.dist:check_entry_points extras_require = setuptools.dist:check_extras +install_requires = setuptools.dist:check_install_requires namespace_packages = setuptools.dist:check_nsp test_suite = setuptools.dist:check_test_suite eager_resources = setuptools.dist:assert_string_list zip_safe = setuptools.dist:assert_bool +[egg_info.writers] +requires.txt = setuptools.command.egg_info:write_requirements +PKG-INFO = setuptools.command.egg_info:write_pkg_info +eager_resources.txt = setuptools.command.egg_info:write_arg +top_level.txt = setuptools.command.egg_info:write_toplevel_names +namespace_packages.txt = setuptools.command.egg_info:write_arg +entry_points.txt = setuptools.command.egg_info:write_entries +depends.txt = setuptools.command.egg_info:warn_depends_obsolete + [distutils.commands] rotate = setuptools.command.rotate:rotate develop = setuptools.command.develop:develop From pje at users.sourceforge.net Sat Aug 6 23:17:52 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 14:17:52 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command egg_info.py, 1.10, 1.11 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32399/setuptools/command Modified Files: egg_info.py Log Message: Allow distutils extensions to define new kinds of metadata that can be written to EGG-INFO. Extensible applications and frameworks can thus make it possible for plugin projects to supply setup() metadata that can then be used by the application or framework. Index: egg_info.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/egg_info.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- egg_info.py 6 Aug 2005 18:46:28 -0000 1.10 +++ egg_info.py 6 Aug 2005 21:17:50 -0000 1.11 @@ -8,7 +8,7 @@ from distutils.errors import * from distutils import log from pkg_resources import parse_requirements, safe_name, \ - safe_version, yield_lines, EntryPoint + safe_version, yield_lines, EntryPoint, iter_entry_points class egg_info(Command): @@ -80,47 +80,55 @@ - def run(self): - # Make the .egg-info directory, then write PKG-INFO and requires.txt - self.mkpath(self.egg_info) - log.info("writing %s" % os.path.join(self.egg_info,'PKG-INFO')) - - if not self.dry_run: - metadata = self.distribution.metadata - metadata.version, oldver = self.egg_version, metadata.version - metadata.name, oldname = self.egg_name, metadata.name - try: - # write unescaped data to PKG-INFO, so older pkg_resources - # can still parse it - metadata.write_pkg_info(self.egg_info) - finally: - metadata.name, metadata.version = oldname, oldver - self.write_entry_points() - self.write_requirements() - self.write_toplevel_names() - self.write_or_delete_dist_arg('namespace_packages') - self.write_or_delete_dist_arg('eager_resources') - if os.path.exists(os.path.join(self.egg_info,'depends.txt')): - log.warn( - "WARNING: 'depends.txt' is not used by setuptools 0.6!\n" - "Use the install_requires/extras_require setup() args instead." - ) + def write_or_delete_file(self, what, filename, data): + """Write `data` to `filename` or delete if empty - def write_requirements(self): - dist = self.distribution - if not getattr(dist,'install_requires',None) and \ - not getattr(dist,'extras_require',None): return + If `data` is non-empty, this routine is the same as ``write_file()``. + If `data` is empty but not ``None``, this is the same as calling + ``delete_file(filename)`. If `data` is ``None``, then this is a no-op + unless `filename` exists, in which case a warning is issued about the + orphaned file. + """ + if data: + self.write_file(what, filename, data) + elif os.path.exists(filename): + if data is None: + log.warn( + "%s not set in setup(), but %s exists", what, filename + ) + return + else: + self.delete_file(filename) - requires = os.path.join(self.egg_info,"requires.txt") - log.info("writing %s", requires) + def write_file(self, what, filename, data): + """Write `data` to `filename` (if not a dry run) after announcing it + `what` is used in a log message to identify what is being written + to the file. + """ + log.info("writing %s to %s", what, filename) if not self.dry_run: - f = open(requires, 'wt') - f.write('\n'.join(yield_lines(dist.install_requires))) - for extra,reqs in dist.extras_require.items(): - f.write('\n\n[%s]\n%s' % (extra, '\n'.join(yield_lines(reqs)))) + f = open(filename, 'wb') + f.write(data) f.close() + def delete_file(self, filename): + """Delete `filename` (if not a dry run) after announcing it""" + log.info("deleting %s", filename) + if not self.dry_run: + os.unlink(filename) + + + + + def run(self): + # Make the .egg-info directory, then write PKG-INFO and requires.txt + self.mkpath(self.egg_info) + installer = self.distribution.fetch_build_egg + for ep in iter_entry_points('egg_info.writers'): + writer = ep.load(installer=installer) + writer(self, ep.name, os.path.join(self.egg_info,ep.name)) + def tagged_version(self): version = self.distribution.get_version() if self.tag_build: @@ -132,7 +140,6 @@ version += time.strftime("-%Y%m%d") return safe_version(version) - def get_svn_revision(self): stdin, stdout = os.popen4("svn info -R"); stdin.close() result = stdout.read(); stdout.close() @@ -146,60 +153,94 @@ return str(max(revisions)) - def write_toplevel_names(self): - pkgs = dict.fromkeys( - [k.split('.',1)[0] - for k in self.distribution.iter_distribution_names() - ] + + + + + + + + + +def write_pkg_info(cmd, basename, filename): + log.info("writing %s", filename) + if not cmd.dry_run: + metadata = cmd.distribution.metadata + metadata.version, oldver = cmd.egg_version, metadata.version + metadata.name, oldname = cmd.egg_name, metadata.name + try: + # write unescaped data to PKG-INFO, so older pkg_resources + # can still parse it + metadata.write_pkg_info(cmd.egg_info) + finally: + metadata.name, metadata.version = oldname, oldver + +def warn_depends_obsolete(cmd, basename, filename): + if os.path.exists(filename): + log.warn( + "WARNING: 'depends.txt' is not used by setuptools 0.6!\n" + "Use the install_requires/extras_require setup() args instead." ) - toplevel = os.path.join(self.egg_info, "top_level.txt") - log.info("writing list of top-level names to %s" % toplevel) - if not self.dry_run: - f = open(toplevel, 'wt') - f.write('\n'.join(pkgs)) - f.write('\n') - f.close() + + +def write_requirements(cmd, basename, filename): + dist = cmd.distribution + data = ['\n'.join(yield_lines(dist.install_requires or ()))] + for extra,reqs in (dist.extras_require or {}).items(): + data.append('\n\n[%s]\n%s' % (extra, '\n'.join(yield_lines(reqs)))) + cmd.write_or_delete_file("requirements", filename, ''.join(data)) + +def write_toplevel_names(cmd, basename, filename): + pkgs = dict.fromkeys( + [k.split('.',1)[0] + for k in cmd.distribution.iter_distribution_names() + ] + ) + cmd.write_file("top-level names", filename, '\n'.join(pkgs)+'\n') + + + + + + +def write_arg(cmd, basename, filename): + argname = os.path.splitext(basename)[0] + value = getattr(cmd.distribution, argname, None) + if value is not None: + value = '\n'.join(value)+'\n' + cmd.write_or_delete_file(argname, filename, value) + +def write_entries(cmd, basename, filename): + ep = cmd.distribution.entry_points + + if isinstance(ep,basestring) or ep is None: + data = ep + elif ep is not None: + data = [] + for section, contents in ep.items(): + if not isinstance(contents,basestring): + contents = EntryPoint.parse_list(section, contents) + contents = '\n'.join(map(str,contents.values())) + data.append('[%s]\n%s\n\n' % (section,contents)) + data = ''.join(data) + + cmd.write_or_delete_file('entry points', filename, data) + + + + + + + + + + + + - def write_or_delete_dist_arg(self, argname, filename=None): - value = getattr(self.distribution, argname, None) - filename = filename or argname+'.txt' - filename = os.path.join(self.egg_info,filename) - if value: - log.info("writing %s", filename) - if not self.dry_run: - f = open(filename, 'wt') - f.write('\n'.join(value)) - f.write('\n') - f.close() - elif os.path.exists(filename): - if value is None: - log.warn( - "%s not set in setup(), but %s exists", argname, filename - ) - return - log.info("deleting %s", filename) - if not self.dry_run: - os.unlink(filename) - def write_entry_points(self): - ep = getattr(self.distribution,'entry_points',None) - if ep is None: - return - epname = os.path.join(self.egg_info,"entry_points.txt") - log.info("writing %s", epname) - if not self.dry_run: - f = open(epname, 'wt') - if isinstance(ep,basestring): - f.write(ep) - else: - for section, contents in ep.items(): - if not isinstance(contents,basestring): - contents = EntryPoint.parse_list(section, contents) - contents = '\n'.join(map(str,contents.values())) - f.write('[%s]\n%s\n\n' % (section,contents)) - f.close() From pje at users.sourceforge.net Sat Aug 6 23:17:52 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 14:17:52 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools setup.py, 1.35, 1.36 setuptools.txt, 1.28, 1.29 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32399 Modified Files: setup.py setuptools.txt Log Message: Allow distutils extensions to define new kinds of metadata that can be written to EGG-INFO. Extensible applications and frameworks can thus make it possible for plugin projects to supply setup() metadata that can then be used by the application or framework. Index: setup.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setup.py,v retrieving revision 1.35 retrieving revision 1.36 diff -u -d -r1.35 -r1.36 --- setup.py 6 Aug 2005 18:46:27 -0000 1.35 +++ setup.py 6 Aug 2005 21:17:49 -0000 1.36 @@ -40,7 +40,6 @@ scripts = ['easy_install.py'], zip_safe = False, # We want 'python -m easy_install' to work :( - entry_points = { "distutils.commands" : [ "%(cmd)s = setuptools.command.%(cmd)s:%(cmd)s" % locals() @@ -50,13 +49,23 @@ "eager_resources = setuptools.dist:assert_string_list", "namespace_packages = setuptools.dist:check_nsp", "extras_require = setuptools.dist:check_extras", + "install_requires = setuptools.dist:check_install_requires", "entry_points = setuptools.dist:check_entry_points", "test_suite = setuptools.dist:check_test_suite", "zip_safe = setuptools.dist:assert_bool", - ] + ], + "egg_info.writers": [ + "PKG-INFO = setuptools.command.egg_info:write_pkg_info", + "requires.txt = setuptools.command.egg_info:write_requirements", + "entry_points.txt = setuptools.command.egg_info:write_entries", + "eager_resources.txt = setuptools.command.egg_info:write_arg", + "namespace_packages.txt = setuptools.command.egg_info:write_arg", + "top_level.txt = setuptools.command.egg_info:write_toplevel_names", + "depends.txt = setuptools.command.egg_info:warn_depends_obsolete", + ], }, - - setup_requires = ['setuptools>=0.6a0'], + # uncomment for testing + # setup_requires = ['setuptools>=0.6a0'], classifiers = [f.strip() for f in """ Development Status :: 3 - Alpha @@ -68,23 +77,6 @@ Topic :: Software Development :: Libraries :: Python Modules Topic :: System :: Archiving :: Packaging Topic :: System :: Systems Administration - Topic :: Utilities - """.splitlines() if f.strip()] + Topic :: Utilities""".splitlines() if f.strip()] ) - - - - - - - - - - - - - - - - Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- setuptools.txt 6 Aug 2005 19:29:48 -0000 1.28 +++ setuptools.txt 6 Aug 2005 21:17:49 -0000 1.29 @@ -622,6 +622,21 @@ point optional if a requirement isn't installed.) +Defining Additional Metadata +---------------------------- + +Some extensible applications and frameworks may need to define their own kinds +of metadata to include in eggs, which they can then access using the +``pkg_resources`` metadata APIs. Ordinarily, this is done by having plugin +developers include additional files in their ``ProjectName.egg-info`` +directory. However, since it can be tedious to create such files by hand, you +may want to create a distutils extension that will create the necessary files +from arguments to ``setup()``, in much the same way that ``setuptools`` does +for many of the ``setup()`` arguments it adds. See the section below on +`Creating distutils Extensions`_ for more details, especially the subsection on +`Adding new EGG-INFO Files`_. + + "Development Mode" ================== @@ -1301,6 +1316,14 @@ ``package_dir`` argument to the ``setup()`` function, if any. If there is no ``package_dir`` set, this option defaults to the current directory. +In addition to writing the core egg metadata defined by ``setuptools`` and +required by ``pkg_resources``, this command can be extended to write other +metadata files as well, by defining entry points in the ``egg_info.writers`` +group. See the section on `Adding new EGG-INFO Files`_ below for more details. +Note that using additional metadata writers may require you to include a +``setup_requires`` argument to ``setup()`` in order to ensure that the desired +writers are available on ``sys.path``. + .. _rotate: @@ -1639,6 +1662,60 @@ script lists your extension in its ``setup_requires`` argument. +Adding new EGG-INFO Files +------------------------- + +Some extensible applications or frameworks may want to allow third parties to +develop plugins with application or framework-specific metadata included in +the plugins' EGG-INFO directory, for easy access via the ``pkg_resources`` +metadata API. The easiest way to allow this is to create a distutils extension +to be used from the plugin projects' setup scripts (via ``setup_requires``) +that defines a new setup keyword, and then uses that data to write an EGG-INFO +file when the ``egg_info`` command is run. + +The ``egg_info`` command looks for extension points in an ``egg_info.writers`` +group, and calls them to write the files. Here's a simple example of a +distutils extension defining a setup argument ``foo_bar``, which is a list of +lines that will be written to ``foo_bar.txt`` in the EGG-INFO directory of any +project that uses the argument:: + + setup( + # ... + entry_points = { + "distutils.setup_keywords": [ + "foo_bar = setuptools.dist:assert_string_list", + ], + "egg_info.writers": [ + "foo_bar.txt = setuptools.command.egg_info:write_arg", + ], + }, + ) + +This simple example makes use of two utility functions defined by setuptools +for its own use: a routine to validate that a setup keyword is a sequence of +strings, and another one that looks up a setup argument and writes it to +a file. Here's what the writer utility looks like:: + + def write_arg(cmd, basename, filename): + argname = os.path.splitext(basename)[0] + value = getattr(cmd.distribution, argname, None) + if value is not None: + value = '\n'.join(value)+'\n' + cmd.write_or_delete_file(argname, filename, value) + +As you can see, ``egg_info.writers`` entry points must be a function taking +three arguments: a ``egg_info`` command instance, the basename of the file to +write (e.g. ``foo_bar.txt``), and the actual full filename that should be +written to. + +In general, writer functions should honor the command object's ``dry_run`` +setting when writing files, and use the ``distutils.log`` object to do any +console output. The easiest way to conform to this requirement is to use +the ``cmd`` object's ``write_file()``, ``delete_file()``, and +``write_or_delete_file()`` methods exclusively for your file operations. See +those methods' docstrings for more details. + + Subclassing ``Command`` ----------------------- @@ -1709,9 +1786,10 @@ ``setup_requires`` allows you to automatically find and download packages that are needed in order to *build* your project (as opposed to running it). - * ``setuptools`` now finds its commands and ``setup()`` argument validators - using entry points, so that they are extensible by third-party packages. - See `Creating distutils Extensions`_ above for more details. + * ``setuptools`` now finds its commands, ``setup()`` argument validators, and + metadata writers using entry points, so that they can be extended by + third-party packages. See `Creating distutils Extensions`_ above for more + details. * The vestigial ``depends`` command has been removed. It was never finished or documented, and never would have worked without EasyInstall - which it From bcannon at users.sourceforge.net Sun Aug 7 01:14:02 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Sat, 06 Aug 2005 16:14:02 -0700 Subject: [Python-checkins] python/nondist/peps pep-3000.txt,1.17,1.18 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16725 Modified Files: pep-3000.txt Log Message: Mention plan to remove ``raise Exception, "message"`` style of raising exceptions. Index: pep-3000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-3000.txt,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- pep-3000.txt 28 Apr 2005 20:04:32 -0000 1.17 +++ pep-3000.txt 6 Aug 2005 23:13:59 -0000 1.18 @@ -67,6 +67,7 @@ * The ``lambda`` statement: use nested or named functions [1]_, [9]_ * String exceptions: use instances of an Exception class [2]_ +* ``raise Exception, "message"``: use ``raise Exception("message")`` [14]_ * ```x```: use ``repr(x)`` [2]_ * The ``<>`` operator: use ``!=`` instead [3]_ * Unbound methods [7]_ @@ -153,6 +154,9 @@ .. [13] python-dev email ("anonymous blocks") http://mail.python.org/pipermail/python-dev/2005-April/053060.html +.. [14] python-dev email ("PEP 8: exception style") + http://mail.python.org/pipermail/python-dev/2005-August/055190.html + Copyright ========= From pje at users.sourceforge.net Sun Aug 7 03:03:38 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 18:03:38 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools package_index.py, 1.15, 1.16 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32363/setuptools Modified Files: package_index.py Log Message: Renamed AvailableDistributions -> Environment. Add sketch of pkg_resources manual outline. Index: package_index.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/package_index.py,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- package_index.py 24 Jul 2005 02:41:43 -0000 1.15 +++ package_index.py 7 Aug 2005 01:03:35 -0000 1.16 @@ -121,11 +121,11 @@ -class PackageIndex(AvailableDistributions): +class PackageIndex(Environment): """A distribution index that scans web pages for download URLs""" def __init__(self,index_url="http://www.python.org/pypi",*args,**kw): - AvailableDistributions.__init__(self,*args,**kw) + Environment.__init__(self,*args,**kw) self.index_url = index_url + "/"[:not index_url.endswith('/')] self.scanned_urls = {} self.fetched_urls = {} From pje at users.sourceforge.net Sun Aug 7 03:03:39 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 18:03:39 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/tests test_resources.py, 1.20, 1.21 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/tests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32363/setuptools/tests Modified Files: test_resources.py Log Message: Renamed AvailableDistributions -> Environment. Add sketch of pkg_resources manual outline. Index: test_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/tests/test_resources.py,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- test_resources.py 25 Jul 2005 03:12:51 -0000 1.20 +++ test_resources.py 7 Aug 2005 01:03:36 -0000 1.21 @@ -23,7 +23,7 @@ def testCollection(self): # empty path should produce no distributions - ad = AvailableDistributions([], python=None) + ad = Environment([], python=None) self.assertEqual(list(ad), []) self.assertEqual(len(ad),0) self.assertEqual(ad.get('FooPkg'),None) @@ -122,7 +122,7 @@ def testResolve(self): - ad = AvailableDistributions([]); ws = WorkingSet([]) + ad = Environment([]); ws = WorkingSet([]) # Resolving no requirements -> nothing to install self.assertEqual( list(ws.resolve([],ad)), [] ) From pje at users.sourceforge.net Sun Aug 7 03:03:38 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 18:03:38 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command easy_install.py, 1.19, 1.20 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32363/setuptools/command Modified Files: easy_install.py Log Message: Renamed AvailableDistributions -> Environment. Add sketch of pkg_resources manual outline. Index: easy_install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/easy_install.py,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- easy_install.py 6 Aug 2005 17:54:55 -0000 1.19 +++ easy_install.py 7 Aug 2005 01:03:36 -0000 1.20 @@ -181,7 +181,7 @@ self.package_index = self.create_index( self.index_url, search_path = self.shadow_path ) - self.local_index = AvailableDistributions(self.shadow_path) + self.local_index = Environment(self.shadow_path) if self.find_links is not None: if isinstance(self.find_links, basestring): @@ -805,7 +805,7 @@ try: args.append(dist_dir) self.run_setup(setup_script, setup_base, args) - all_eggs = AvailableDistributions([dist_dir]) + all_eggs = Environment([dist_dir]) eggs = [] for key in all_eggs: for dist in all_eggs[key]: @@ -1064,14 +1064,14 @@ -class PthDistributions(AvailableDistributions): +class PthDistributions(Environment): """A .pth file with Distribution paths in it""" dirty = False def __init__(self, filename): self.filename = filename; self._load() - AvailableDistributions.__init__( + Environment.__init__( self, list(yield_lines(self.paths)), None, None ) @@ -1109,13 +1109,13 @@ """Add `dist` to the distribution map""" if dist.location not in self.paths: self.paths.append(dist.location); self.dirty = True - AvailableDistributions.add(self,dist) + Environment.add(self,dist) def remove(self,dist): """Remove `dist` from the distribution map""" while dist.location in self.paths: self.paths.remove(dist.location); self.dirty = True - AvailableDistributions.remove(self,dist) + Environment.remove(self,dist) def main(argv, **kw): From pje at users.sourceforge.net Sun Aug 7 03:03:38 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 18:03:38 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.txt, NONE, 1.1 pkg_resources.py, 1.59, 1.60 setuptools.txt, 1.29, 1.30 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32363 Modified Files: pkg_resources.py setuptools.txt Added Files: pkg_resources.txt Log Message: Renamed AvailableDistributions -> Environment. Add sketch of pkg_resources manual outline. --- NEW FILE: pkg_resources.txt --- ============================================================= Package Discovery and Resource Access using ``pkg_resources`` ============================================================= The ``pkg_resources`` module, distributed with ``setuptools``, provides features for Python libraries to access resource files, and for extensible applications and frameworks to automatically discover plugins. It also provides runtime support for using C extensions that are inside zipfile eggs, support for merging packages that have separately-distributed modules or subpackages, and APIs for managing Python's current "working set" of active packages. .. contents:: **Table of Contents** -------- Overview -------- XXX ----------------- Developer's Guide ----------------- Accessing Resources Finding and Activating Package Distributions get_provider() require() WorkingSet iter_distributions Running Scripts Configuration Namespace Packages Extensible Applications and Frameworks Locating entry points Activation listeners Metadata access Extended Discovery and Installation Supporting Custom PEP 302 Implementations ------------- API Reference ------------- ``WorkingSet`` Objects ====================== Listeners ``Environment`` Objects ======================= XXX ``EntryPoint`` Objects ====================== XXX ``Requirement`` Objects ======================= XXX Syntax, parse_requirments, Requirement.parse, etc. ``Distribution`` Objects ======================== XXX ``ResourceManager`` Objects =========================== XXX Exceptions ========== XXX ResolutionError, VersionConflict, DistributionNotFound, UnknownExtra Utility Functions ================= Parsing Utilities ----------------- yield_lines XXX split_sections XXX parse_version XXX safe_name XXX safe_version XXX Platform Utilities ------------------ get_platform XXX compatible_platforms XXX File/Path Utilities ------------------- ensure_directory XXX normalize_path XXX Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.59 retrieving revision 1.60 diff -u -d -r1.59 -r1.60 --- pkg_resources.py 6 Aug 2005 20:54:01 -0000 1.59 +++ pkg_resources.py 7 Aug 2005 01:03:34 -0000 1.60 @@ -52,7 +52,7 @@ 'get_default_cache', # Primary implementation classes - 'AvailableDistributions', 'WorkingSet', 'ResourceManager', + 'Environment', 'WorkingSet', 'ResourceManager', 'Distribution', 'Requirement', 'EntryPoint', # Exceptions @@ -76,7 +76,7 @@ 'fixup_namespace_packages', 'get_importer', # Deprecated/backward compatibility only - 'run_main', + 'run_main', 'AvailableDistributions', ] @@ -453,7 +453,7 @@ """List all distributions needed to (recursively) meet `requirements` `requirements` must be a sequence of ``Requirement`` objects. `env`, - if supplied, should be an ``AvailableDistributions`` instance. If + if supplied, should be an ``Environment`` instance. If not supplied, it defaults to all distributions available within any entry or distribution in the working set. `installer`, if supplied, will be invoked with each requirement that cannot be met by an @@ -476,7 +476,7 @@ if dist is None: # Find the best distribution and add it to the map if env is None: - env = AvailableDistributions(self.entries) + env = Environment(self.entries) dist = best[req.key] = env.best_match(req, self, installer) if dist is None: raise DistributionNotFound(req) # XXX put more info here @@ -531,7 +531,7 @@ -class AvailableDistributions(object): +class Environment(object): """Searchable snapshot of distributions on a search path""" def __init__(self,search_path=None,platform=get_platform(),python=PY_MAJOR): @@ -645,7 +645,6 @@ return self.obtain(req, installer) # try and download/install - def obtain(self, requirement, installer=None): """Obtain a distro that matches requirement (e.g. via download)""" if installer is not None: @@ -653,6 +652,7 @@ def __len__(self): return len(self._distmap) +AvailableDistributions = Environment # XXX backward compatibility class ResourceManager: """Manage resource extraction and packages""" Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- setuptools.txt 6 Aug 2005 21:17:49 -0000 1.29 +++ setuptools.txt 7 Aug 2005 01:03:35 -0000 1.30 @@ -51,6 +51,12 @@ * Deploy your project in "development mode", such that it's available on ``sys.path``, yet can still be edited directly from its source checkout. +* Easily extend the distutils with new commands or ``setup()`` arguments, and + distribute/reuse your extensions for multiple projects, without copying code. + +* Create extensible applications and frameworks that automatically discover + extensions, using simple "entry points" declared in a project's setup script. + .. contents:: **Table of Contents** @@ -1846,7 +1852,9 @@ that tells it to only yield distributions whose location is the passed-in path. (It defaults to False, so that the default behavior is unchanged.) - * The ``resolve()`` method of ``AvailableDistributions`` is now a method of + * ``AvailableDistributions`` is now called ``Environment`` + + * The ``resolve()`` method of ``Environment`` is now a method of ``WorkingSet`` instead, and the ``best_match()`` method now uses a working set instead of a path list as its second argument. From tim_one at users.sourceforge.net Sun Aug 7 04:47:15 2005 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sat, 06 Aug 2005 19:47:15 -0700 Subject: [Python-checkins] python/dist/src/PCbuild readme.txt,1.60,1.61 Message-ID: Update of /cvsroot/python/python/dist/src/PCbuild In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12529 Modified Files: readme.txt Log Message: Update some Python version numbers. Index: readme.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/readme.txt,v retrieving revision 1.60 retrieving revision 1.61 diff -u -d -r1.60 -r1.61 --- readme.txt 26 Jul 2005 02:29:21 -0000 1.60 +++ readme.txt 7 Aug 2005 02:47:12 -0000 1.61 @@ -12,7 +12,7 @@ The proper order to build subprojects: 1) pythoncore (this builds the main Python DLL and library files, - python21.{dll, lib} in Release mode) + python25.{dll, lib} in Release mode) NOTE: in previous releases, this subproject was named after the release number, e.g. python20. @@ -25,7 +25,7 @@ to the subsystems they implement; see SUBPROJECTS below) When using the Debug setting, the output files have a _d added to -their name: python24_d.dll, python_d.exe, parser_d.pyd, and so on. +their name: python25_d.dll, python_d.exe, parser_d.pyd, and so on. SUBPROJECTS ----------- @@ -114,7 +114,7 @@ all.tcl: Total 8420 Passed 6826 Skipped 1581 Failed 13 Sourced 91 Test Files. Files with failing tests: canvImg.test scrollbar.test textWind.test winWm.test - + Built Tix --------- Download from http://prdownloads.sourceforge.net/tix/tix-8.1.4.tar.gz From tim_one at users.sourceforge.net Sun Aug 7 04:48:01 2005 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sat, 06 Aug 2005 19:48:01 -0700 Subject: [Python-checkins] python/dist/src/PCbuild readme.txt,1.61,1.62 Message-ID: Update of /cvsroot/python/python/dist/src/PCbuild In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12595 Modified Files: readme.txt Log Message: Removed XXX block about a test_bsddb3 failure that went away a long time ago. Index: readme.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/readme.txt,v retrieving revision 1.61 retrieving revision 1.62 diff -u -d -r1.61 -r1.62 --- readme.txt 7 Aug 2005 02:47:12 -0000 1.61 +++ readme.txt 7 Aug 2005 02:47:59 -0000 1.62 @@ -238,17 +238,6 @@ XXX doesn't cause a test to fail when it happens (exceptions in XXX threads are invisible to unittest). - XXX 11-Apr-2004 tim - XXX On WinXP Pro, I got one failure from test_bsddb3: - XXX - XXX ERROR: test04_n_flag (bsddb.test.test_compat.CompatibilityTestCase) - XXX Traceback (most recent call last): - XXX File "C:\Code\python\lib\bsddb\test\test_compat.py", line 86, in test04_n_flag - XXX f = hashopen(self.filename, 'n') - XXX File "C:\Code\python\lib\bsddb\__init__.py", line 293, in hashopen - XXX d.open(file, db.DB_HASH, flags, mode) - XXX DBInvalidArgError: (22, 'Invalid argument -- DB_TRUNCATE illegal with locking specified') - _ssl Python wrapper for the secure sockets library. From tim_one at users.sourceforge.net Sun Aug 7 05:05:00 2005 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Sat, 06 Aug 2005 20:05:00 -0700 Subject: [Python-checkins] python/dist/src/Lib/test test_generators.py, 1.45, 1.46 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14552/Lib/test Modified Files: test_generators.py Log Message: Whitespace normalization (ran reindent.py over the whole tree). Index: test_generators.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_generators.py,v retrieving revision 1.45 retrieving revision 1.46 diff -u -d -r1.45 -r1.46 --- test_generators.py 2 Aug 2005 00:46:43 -0000 1.45 +++ test_generators.py 7 Aug 2005 03:04:58 -0000 1.46 @@ -484,7 +484,7 @@ merged A into G A->G B->G C->G D->G E->G F->G G->G H->G I->G J->G K->G L->G M->G ->>> for s in sets: s.close() # break cycles +>>> for s in sets: s.close() # break cycles """ # Emacs turd ' @@ -1467,12 +1467,12 @@ >>> g.throw(ValueError, TypeError(1)) # mismatched type, rewrapped caught ValueError (1) ->>> g.throw(ValueError(1), "foo") # bad args +>>> g.throw(ValueError(1), "foo") # bad args Traceback (most recent call last): ... TypeError: instance exception may not have a separate value ->>> g.throw(ValueError, "foo", 23) # bad args +>>> g.throw(ValueError, "foo", 23) # bad args Traceback (most recent call last): ... TypeError: throw() third argument must be a traceback object @@ -1482,13 +1482,13 @@ ... raise exc ... except: ... g.throw(*sys.exc_info()) ->>> throw(g,ValueError) # do it with traceback included +>>> throw(g,ValueError) # do it with traceback included caught ValueError () >>> g.send(1) 1 ->>> throw(g,TypeError) # terminate the generator +>>> throw(g,TypeError) # terminate the generator Traceback (most recent call last): ... TypeError @@ -1501,12 +1501,12 @@ ... StopIteration ->>> g.throw(ValueError,6) # throw on closed generator +>>> g.throw(ValueError,6) # throw on closed generator Traceback (most recent call last): ... ValueError: 6 ->>> f().throw(ValueError,7) # throw on just-opened generator +>>> f().throw(ValueError,7) # throw on just-opened generator Traceback (most recent call last): ... ValueError: 7 @@ -1527,11 +1527,11 @@ >>> f().close() # close on just-opened generator should be fine ->>> def f(): yield # an even simpler generator ->>> f().close() # close before opening +>>> def f(): yield # an even simpler generator +>>> f().close() # close before opening >>> g = f() >>> g.next() ->>> g.close() # close normally +>>> g.close() # close normally And finalization: From bcannon at users.sourceforge.net Sun Aug 7 06:14:07 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Sat, 06 Aug 2005 21:14:07 -0700 Subject: [Python-checkins] python/nondist/peps pep-0348.txt,1.4,1.5 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22391 Modified Files: pep-0348.txt Log Message: Essentially version 3 of this PEP. All renamings have been removed. All new exceptions that were not superclasses have been removed. CriticalException has been renamed TerminalException. SystemError and MemoryError have been moved back under Exception, but while inheriting from the new exception VMError. ControlFlowException has been removed and its subclasses now directly inherit Exception. Also includes reformatting of the references and some editorial changes as suggested by David Goodger. Index: pep-0348.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0348.txt,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- pep-0348.txt 5 Aug 2005 05:31:44 -0000 1.4 +++ pep-0348.txt 7 Aug 2005 04:14:04 -0000 1.5 @@ -13,11 +13,11 @@ Abstract ======== -Python, as of version 2.4, has 38 exceptions (including warnings) in +Python, as 0of version 2.4, has 38 exceptions (including warnings) in the built-in namespace in a rather shallow hierarchy. This list of classes has grown over the years without a chance to learn from -mistakes and clean up the hierarchy. This PEP proposes doing a -reorganization for Python 3.0 when backwards-compatibility is not an +experience. This PEP proposes doing a reorganization of the hierarchy +for Python 3.0 when backwards-compatibility is not as much of an issue. Along with this reorganization, adding a requirement that all objects passed to a ``raise`` statement must inherit from a specific superclass is proposed. Lastly, bare ``except`` clauses will catch @@ -29,63 +29,68 @@ Exceptions are a critical part of Python. While exceptions are traditionally used to signal errors in a program, they have also grown -to be used for flow control for things such as iterators. Their -importance is great. +to be used for flow control for things such as iterators. -But the organization of the exception hierarchy is suboptimal to serve -the multiple uses of exceptions. Mostly for backwards-compatibility -reasons, the hierarchy has stayed very flat and old exceptions whose -usefulness has not been proven have been left in. Making exceptions -more hierarchical would help facilitate exception handling by making -exception catching using inheritance much more logical. This should -also help lead to fewer errors from overly broad exception catching in -``except`` clauses. +While their importance is great, there is lack of structure to them. +This stems from the fact that any object can be raised as an +exception. Because of this you have no guarantee in terms of what +kind of object will be raised, destroying any possible hierarchy +raised objects might adhere to. -A mandatory superclass for all exceptions is also being proposed -[#Summary2004-08-01]_. By requiring any object that is used in a -``raise`` statement to inherit from a specific superclass, certain -attributes (such as those laid out in PEP 344 [#PEP344]_) can be -guaranteed to exist. This also will lead to the planned removal of -string exceptions. +But exceptions do have a hierarchy, showing the severity of the +exception. The hierarchy also groups related exceptions together to +simplify catching them in ``except`` clauses. To allow peopele to +be able to rely on this hierarchy, a common superclasse that all +raise objects must inherit from is being proposed. It also allows +guarantees about the interface to raised objects to be made (see +PEP 344 [#PEP344]_). A discussion about all of this has occurred +before on python-dev [#Summary2004-08-01]_. -Lastly, bare ``except`` clauses are to catch only exceptions that -inherit from ``Exception`` [#python-dev3]_. While currently used to -catch all exceptions, that use is too far-reaching and typically not -desired. Catching only exceptions that inherit from ``Exception`` -allows other exceptions (those that should not be caught unless -explicitly desired) to continue to propagate up the execution stack. +But allowing a guarantee about the hierarchy is not the only place +where exceptions can stand improvement. Bare ``except`` clauses are +often used in an inappropriate manner. Since they catch *all* raised +objects, they can catch exceptions that should have been allowed to +propagate to the top level of the execution stack, leading to the +interpreter terminating execution. Once again, this has been +discussed on python-dev [#python-dev3]_. + +To fix this over-reaching of bare ``except`` clauses, it is being +proposed that only objects inheriting from Exception be caught by +bare ``except`` clauses. This will allow the exception hierarchy +to be organized in such a way that bare ``except`` clauses can be +more useful by allowing exceptions that should not normally be caught +to lead to the termination of the interpreter. Philosophy of Reorganization ============================ -There are several goals in this reorganization that defined the -philosophy used to guide the work. One goal was to prune out unneeded -exceptions. Extraneous exceptions should not be left in since they -just serve to clutter the built-in namespace. Unneeded exceptions -also dilute the importance of other exceptions by splitting uses -between several exceptions when all uses should have been under a -single exception. +For the reorganization of the hierarchy, there was a general +philosophy followed that developed from discussion of earlier drafts +of this PEP [#python-dev-thread1]_, [#python-dev-thread2]_, +[#python-dev-thread3]_. First and foremost was to not break anything +that works. This meant that renaming exceptions was out of the +question unless the name was deemed severely bad. This +also meant no removal of exceptions unless they were viewed as +truly misplaced. The introduction of new exceptions were only done in +situations where there might be a use for catching a superclass of a +category of exceptions. Lastly, existing exceptions would have their +inheritance tree changed only if it was felt they were truly +misplaced to begin with. -Another goal was to introduce exceptions that were deemed necessary to -fill holes in the hierarchy. Most new exceptions were added to flesh -out the inheritance hierarchy to make it easier to catch a category of -exceptions with a simpler ``except`` clause. +For all new exceptions, the proper suffix had to be chosen. For +those that signal an error, "Error" is to be used. If the exception +is a warning, then "Warning". "Exception" is to be used when none +of the other suffixes are proper to use and no specific suffix is +a better fit. -Changing inheritance to make the hierarchy more reasonable was a goal. -As stated above, having proper inheritance allows for more accurate -``except`` statements when catching exceptions based on the -inheritance tree. +After that it came down to choosing which exceptions should and +should not inherit from Exception. This was for the purpose of +making bare ``except`` clauses more useful. -Lastly, some renaming was done to make the usage of certain exceptions -more obvious. Having to look up an exception due to the name not -accurately reflecting its intended use is annoying and slows down -debugging. Having accurate names also makes debugging easier for new -programmers. But for simplicity, for the convenience of existing -users, and for the sake of transitioning to Python 3.0, only -exceptions whose names were significantly out of alignment with their -stated purpose have been renamed. All exceptions dealing with errors -will be named with an "Error" suffix. +Lastly, the entire existing hierarchy had to inherit from the new +exception meant to act as the required superclass for all exceptions +to inherit from. New Hierarchy @@ -94,76 +99,67 @@ .. Note:: Exceptions flagged with "stricter inheritance" will no longer inherit from a certain class. A "broader inheritance" flag means a class has been added to the exception's inheritance tree. + All comparisons are against the Python 2.4 exception hierarchy. .. parsed-literal:: - BaseException - +-- CriticalError (new) - +-- KeyboardInterrupt (stricter inheritance) - +-- MemoryError (stricter inheritance) - +-- SystemError (stricter inheritance) - +-- ControlFlowException (new) - +-- GeneratorExit (defined in PEP 342 [#PEP342]_) - +-- StopIteration (stricter inheritance) - +-- SystemExit (stricter inheritance) - +-- Exception - +-- StandardError - +-- ArithmeticError - +-- DivideByZeroError - +-- FloatingPointError - +-- OverflowError - +-- AssertionError - +-- AttributeError - +-- EnvironmentError - +-- IOError - +-- EOFError (broader inheritance) - +-- OSError - +-- ImportError - +-- LookupError - +-- IndexError - +-- KeyError - +-- NamespaceError (renamed from NameError) - +-- UnboundFreeError (new) - +-- UnboundGlobalError (new) - +-- UnboundLocalError - +-- NotImplementedError (stricter inheritance) - +-- SyntaxError - +-- IndentationError - +-- TabError - +-- TypeError - +-- UserError (renamed from RuntimeError) - +-- UnicodeError - +-- UnicodeDecodeError - +-- UnicodeEncodeError - +-- UnicodeTranslateError - +-- ValueError - +-- Warning - +-- AnyDeprecationWarning (new; broader inheritance for subclasses) - +-- PendingDeprecationWarning - +-- DeprecationWarning - +-- FutureWarning - +-- SyntaxWarning - +-- SemanticsWarning (renamed from RuntimeWarning) - +-- UserWarning - +-- WeakReferenceError (renamed from ReferenceError) + +-- BaseException (new; broader inheritance for subclasses) + +-- TerminalException (new; stricter inheritance for subclasses) + +-- KeyboardInterrupt + +-- SystemExit + +-- Exception + +-- GeneratorExit (defined in PEP 342 [#PEP342]_) + +-- StandardError + +-- ArithmeticError + +-- DivideByZeroError + +-- FloatingPointError + +-- OverflowError + +-- AssertionError + +-- AttributeError + +-- EnvironmentError + +-- IOError + +-- EOFError (broader inheritance) + +-- OSError + +-- ImportError + +-- LookupError + +-- IndexError + +-- KeyError + +-- NameError + +-- UnboundLocalError + +-- NotImplementedError (stricter inheritance) + +-- SyntaxError + +-- IndentationError + +-- TabError + +-- TypeError + +-- RuntimeError + +-- UnicodeError + +-- UnicodeDecodeError + +-- UnicodeEncodeError + +-- UnicodeTranslateError + +-- ValueError + +-- VMError (new; broader inheritance for subclasses) + +-- MemoryError + +-- SystemError + +-- ReferenceError + +-- StopIteration + +-- Warning + +-- AnyDeprecationWarning (new; broader inheritance for subclasses) + +-- PendingDeprecationWarning + +-- DeprecationWarning + +-- FutureWarning + +-- SyntaxWarning + +-- RuntimeWarning + +-- UserWarning Differences Compared to Python 2.4 ================================== -Changes to exceptions from Python 2.4 can take shape in three forms: -removal, renaming, or change of position in the hierarchy. There are -also new exceptions introduced in the proposed hierarchy. - -In terms of new exceptions, almost all are added to flesh out the -inheritance tree. Those that are leaf classes are added to alleviate -the overloading of another exception. - -Positional changes result in either broader or more restrictive -inheritance. The broader inheritance typically occurred to allow for -a more reasonable superclass to group related exceptions together. -Stricter inheritance happened when the pre-existing inheritance was -deemed incorrect and needed correction. +A more thorough explanation of terms is needed when discussing +inheritance changes. Inheritance changes result in either broader or +more restrictive inheritance. "Broader" is when a class has an +inheritance tree like ``cls, A`` and then becomes ``cls, B, A``. +"Stricter is the reverse. New Exceptions @@ -175,35 +171,19 @@ The superclass that all exceptions must inherit from. -CriticalError -''''''''''''' - -The superclass for severe error exceptions; typically, one would not -want to recover from such an exception. The name is meant to reflect -that these exceptions are raised asynchronously by the interpreter -when a critical event has occured. - - -ControlFlowException -'''''''''''''''''''' - -This exception exists as a superclass for all exceptions that directly -deal with control flow. Inheriting from BaseException instead of -Exception prevents them from being caught accidently when one wants to -catch errors. The name, by not mentioning "Error", does not lead to -one to confuse the subclasses as errors. - - -UnboundGlobalError -'''''''''''''''''' +TerminalException +''''''''''''''''' -Raised when a global variable was not found. +Superclass for exceptions that are meant to the termination of the +interpreter. It does not inherit from Exception so that +subclasses are not caught by bare ``except`` clauses. -UnboundFreeError -'''''''''''''''' +VMError +''''''' -Raised when a free variable is not found. +Superclass for exceptions that deal directly with the virtual +machine. AnyDeprecationWarning @@ -226,92 +206,14 @@ Too OS-specific to be kept in the built-in exception hierarchy. -Renamed Exceptions ------------------- - -RuntimeError -'''''''''''' - -Renamed to UserError. - -Meant as a generic exception for use when neither a new exception -class nor inheritance-based exception catching is desired, -RuntimeError is poorly named. Its name in Python 2.4 seems to suggest -an error that occurred at runtime, possibly an error in the VM. -Renaming the exception to UserError more clearly states the purpose of -the exception as a quick-and-dirty error exception. The name also -keeps it in line with UserWarning. - -If a user wants an non-error exception, raising BaseException directly -should be sufficient since Exception, which UserError inherits from, -is only used for errors. - - -ReferenceError -'''''''''''''' - -Renamed to WeakReferenceError. - -ReferenceError was added to the built-in exception hierarchy in Python -2.2 [#exceptions-stdlib]_. Its name comes directly from the time when -it resided in the ``weakref`` module. Unfortunately its name does not -suggest its connection to weak references and thus deserves a -renaming. - - -NameError -''''''''' - -Renamed to NamespaceError. - -While NameError suggests its common use, it is not entirely apparent. -Making it a superclass for namespace-related exceptions warrants a -renaming to make its use abundantly clear. Plus the documentation of -the exception module [#exceptions-stdlib]_ states that it was actually -meant for global names and not for just any exception. - - -RuntimeWarning -'''''''''''''' - -Renamed to SemanticsWarning. - -RuntimeWarning is supposed to represent semantic changes coming in the -future. But while saying that it affects the "runtime" is true, -flat-out stating that it is a semantic change is much clearer, -eliminating any possible association of the term "runtime" with the -virtual machine. - - Change of Position in the Exception Hierarchy --------------------------------------------- -KeyboardInterrupt, MemoryError, and SystemError -''''''''''''''''''''''''''''''''''''''''''''''' - -Inherit from CriticalError instead of from Exception. - -These three exceptions are not standard errors by any means. They are -raised asynchronously by the interpreter when something specific has -occurred. Thus they warrant not inheriting from Exception but from an -entirely separate exception that will not be caught by a bare -``except`` clause. - - -StopIteration and SystemExit -'''''''''''''''''''''''''''' - -Inherit from ControlFlowException instead of from Exception. - -By having these exceptions no longer inherit from Exception they will -not be accidentally caught by a bare ``except`` clause. - - NotImplementedError ''''''''''''''''''' -Inherits from Exception instead of from RuntimeError (renamed to -UserError). +Inherits from Exception instead of from RuntimeError. + Originally inheriting from RuntimeError, NotImplementedError does not have any direct relation to the exception meant for use in user code @@ -387,20 +289,6 @@ preserving backwards-compatibility. -Renamed Exceptions -'''''''''''''''''' - -Renamed exceptions will directly subclass the new names. When the old -exceptions are instantiated (which occurs when an exception is caught, -either by a ``try`` statement or by propagating to the top of the -execution stack), a PendingDeprecationWarning will be raised. - -This should properly preserve backwards-compatibility as old usage -won't change and the new names can also be used to catch exceptions -using the old names. The warning of the deprecation is also kept -simple. - - New Inheritance for Old Exceptions '''''''''''''''''''''''''''''''''' @@ -428,21 +316,23 @@ Required Superclass for ``raise`` --------------------------------- -A SemanticsWarning will be raised when an object is passed to +A DeprecationWarning will be raised when an object is passed to ``raise`` that does not have the proper inheritance. Removal of Bare ``except`` Clauses ---------------------------------- -A SemanticsWarning will be raised for all bare ``except`` clauses. +A RuntimeWarning will be raised for all bare ``except`` clauses that +catch an exception that does not inherit from Exception. Rejected Ideas ============== -Threads on python-dev discussing this PEP can be found at -[#python-dev-thread1]_ and [#python-dev-thread2]_ +Multiple threads on python-dev discussing this PEP have lead to +various ideas being rejected [#python-dev-thread1]_, +[#python-dev-thread2]_, [#python-dev-thread3]_. KeyboardInterrupt inheriting from ControlFlowException @@ -452,8 +342,7 @@ Some view the exception more as control flow being caused by the user. But with its asynchronous cause (the user is able to trigger the exception at any point in code) its proper place is inheriting from -CriticalException. It also keeps the name of the exception from being -"CriticalError". +CriticalError. Other Names for BaseException and Exception @@ -508,7 +397,7 @@ ---------------------------------- Proposed because a SystemError is meant to lead to a system exit, the -idea was removed since CriticalException indicates this better. +idea was removed since CriticalError indicates this better. ControlFlowException Under Exception @@ -529,18 +418,33 @@ Python have default behavior [#python-dev3]_. -Open Issues -=========== +Rename NameError to NamespaceError +---------------------------------- -Remove ControlFlowException? +NameError is considered more succinct and leaves open no possible mistyping of +the capitalization of "Namespace" [#python-dev5]_. + + +Renaming RuntimeError or Introducing SimpleError +'''''''''''''''''''''''''''''''''''''''''''''''' + +The thinking was that RuntimeError was in no way an obvious name for +an exception meant to be used when a situation did not call for the +creation of a new exception. The renaming was rejected on the basis +that the exception is already used throughout the interpreter [#python-dev6]_. +Rejection of SimpleError was founded on the thought that people +should be free to use whatever exception they choose and not have one +so blatently suggested [#python-dev7]_. + +Renaming Existing Exceptions ---------------------------- -It has been suggested that ControlFlowException is not needed. Since -the desire to catch any control flow exception will be atypical, the -suggestion is to just remove the exception and let the exceptions that -inherited from it inherit directly from BaseException. This still -preserves the seperation from Exception which is one of the driving -factors behind the introduction of ControlFlowException. +Various renamings were suggested but non garnered more than a +0 vote +(renaming ReferenceError to WeakReferenceError). The thinking was +that the existing names were fine and no one had actively complained +about them ever. To minimize backwards-compatibility issues and +causing existing Python programmers extra pain, the renamings were +removed. Acknowledgements @@ -548,51 +452,56 @@ Thanks to Robert Brewer, Josiah Carlson, Nick Coghlan, Timothy Delaney, Jack Diedrich, Fred L. Drake, Jr., Philip J. Eby, Greg Ewing, -James Y. Knight, MA Lemburg, Guido van Rossum, Stephen J. Turnbull and -everyone else I missed for participating in the discussion. +James Y. Knight, MA Lemburg, Guido van Rossum, Stephen J. Turnbull, +Raymond Hettinger, and everyone else I missed for participating in the +discussion. References ========== .. [#PEP342] PEP 342 (Coroutines via Enhanced Generators) - (http://www.python.org/peps/pep-0342.html) + http://www.python.org/peps/pep-0342.html .. [#PEP344] PEP 344 (Exception Chaining and Embedded Tracebacks) - (http://www.python.org/peps/pep-0344.html) + http://www.python.org/peps/pep-0344.html .. [#Summary2004-08-01] python-dev Summary (An exception is an exception, unless it doesn't inherit from Exception) - (http://www.python.org/dev/summary/2004-08-01_2004-08-15.html#an-exception-is-an-exception-unless-it-doesn-t-inherit-from-exception) - -.. [#Summary2004-09-01] python-dev Summary (Cleaning the Exception House) - (http://www.python.org/dev/summary/2004-09-01_2004-09-15.html#cleaning-the-exception-house) - -.. [#python-dev1] python-dev email (Exception hierarchy) - (http://mail.python.org/pipermail/python-dev/2004-August/047908.html) - -.. [#python-dev2] python-dev email (Dangerous exceptions) - (http://mail.python.org/pipermail/python-dev/2004-September/048681.html) + http://www.python.org/dev/summary/2004-08-01_2004-08-15.html#an-exception-is-an-exception-unless-it-doesn-t-inherit-from-exception .. [#python-dev3] python-dev email (PEP, take 2: Exception Reorganization for Python 3.0) - (http://mail.python.org/pipermail/python-dev/2005-August/055116.html) + http://mail.python.org/pipermail/python-dev/2005-August/055116.html .. [#exceptions-stdlib] exceptions module - (http://docs.python.org/lib/module-exceptions.html) + http://docs.python.org/lib/module-exceptions.html .. [#python-dev-thread1] python-dev thread (Pre-PEP: Exception Reorganization for Python 3.0) - (http://mail.python.org/pipermail/python-dev/2005-July/055020.html, - http://mail.python.org/pipermail/python-dev/2005-August/055065.html) + http://mail.python.org/pipermail/python-dev/2005-July/055020.html, + http://mail.python.org/pipermail/python-dev/2005-August/055065.html .. [#python-dev-thread2] python-dev thread (PEP, take 2: Exception Reorganization for Python 3.0) - (http://mail.python.org/pipermail/python-dev/2005-August/055103.html) + http://mail.python.org/pipermail/python-dev/2005-August/055103.html + +.. [#python-dev-thread3] python-dev thread (Reorg PEP checked in) + http://mail.python.org/pipermail/python-dev/2005-August/055138.html .. [#python-dev4] python-dev email (Pre-PEP: Exception Reorganization for Python 3.0) - (http://mail.python.org/pipermail/python-dev/2005-July/055019.html) + http://mail.python.org/pipermail/python-dev/2005-July/055019.html + +.. [#python-dev5] python-dev email (PEP, take 2: Exception Reorganization for +Python 3.0) + http://mail.python.org/pipermail/python-dev/2005-August/055159.html + +.. [#python-dev6] python-dev email (Exception Reorg PEP checked in) + http://mail.python.org/pipermail/python-dev/2005-August/055149.html + +.. [#python-dev7] python-dev email (Exception Reorg PEP checked in) + http://mail.python.org/pipermail/python-dev/2005-August/055175.html Copyright From pje at users.sourceforge.net Sun Aug 7 06:50:47 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 21:50:47 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.60, 1.61 pkg_resources.txt, 1.1, 1.2 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26863 Modified Files: pkg_resources.py pkg_resources.txt Log Message: Document utility routines. Made ``split_sections()`` not lowercase its section headers any more, since e.g. entry point group names are case-sensitive. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.60 retrieving revision 1.61 diff -u -d -r1.60 -r1.61 --- pkg_resources.py 7 Aug 2005 01:03:34 -0000 1.60 +++ pkg_resources.py 7 Aug 2005 04:50:44 -0000 1.61 @@ -1557,26 +1557,29 @@ yield '*final' # ensure that alpha/beta/candidate are before final def parse_version(s): - """Convert a version string to a sortable key + """Convert a version string to a chronologically-sortable key This is a rough cross between distutils' StrictVersion and LooseVersion; if you give it versions that would work with StrictVersion, then it behaves - the same; otherwise it acts like a slightly-smarter LooseVersion. + the same; otherwise it acts like a slightly-smarter LooseVersion. It is + *possible* to create pathological version coding schemes that will fool + this parser, but they should be very rare in practice. The returned value will be a tuple of strings. Numeric portions of the version are padded to 8 digits so they will compare numerically, but without relying on how numbers compare relative to strings. Dots are dropped, but dashes are retained. Trailing zeros between alpha segments - or dashes are suppressed, so that e.g. 2.4.0 is considered the same as 2.4. - Alphanumeric parts are lower-cased. + or dashes are suppressed, so that e.g. "2.4.0" is considered the same as + "2.4". Alphanumeric parts are lower-cased. - The algorithm assumes that strings like '-' and any alpha string > "final" - represents a "patch level". So, "2.4-1" is assumed to be a branch or patch - of "2.4", and therefore "2.4.1" is considered newer than "2.4-1". + The algorithm assumes that strings like "-" and any alpha string that + alphabetically follows "final" represents a "patch level". So, "2.4-1" + is assumed to be a branch or patch of "2.4", and therefore "2.4.1" is + considered newer than "2.4-1", whic in turn is newer than "2.4". Strings like "a", "b", "c", "alpha", "beta", "candidate" and so on (that come before "final" alphabetically) are assumed to be pre-release versions, - and so the version "2.4" is considered newer than "2.4a1". + so that the version "2.4" is considered newer than "2.4a1". Finally, to handle miscellaneous cases, the strings "pre", "preview", and "rc" are treated as if they were "c", i.e. as though they were release @@ -1596,7 +1599,6 @@ - class EntryPoint(object): """Object representing an importable location""" @@ -1810,7 +1812,7 @@ dm = self.__dep_map = {None: []} for name in 'requires.txt', 'depends.txt': for extra,reqs in split_sections(self._get_metadata(name)): - dm.setdefault(extra,[]).extend(parse_requirements(reqs)) + dm.setdefault(extra.lower(),[]).extend(parse_requirements(reqs)) return dm _dep_map = property(_dep_map) @@ -2099,7 +2101,7 @@ def split_sections(s): """Split a string or iterable thereof into (section,content) pairs - Each ``section`` is a lowercase version of the section header ("[section]") + Each ``section`` is a stripped version of the section header ("[section]") and each ``content`` is a list of stripped lines excluding blank lines and comment-only lines. If there are any such lines before the first section header, they're returned in a first ``section`` of ``None``. @@ -2111,7 +2113,7 @@ if line.endswith("]"): if section or content: yield section, content - section = line[1:-1].strip().lower() + section = line[1:-1].strip() content = [] else: raise ValueError("Invalid section heading", line) Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- pkg_resources.txt 7 Aug 2005 01:03:35 -0000 1.1 +++ pkg_resources.txt 7 Aug 2005 04:50:44 -0000 1.2 @@ -2,10 +2,10 @@ Package Discovery and Resource Access using ``pkg_resources`` ============================================================= -The ``pkg_resources`` module, distributed with ``setuptools``, provides -features for Python libraries to access resource files, and for extensible +The ``pkg_resources`` module distributed with ``setuptools`` provides an API +for Python libraries to access their resource files, and for extensible applications and frameworks to automatically discover plugins. It also -provides runtime support for using C extensions that are inside zipfile +provides runtime support for using C extensions that are inside zipfile-format eggs, support for merging packages that have separately-distributed modules or subpackages, and APIs for managing Python's current "working set" of active packages. @@ -96,38 +96,128 @@ Parsing Utilities ----------------- -yield_lines - XXX +``parse_version(version)`` + Parse a project's version string, returning a value that can be used to + compare versions by chronological order. Semantically, the format is a + rough cross between distutils' ``StrictVersion`` and ``LooseVersion`` + classes; if you give it versions that would work with ``StrictVersion``, + then they will compare the same way. Otherwise, comparisons are more like + a "smarter" form of ``LooseVersion``. It is *possible* to create + pathological version coding schemes that will fool this parser, but they + should be very rare in practice. -split_sections - XXX + The returned value will be a tuple of strings. Numeric portions of the + version are padded to 8 digits so they will compare numerically, but + without relying on how numbers compare relative to strings. Dots are + dropped, but dashes are retained. Trailing zeros between alpha segments + or dashes are suppressed, so that e.g. "2.4.0" is considered the same as + "2.4". Alphanumeric parts are lower-cased. -parse_version - XXX + The algorithm assumes that strings like "-" and any alpha string that + alphabetically follows "final" represents a "patch level". So, "2.4-1" + is assumed to be a branch or patch of "2.4", and therefore "2.4.1" is + considered newer than "2.4-1", whic in turn is newer than "2.4". -safe_name - XXX + Strings like "a", "b", "c", "alpha", "beta", "candidate" and so on (that + come before "final" alphabetically) are assumed to be pre-release versions, + so that the version "2.4" is considered newer than "2.4a1". -safe_version - XXX + Finally, to handle miscellaneous cases, the strings "pre", "preview", and + "rc" are treated as if they were "c", i.e. as though they were release + candidates, and therefore are not as new as a version string that does not + contain them. + +``yield_lines(strs)`` + Yield non-empty/non-comment lines from a string/unicode or a possibly- + nested sequence thereof. If `strs` is an instance of ``basestring``, it + is split into lines, and each non-blank, non-comment line is yielded after + stripping leading and trailing whitespace. (Lines whose first non-blank + character is ``#`` are considered comment lines.) + + If `strs` is not an instance of ``basestring``, it is iterated over, and + each item is passed recursively to ``yield_lines()``, so that an arbitarily + nested sequence of strings, or sequences of sequences of strings can be + flattened out to the lines contained therein. So for example, passing + a file object or a list of strings to ``yield_lines`` will both work. + (Note that between each string in a sequence of strings there is assumed to + be an implicit line break, so lines cannot bridge two strings in a + sequence.) + + This routine is used extensively by ``pkg_resources`` to parse metadata + and file formats of various kinds, and most other ``pkg_resources`` + parsing functions that yield multiple values will use it to break up their + input. However, this routine is idempotent, so calling ``yield_lines()`` + on the output of another call to ``yield_lines()`` is completely harmless. + +``split_sections(strs)`` + Split a string (or possibly-nested iterable thereof), yielding ``(section, + content)`` pairs found using an ``.ini``-like syntax. Each ``section`` is + a whitespace-stripped version of the section name ("``[section]``") + and each ``content`` is a list of stripped lines excluding blank lines and + comment-only lines. If there are any non-blank, non-comment lines before + the first section header, they're yielded in a first ``section`` of + ``None``. + + This routine uses ``yield_lines()`` as its front end, so you can pass in + anything that ``yield_lines()`` accepts, such as an open text file, string, + or sequence of strings. ``ValueError`` is raised if a malformed section + header is found (i.e. a line starting with ``[`` but not ending with + ``]``). + + Note that this simplistic parser assumes that any line whose first nonblank + character is ``[`` is a section heading, so it can't support .ini format + variations that allow ``[`` as the first nonblank character on other lines. + +``safe_name(name)`` + Return a "safe" form of a project's name, suitable for use in a + ``Requirement`` string, as a distribution name, or a PyPI project name. + All non-alphanumeric runs are condensed to single "-" characters, such that + a name like "The $$$ Tree" becomes "The-Tree". Note that if you are + generating a filename from this value you should replace the "-" characters + with underscores ("_") because setuptools and the distutils + +``safe_version(version)`` + Similar to ``safe_name()`` except that spaces in the input become dots, and + dots are allowed to exist in the output. As with ``safe_name()``, if you + are generating a filename from this you should replace any "-" characters + in the output with underscores. Platform Utilities ------------------ -get_platform - XXX +``get_platform()`` + Return this platform's identifier string. For Windows, the return value + is ``"win32"``, and for Mac OS X it is a string of the form + ``"macosx-10.4-ppc"``. All other platforms return the same uname-based + string that the ``distutils.util.get_platform()`` function returns. -compatible_platforms - XXX +``compatible_platforms(provided, required)`` + Return true if a distribution built on the `provided` platform may be used + on the `required` platform. If either platform value is ``None``, it is + considered a wildcard, and the platforms are therefore compatible. + Likewise, if the platform strings are equal, they're also considered + compatible, and ``True`` is returned. Currently, the only non-equal + platform strings that are considered compatible are Mac OS X platform + strings with the same hardware type (e.g. ``ppc``) and major version + (e.g. ``10``) with the `provided` platform's minor version being less than + or equal to the `required` platform's minor version. File/Path Utilities ------------------- -ensure_directory - XXX +``ensure_directory(path)`` + Ensure that the parent directory (``os.path.dirname``) of `path` actually + exists, using ``os.makedirs()`` if necessary. -normalize_path - XXX +``normalize_path(path)`` + Return a "normalized" version of `path`, such that two paths represent + the same filesystem location if they have equal ``normalized_path()`` + values. Specifically, this is a shortcut for calling ``os.path.realpath`` + and ``os.path.normcase`` on `path`. Unfortunately, on certain platforms + (notably Cygwin and Mac OS X) the ``normcase`` function does not accurately + reflect the platform's case-sensitivity, so there is always the possibility + of two apparently-different paths being equal on such platforms. + From pje at users.sourceforge.net Sun Aug 7 07:52:49 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 06 Aug 2005 22:52:49 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.61, 1.62 pkg_resources.txt, 1.2, 1.3 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv722 Modified Files: pkg_resources.py pkg_resources.txt Log Message: Add docs for exceptions, and for much of the ResourceManager API. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.61 retrieving revision 1.62 diff -u -d -r1.61 -r1.62 --- pkg_resources.py 7 Aug 2005 04:50:44 -0000 1.61 +++ pkg_resources.py 7 Aug 2005 05:52:36 -0000 1.62 @@ -656,44 +656,44 @@ class ResourceManager: """Manage resource extraction and packages""" - extraction_path = None def __init__(self): self.cached_files = {} - def resource_exists(self, package_name, resource_name): - """Does the named resource exist in the named package?""" - return get_provider(package_name).has_resource(resource_name) + def resource_exists(self, package_or_requirement, resource_name): + """Does the named resource exist?""" + return get_provider(package_or_requirement).has_resource(resource_name) - def resource_isdir(self, package_name, resource_name): - """Does the named resource exist in the named package?""" - return get_provider(package_name).resource_isdir(resource_name) + def resource_isdir(self, package_or_requirement, resource_name): + """Is the named resource an existing directory?""" + return get_provider(package_or_requirement).resource_isdir( + resource_name + ) - def resource_filename(self, package_name, resource_name): + def resource_filename(self, package_or_requirement, resource_name): """Return a true filesystem path for specified resource""" - return get_provider(package_name).get_resource_filename( - self,resource_name + return get_provider(package_or_requirement).get_resource_filename( + self, resource_name ) - def resource_stream(self, package_name, resource_name): + def resource_stream(self, package_or_requirement, resource_name): """Return a readable file-like object for specified resource""" - return get_provider(package_name).get_resource_stream( + return get_provider(package_or_requirement).get_resource_stream( self, resource_name ) - def resource_string(self, package_name, resource_name): + def resource_string(self, package_or_requirement, resource_name): """Return specified resource as a string""" - return get_provider(package_name).get_resource_string( + return get_provider(package_or_requirement).get_resource_string( self, resource_name ) - def resource_listdir(self, package_name, resource_name): - return get_provider(package_name).resource_listdir(resource_name) - - - - + def resource_listdir(self, package_or_requirement, resource_name): + """List the contents of the named resource directory""" + return get_provider(package_or_requirement).resource_listdir( + resource_name + ) def get_cache_path(self, archive_name, names=()): """Return absolute location in cache for `archive_name` and `names` @@ -701,7 +701,7 @@ The parent directory of the resulting path will be created if it does not already exist. `archive_name` should be the base filename of the enclosing egg (which may not be the name of the enclosing zipfile!), - including the ".egg" extension. `names`, if provided, should be a + including its ".egg" extension. `names`, if provided, should be a sequence of path name parts "under" the egg's extraction location. This method should only be called by resource providers that need to @@ -739,7 +739,12 @@ def set_extraction_path(self, path): """Set the base path where resources will be extracted to, if needed. - If not set, this defaults to ``os.expanduser("~/.python-eggs")``. + If you do not call this routine before any extractions take place, the + path defaults to the return value of ``get_default_cache()``. (Which + is based on the ``PYTHON_EGG_CACHE`` environment variable, with various + platform-specific fallbacks. See that routine's documentation for more + details.) + Resources are extracted to subdirectories of this path based upon information given by the ``IResourceProvider``. You may set this to a temporary directory, but then you must call ``cleanup_resources()`` to @@ -772,11 +777,6 @@ - - - - - def get_default_cache(): """Determine the default cache location Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- pkg_resources.txt 7 Aug 2005 04:50:44 -0000 1.2 +++ pkg_resources.txt 7 Aug 2005 05:52:37 -0000 1.3 @@ -46,6 +46,8 @@ API Reference ------------- +XXX Namespace stuff, + ``WorkingSet`` Objects ====================== @@ -74,24 +76,170 @@ ``Distribution`` Objects ======================== -XXX +Factories: get_provider, get_distribution, find_distributions; see also +WorkingSet and Environment APIs. -``ResourceManager`` Objects -=========================== +``ResourceManager`` API +======================= -XXX +The ``ResourceManager`` class provides uniform access to package resources, +whether those resources exist as files and directories or are compressed in +an archive of some kind. + +Normally, you do not need to create or explicitly manage ``ResourceManager`` +instances, as the ``pkg_resources`` module creates a global instance for you, +and makes most of its methods available as top-level names in the +``pkg_resources`` module namespace. So, for example, this code actually +calls the ``resource_string()`` method of the global ``ResourceManager``:: + + import pkg_resources + my_data = pkg_resources.resource_string(__name__, "foo.dat") + +Thus, you can use the APIs below without needing a ``ResourceManager`` +instance; just import and use them. + + +Basic Resource Access +--------------------- + +XXX explain resource paths, layout, etc. here + +``resource_exists(package_or_requirement, resource_name)`` + Does the named resource exist? + +``resource_stream(package_or_requirement, resource_name)`` + Return a readable file-like object for specified resource + +``resource_string(package_or_requirement, resource_name)`` + Return specified resource as a string + +``resource_isdir(package_or_requirement, resource_name)`` + Is the named resource an existing directory? + +``resource_listdir(package_or_requirement, resource_name)`` + List the contents of the named resource directory + + +Resource Extraction +------------------- + +``resource_filename(package_or_requirement, resource_name)`` + Sometimes, it is not sufficient to access a resource in string or stream + form, and a true filesystem filename is needed. In such cases, you can + use this method (or module-level function) to obtain a filename for a + resource. If the resource is in an archive distribution (such as a zipped + egg), it will be extracted to a cache directory, and the filename within + the cache will be returned. If the named resource is a directory, then + all resources within that directory (including subdirectories) are also + extracted. If the named resource is a C extension or "eager resource" + (see the ``setuptools`` documentation for details), then all C extensions + and eager resources are extracted at the same time. + + Archived resources are extracted to a cache location that can be managed by + the following two methods: + +``set_extraction_path(path)`` + Set the base path where resources will be extracted to, if needed. + + If you do not call this routine before any extractions take place, the + path defaults to the return value of ``get_default_cache()``. (Which is + based on the ``PYTHON_EGG_CACHE`` environment variable, with various + platform-specific fallbacks. See that routine's documentation for more + details.) + + Resources are extracted to subdirectories of this path based upon + information given by the ``IResourceProvider``. You may set this to a + temporary directory, but then you must call ``cleanup_resources()`` to + delete the extracted files when done. There is no guarantee that + ``cleanup_resources()`` will be able to remove all extracted files. + + (Note: you may not change the extraction path for a given resource + manager once resources have been extracted, unless you first call + ``cleanup_resources()``.) + +``cleanup_resources(force=False)`` + Delete all extracted resource files and directories, returning a list + of the file and directory names that could not be successfully removed. + This function does not have any concurrency protection, so it should + generally only be called when the extraction path is a temporary + directory exclusive to a single process. This method is not + automatically called; you must call it explicitly or register it as an + ``atexit`` function if you wish to ensure cleanup of a temporary + directory used for extractions. + + +"Provider" Interface +-------------------- + +If you are implementing an ``IResourceProvider`` and/or ``IMetadataProvider`` +for a new distribution archive format, you may need to use the following +``ResourceManager`` methods to co-ordinate extraction of resources to the +filesystem. If you're not implementing an archive format, however, you have +no need to use these methods. Unlike the other methods listed above, they are +*not* available as top-level functions tied to the global ``ResourceManager``; +you must therefore have an explicit ``ResourceManager`` instance to use them. + +``get_cache_path(archive_name, names=())`` + Return absolute location in cache for `archive_name` and `names` + + The parent directory of the resulting path will be created if it does + not already exist. `archive_name` should be the base filename of the + enclosing egg (which may not be the name of the enclosing zipfile!), + including its ".egg" extension. `names`, if provided, should be a + sequence of path name parts "under" the egg's extraction location. + + This method should only be called by resource providers that need to + obtain an extraction location, and only for names they intend to + extract, as it tracks the generated names for possible cleanup later. + +``postprocess(tempname, filename)`` + Perform any platform-specific postprocessing of `tempname`. + Resource providers should call this method ONLY after successfully + extracting a compressed resource. They must NOT call it on resources + that are already in the filesystem. + + `tempname` is the current (temporary) name of the file, and `filename` + is the name it will be renamed to by the caller after this routine + returns. Exceptions ========== -XXX ResolutionError, VersionConflict, DistributionNotFound, UnknownExtra +``pkg_resources`` provides a simple exception hierarchy for problems that may +occur when processing requests to locate and activate packages:: + + ResolutionError + DistributionNotFound + VersionConflict + UnknownExtra + +``ResolutionError`` + This class is used as a base class for the other three exceptions, so that + you can catch all of them with a single "except" clause. It is also raised + directly for miscellaneous requirement-resolution problems like trying to + run a script that doesn't exist in the distribution it was requested from. + +``DistributionNotFound`` + A distribution needed to fulfill a requirement could not be found. + +``VersionConflict`` + The requested version of a project conflicts with an already-activated + version of the same project. + +``UnknownExtra`` + One of the "extras" requested was not recognized by the distribution it + was requested from. Utility Functions ================= +In addition to its high-level APIs, ``pkg_resources`` also includes several +generally-useful utility routines. These routines are used to implement the +high-level APIs, but can also be quite useful by themselves. + Parsing Utilities ----------------- @@ -203,6 +351,14 @@ (e.g. ``10``) with the `provided` platform's minor version being less than or equal to the `required` platform's minor version. +``get_default_cache()`` + Determine the default cache location for extracting resources from zipped + eggs. This routine returns the ``PYTHON_EGG_CACHE`` environment variable, + if set. Otherwise, on Windows, it returns a "Python-Eggs" subdirectory of + the user's "Application Data" directory. On all other systems, it returns + ``os.path.expanduser("~/.python-eggs")`` if ``PYTHON_EGG_CACHE`` is not + set. + File/Path Utilities ------------------- From rhettinger at users.sourceforge.net Sun Aug 7 15:02:55 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 07 Aug 2005 06:02:55 -0700 Subject: [Python-checkins] python/dist/src/Include setobject.h,2.8,2.9 Message-ID: Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2124/Include Modified Files: setobject.h Log Message: * Bring in INIT_NONZERO_SET_SLOTS macro from dictionary code. * Bring in free list from dictionary code. * Improve several comments. * Differencing can leave many dummy entries. If more than 1/6 are dummies, then resize them away. * Factor-out common code with new macro, PyAnySet_CheckExact. Index: setobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/setobject.h,v retrieving revision 2.8 retrieving revision 2.9 diff -u -d -r2.8 -r2.9 --- setobject.h 2 Aug 2005 03:45:16 -0000 2.8 +++ setobject.h 7 Aug 2005 13:02:52 -0000 2.9 @@ -59,12 +59,16 @@ PyAPI_DATA(PyTypeObject) PySet_Type; PyAPI_DATA(PyTypeObject) PyFrozenSet_Type; -/* Invariants for frozensets only: +/* Invariants for frozensets: * data is immutable. * hash is the hash of the frozenset or -1 if not computed yet. + * Invariants for sets: + * hash is -1 */ #define PyFrozenSet_CheckExact(ob) ((ob)->ob_type == &PyFrozenSet_Type) +#define PyAnySet_CheckExact(ob) \ + ((ob)->ob_type == &PySet_Type || (ob)->ob_type == &PyFrozenSet_Type) #define PyAnySet_Check(ob) \ ((ob)->ob_type == &PySet_Type || (ob)->ob_type == &PyFrozenSet_Type || \ PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \ From rhettinger at users.sourceforge.net Sun Aug 7 15:02:55 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 07 Aug 2005 06:02:55 -0700 Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.44,1.45 Message-ID: Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2124/Objects Modified Files: setobject.c Log Message: * Bring in INIT_NONZERO_SET_SLOTS macro from dictionary code. * Bring in free list from dictionary code. * Improve several comments. * Differencing can leave many dummy entries. If more than 1/6 are dummies, then resize them away. * Factor-out common code with new macro, PyAnySet_CheckExact. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.44 retrieving revision 1.45 diff -u -d -r1.44 -r1.45 --- setobject.c 6 Aug 2005 18:57:13 -0000 1.44 +++ setobject.c 7 Aug 2005 13:02:53 -0000 1.45 @@ -15,13 +15,22 @@ /* Object used as dummy key to fill deleted entries */ static PyObject *dummy = NULL; /* Initialized by first call to make_new_set() */ +#define INIT_NONZERO_SET_SLOTS(so) do { \ + (so)->table = (so)->smalltable; \ + (so)->mask = PySet_MINSIZE - 1; \ + (so)->hash = -1; \ + } while(0) + #define EMPTY_TO_MINSIZE(so) do { \ memset((so)->smalltable, 0, sizeof((so)->smalltable)); \ (so)->used = (so)->fill = 0; \ - (so)->table = (so)->smalltable; \ - (so)->mask = PySet_MINSIZE - 1; \ + INIT_NONZERO_SET_SLOTS(so); \ } while(0) +/* Reuse scheme to save calls to malloc, free, and memset */ +#define MAXFREESETS 80 +static PySetObject *free_sets[MAXFREESETS]; +static int num_free_sets = 0; /* The basic lookup function used by all operations. @@ -30,13 +39,15 @@ chaining would be substantial (100% with typical malloc overhead). The initial probe index is computed as hash mod the table size. Subsequent -probe indices are computed as explained earlier. +probe indices are computed as explained in Objects/dictobject.c. All arithmetic on hash should ignore overflow. -This function must never return NULL; failures are indicated by returning -a setentry* for which the value field is NULL. Exceptions are never -reported by this function, and outstanding exceptions are maintained. +The lookup function always succeeds and nevers return NULL. This simplifies +and speeds client functions which do won't have to test for and handle +errors. To meet that requirement, any errors generated by a user defined +__cmp__() function are simply cleared and ignored. +Previously outstanding exceptions are maintained. */ static setentry * @@ -187,7 +198,7 @@ freeslot = entry; } } else { - /* Simplified loop that can assume are no dummy entries */ + /* Simplified loop when there are no dummy entries. */ if (entry->hash == hash && _PyString_Eq(entry->key, key)) return entry; for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { @@ -347,7 +358,7 @@ set_insert_key(so, key, hash); if (!(so->used > n_used && so->fill*3 >= (so->mask+1)*2)) return 0; - return set_table_resize(so, so->used*(so->used>50000 ? 2 : 4)); + return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); } #define DISCARD_NOTFOUND 0 @@ -439,7 +450,6 @@ if (table_is_malloced) PyMem_DEL(table); - so->hash = -1; return 0; } @@ -710,16 +720,24 @@ } /* create PySetObject structure */ - so = (PySetObject *)type->tp_alloc(type, 0); - if (so == NULL) - return NULL; + if (num_free_sets && + (type == &PySet_Type || type == &PyFrozenSet_Type)) { + so = free_sets[--num_free_sets]; + assert (so != NULL && PyAnySet_CheckExact(so)); + so->ob_type = type; + _Py_NewReference((PyObject *)so); + EMPTY_TO_MINSIZE(so); + PyObject_GC_Track(so); + } else { + so = (PySetObject *)type->tp_alloc(type, 0); + if (so == NULL) + return NULL; + /* tp_alloc has already zeroed the structure */ + assert(so->table == NULL && so->fill == 0 && so->used == 0); + INIT_NONZERO_SET_SLOTS(so); + } - /* tp_alloc has already zeroed the structure */ - assert(so->table == NULL && so->fill == 0 && so->used == 0); - so->table = so->smalltable; - so->mask = PySet_MINSIZE - 1; so->lookup = set_lookkey_string; - so->hash = -1; so->weakreflist = NULL; if (iterable != NULL) { @@ -767,6 +785,13 @@ void PySet_Fini(void) { + PySetObject *so; + + while (num_free_sets) { + num_free_sets--; + so = free_sets[num_free_sets]; + PyObject_GC_Del(so); + } Py_XDECREF(dummy); Py_XDECREF(emptyfrozenset); } @@ -797,7 +822,10 @@ if (so->table != so->smalltable) PyMem_DEL(so->table); - so->ob_type->tp_free(so); + if (num_free_sets < MAXFREESETS && PyAnySet_CheckExact(so)) + free_sets[num_free_sets++] = so; + else + so->ob_type->tp_free(so); Py_TRASHCAN_SAFE_END(so) } @@ -1079,6 +1107,11 @@ Py_DECREF(it); if (PyErr_Occurred()) return NULL; + /* If more than 1/6 are dummies, then resize them away. */ + if ((so->fill - so->used) * 6 < so->mask) + Py_RETURN_NONE; + if (set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4) == -1) + return NULL; Py_RETURN_NONE; } From akuchling at users.sourceforge.net Sun Aug 7 15:27:56 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Sun, 07 Aug 2005 06:27:56 -0700 Subject: [Python-checkins] python/nondist/peps pep-0008.txt,1.25,1.26 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6634 Modified Files: pep-0008.txt Log Message: Record BDFL opinion on exception-raising style Index: pep-0008.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0008.txt,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- pep-0008.txt 6 Aug 2004 18:47:26 -0000 1.25 +++ pep-0008.txt 7 Aug 2005 13:27:54 -0000 1.26 @@ -546,6 +546,13 @@ class MessageError(Exception): """Base class for errors in the email package.""" + When raising an exception, use "raise ValueError('message')" + instead of the older form "raise ValueError, 'message'". The + paren-using form is preferred because when the exception + arguments are long or include string formatting, you don't need + to use line continuation characters thanks to the containing + parentheses. The older form will be removed in Python 3000. + - Use string methods instead of the string module unless backward-compatibility with versions earlier than Python 2.0 is important. String methods are always much faster and share the From loewis at users.sourceforge.net Sun Aug 7 16:17:45 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 07:17:45 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.3,1.4 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13976 Modified Files: pep-0347.txt Log Message: - add more rationale for using svn. - add discussion section. - change procedure to create a single repository, add conversion script. - require python-cvsroot to be preserved forever. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- pep-0347.txt 5 Aug 2005 07:26:32 -0000 1.3 +++ pep-0347.txt 7 Aug 2005 14:17:43 -0000 1.4 @@ -37,7 +37,12 @@ directories, while keeping the history of these files. - support for change sets (sets of correlated changes to multiple - files) through global revision numbers. + files) through global revision numbers. Change sets are + transactional. + +- atomic, fast tagging: a cvs tag might take many minutes; a + subversion tag (svn cp) will complete quickly, and atomically. + Likewise, branches are very efficient. - support for offline diffs, which is useful when creating patches. @@ -75,8 +80,7 @@ 3. 24 hours after the last commit, download the CVS repository. -4. Convert the CVS repository into two Subversion repositories, one - for Distutils and one for Python. +4. Convert the CVS repository into a Subversion repository. 5. Publish the repositories with write access for committers, and read-only anonymous access. @@ -93,16 +97,6 @@ initially, for the Python CVS as well, since various committers also have a username/password pair for the www SVN repository already. -Alternatives to password-based access include: - -- Subversion over SSH, using SSH key pairs. This would require - committers to be given accounts on the machine, which currently is - ruled out by the administration policy of svn.python.org. - -- Subversion over WebDAV, using SSL client certificates. This would - work, but would require to administrate a certificate authority. - - Downloading the CVS Repository ------------------------------ @@ -115,14 +109,23 @@ should be verified that the last commit, as recorded on the python-commits mailing list, is indeed included in the tarball. +After the conversion, the converted CVS tarball should be kept +forever on www.python.org/archive/python-cvsroot-.tar.bz2 + Converting the CVS Repository ----------------------------- The Python CVS repository contains two modules: distutils and python. -Keeping them together will produce quite long repository URLs, so it -is more convenient if the Python CVS and the Distutils CVS are -converted into two separate repositories. +The python module is further structured into dist and nondist, +where dist only contains src (the python code proper). nondist +contains various subdirectories. + +These should be reorganized in the Subversion repository to get +shorter URLs, following the /{trunk,tags,branches} +structure. A project will be created for each nondist directory, +plus for src (called python), plus distutils. Reorganizing the +repository is best done in the CVS tree, as shown below. Fsfs should be used as the repository format (requires Subversion 1.1). Fsfs has the advantage of being more backup-friendly, as it @@ -130,21 +133,39 @@ commands to be run. The conversion should be done using the cvs2svn utility, available -e.g. in the cvs2svn Debian package. The command for converting the -Python repository is :: - - cvs2svn -q --encoding=latin1 --force-branch=cnri-16-start \ - --force-branch=descr-branch --force-branch=release152p1-patches \ - --force-tag=r16b1 --fs-type=fsfs -s py.svn.new python/python - -The command to convert the distutils repository is :: +e.g. in the cvs2svn Debian package. As cvs2svn does not currently +support the project/trunk structure, each project needs to be +converted separately. To get each conversion result into a separate +directory in the target repository, svnadmin load must be used. +In summary, the conversion script is:: - cvs2svn -q --encoding=latin1 --fs-type=fsfs -s dist.svn.new python/distutils + #!/bin/sh + rm cvs2svn-* + rm -rf python py.new + tar xjf python-cvsroot.tar.bz2 + rm -rf python/CVSROOT + svnadmin create --fs-type fsfs py.new + mv python/python python/orig + mv python/orig/dist/src python/python + mv python/orig/nondist/* python + # nondist/nondist is empty + rmdir python/nondist + rm -rf python/orig + for a in python/* + do + b=`basename $a` + cvs2svn -q --dump-only --encoding=latin1 --force-branch=cnri-16-start \ + --force-branch=descr-branch --force-branch=release152p1-patches \ + --force-tag=r16b1 $a + svn mkdir -m"Conversion to SVN" file:///`pwd`/py.new/$b + svnadmin load -q --parent-dir $b py.new < cvs2svn-dump + rm cvs2svn-dump + done Sample results of this conversion are available at - | http://www.dcl.hpi.uni-potsdam.de/python/ - | http://www.dcl.hpi.uni-potsdam.de/distutils/ + http://www.dcl.hpi.uni-potsdam.de/pysvn/ + Publish the Repositories @@ -169,6 +190,45 @@ remains available. If desired, write access to the python and distutils modules can be disabled through a CVS commitinfo entry. +Discussion +---------- + +Several alternatives had been suggested to the procedure above. +The rejected alternatives are shortly discussed here: + +- create multiple repositories, one for python and one for + distutils. This would have allowed even shorter URLs, but + was rejected because a single repository supports moving code + across projects. + +- Nick Bastin has offered to host a Perforce repository, instead + of using subversion. Details of that offer are not clear yet. + +- Several people suggested to create the project/trunk structure + through standard cvs2svn, followed by renames. This would have + the disadvantage that old revisions use different path names + than recent revisions; the suggested approach through dump files + works without renames. + +- Several people also expressed concern about the administrative + overhead that hosting the repository on python.org would cause + to pydotorg admins. As a specific alternative, BerliOS has been + suggested. The pydotorg admins themselves haven\'t objected + to the additional workload; migrating the repository again if + they get overworked is an option. + +- People have expressed dislike of the basic auth (username/password) + authentication. Two alternatives have been suggested: + + * Subversion over SSH, using SSH key pairs for a single Unix + account, restricted to the execution of svnserve. The pydotorg + admins have ruled out creation of one account per committer; + whether a single account would be acceptable is not yet + decided. + + * Subversion over WebDAV, using SSL client certificates. This would + work, but would require to administrate a certificate authority. + Copyright --------- From loewis at users.sourceforge.net Sun Aug 7 16:23:33 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 07:23:33 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.4,1.5 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15068 Modified Files: pep-0347.txt Log Message: Fix revision tag. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- pep-0347.txt 7 Aug 2005 14:17:43 -0000 1.4 +++ pep-0347.txt 7 Aug 2005 14:23:31 -0000 1.5 @@ -1,6 +1,6 @@ PEP: 347 Title: Migrating the Python CVS to Subversion -Version: $Revision $ +Version: $Revision$ Last-Modified: $Date$ Author: Martin v. Lwis Discussions-To: From loewis at users.sourceforge.net Sun Aug 7 16:29:01 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 07:29:01 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.5,1.6 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15866 Modified Files: pep-0347.txt Log Message: Fix remaining reference to distutils svn; rename URL to /projects. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- pep-0347.txt 7 Aug 2005 14:23:31 -0000 1.5 +++ pep-0347.txt 7 Aug 2005 14:28:59 -0000 1.6 @@ -82,7 +82,7 @@ 4. Convert the CVS repository into a Subversion repository. -5. Publish the repositories with write access for committers, and +5. Publish the repository with write access for committers, and read-only anonymous access. 6. Disable CVS access on SF. @@ -168,15 +168,17 @@ -Publish the Repositories +Publish the Repository ------------------------ -The repositories should be published at https://svn.python.org/python -and https://svn.python.org/distutils. Read-write access should be -granted through basic authentication to all current SF committers; -read-only anonymous access should also be granted. As an option, -websvn (available e.g. from the Debian websvn package) could be -provided. +The repository should be published at https://svn.python.org/projects. +Read-write access should be granted through basic authentication to +all current SF committers; read-only anonymous access should also be +granted. + +As an option, websvn (available e.g. from the Debian websvn package) +could be provided. Unfortunately, in the test installation, websvn +breaks because it runs out of memory. The current SF project admins should get write access to the password file, in order to create or delete new users. From goodger at users.sourceforge.net Sun Aug 7 18:12:02 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sun, 07 Aug 2005 09:12:02 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.6,1.7 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31928 Modified Files: pep-0347.txt Log Message: added missing "us"; whitespace Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- pep-0347.txt 7 Aug 2005 14:28:59 -0000 1.6 +++ pep-0347.txt 7 Aug 2005 16:11:59 -0000 1.7 @@ -97,6 +97,7 @@ initially, for the Python CVS as well, since various committers also have a username/password pair for the www SVN repository already. + Downloading the CVS Repository ------------------------------ @@ -167,14 +168,13 @@ http://www.dcl.hpi.uni-potsdam.de/pysvn/ - Publish the Repository ------------------------ The repository should be published at https://svn.python.org/projects. Read-write access should be granted through basic authentication to all current SF committers; read-only anonymous access should also be -granted. +granted. As an option, websvn (available e.g. from the Debian websvn package) could be provided. Unfortunately, in the test installation, websvn @@ -192,6 +192,7 @@ remains available. If desired, write access to the python and distutils modules can be disabled through a CVS commitinfo entry. + Discussion ---------- @@ -229,7 +230,9 @@ decided. * Subversion over WebDAV, using SSL client certificates. This would - work, but would require to administrate a certificate authority. + work, but would require us to administrate a certificate + authority. + Copyright --------- From tp-update at paypal.com Sun Aug 7 01:09:59 2005 From: tp-update at paypal.com (tp-update@paypal.com) Date: Sat, 6 Aug 2005 19:09:59 -0400 (EDT) Subject: [Python-checkins] PayPal? Account Review Message-ID: <20050806230959.3F3826D7881@xserve.lmtinc.net> An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20050806/fe670380/attachment.htm From loewis at users.sourceforge.net Sun Aug 7 22:50:39 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 13:50:39 -0700 Subject: [Python-checkins] python/dist/src/Lib/distutils msvccompiler.py, 1.64.2.3, 1.64.2.4 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/distutils In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20948/Lib/distutils Modified Files: Tag: release24-maint msvccompiler.py Log Message: Patch #827386: Support absolute source paths in msvccompiler.py. Index: msvccompiler.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/msvccompiler.py,v retrieving revision 1.64.2.3 retrieving revision 1.64.2.4 diff -u -d -r1.64.2.3 -r1.64.2.4 --- msvccompiler.py 11 Mar 2005 17:20:41 -0000 1.64.2.3 +++ msvccompiler.py 7 Aug 2005 20:50:37 -0000 1.64.2.4 @@ -270,6 +270,8 @@ obj_names = [] for src_name in source_filenames: (base, ext) = os.path.splitext (src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base):] # If abs, chop off leading / if ext not in self.src_extensions: # Better to raise an exception instead of silently continuing # and later complain about sources and targets having From loewis at users.sourceforge.net Sun Aug 7 22:50:40 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 13:50:40 -0700 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.68, 1.1193.2.69 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20948/Misc Modified Files: Tag: release24-maint NEWS Log Message: Patch #827386: Support absolute source paths in msvccompiler.py. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.68 retrieving revision 1.1193.2.69 diff -u -d -r1.1193.2.68 -r1.1193.2.69 --- NEWS 2 Aug 2005 10:30:08 -0000 1.1193.2.68 +++ NEWS 7 Aug 2005 20:50:37 -0000 1.1193.2.69 @@ -53,6 +53,8 @@ Library ------- +- Patch #827386: Support absolute source paths in msvccompiler.py. + - Fix a problem in Tkinter introduced by SF patch #869468: delete bogus __hasattr__ and __delattr__ methods on class Tk that were breaking Tkdnd. From loewis at users.sourceforge.net Sun Aug 7 22:51:07 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 13:51:07 -0700 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1329,1.1330 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21005/Misc Modified Files: NEWS Log Message: Patch #827386: Support absolute source paths in msvccompiler.py. Backported to 2.4. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1329 retrieving revision 1.1330 diff -u -d -r1.1329 -r1.1330 --- NEWS 3 Aug 2005 07:30:10 -0000 1.1329 +++ NEWS 7 Aug 2005 20:51:04 -0000 1.1330 @@ -178,6 +178,8 @@ Library ------- +- Patch #827386: Support absolute source paths in msvccompiler.py. + - Patch #1105730: Apply the new implementation of commonprefix in posixpath to ntpath, macpath, os2emxpath and riscospath. From loewis at users.sourceforge.net Sun Aug 7 22:51:07 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 13:51:07 -0700 Subject: [Python-checkins] python/dist/src/Lib/distutils msvccompiler.py, 1.68, 1.69 Message-ID: Update of /cvsroot/python/python/dist/src/Lib/distutils In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21005/Lib/distutils Modified Files: msvccompiler.py Log Message: Patch #827386: Support absolute source paths in msvccompiler.py. Backported to 2.4. Index: msvccompiler.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/msvccompiler.py,v retrieving revision 1.68 retrieving revision 1.69 diff -u -d -r1.68 -r1.69 --- msvccompiler.py 12 Mar 2005 19:05:58 -0000 1.68 +++ msvccompiler.py 7 Aug 2005 20:51:04 -0000 1.69 @@ -269,6 +269,8 @@ obj_names = [] for src_name in source_filenames: (base, ext) = os.path.splitext (src_name) + base = os.path.splitdrive(base)[1] # Chop off the drive + base = base[os.path.isabs(base):] # If abs, chop off leading / if ext not in self.src_extensions: # Better to raise an exception instead of silently continuing # and later complain about sources and targets having From pje at users.sourceforge.net Sun Aug 7 22:54:13 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 07 Aug 2005 13:54:13 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.txt, 1.3, 1.4 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21568 Modified Files: pkg_resources.txt Log Message: Document resource and metadata access APIs. Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- pkg_resources.txt 7 Aug 2005 05:52:37 -0000 1.3 +++ pkg_resources.txt 7 Aug 2005 20:54:10 -0000 1.4 @@ -46,7 +46,11 @@ API Reference ------------- -XXX Namespace stuff, + +Namespace Package Support +========================= + +XXX ``WorkingSet`` Objects @@ -96,30 +100,64 @@ import pkg_resources my_data = pkg_resources.resource_string(__name__, "foo.dat") -Thus, you can use the APIs below without needing a ``ResourceManager`` -instance; just import and use them. +Thus, you can use the APIs below without needing an explicit +``ResourceManager`` instance; just import and use them as needed. Basic Resource Access --------------------- -XXX explain resource paths, layout, etc. here +In the following methods, the `package_or_requirement` argument may be either +a Python package/module name (e.g. ``foo.bar``) or a ``Requirement`` instance. +If it is a package or module name, the named module or package must be +importable (i.e., be in a distribution or directory on ``sys.path``), and the +`resource_name` argument is interpreted relative to the named package. (Note +that if a module name is used, then the resource name is relative to the +package immediately containing the named module.) + +If it is a ``Requirement``, then the requirement is automatically resolved +(searching the current ``Environment`` if necessary) and a matching +distribution is added to the ``WorkingSet`` and ``sys.path`` if one was not +already present. (Unless the ``Requirement`` can't be satisfied, in which +case an exception is raised.) The `resource_name` argument is then interpreted +relative to the root of the identified distribution; i.e. its first path +segment will be treated as a peer of the top-level modules or packages in the +distribution. + +Note that resource names must be ``/``-separated paths and cannot be absolute +(i.e. no leading ``/``) or contain relative names like ``..``. Do *not* use +``os.path`` routines to manipulate resource paths, as they are *not* filesystem +paths. ``resource_exists(package_or_requirement, resource_name)`` - Does the named resource exist? + Does the named resource exist? Return ``True`` or ``False`` accordingly. ``resource_stream(package_or_requirement, resource_name)`` - Return a readable file-like object for specified resource + Return a readable file-like object for the specified resource; it may be + an actual file, a ``StringIO``, or some similar object. The stream is + in "binary mode", in the sense that whatever bytes are in the resource + will be read as-is. ``resource_string(package_or_requirement, resource_name)`` - Return specified resource as a string + Return the specified resource as a string. The resource is read in + binary fashion, such that the returned string contains exactly the bytes + that are stored in the resource. ``resource_isdir(package_or_requirement, resource_name)`` - Is the named resource an existing directory? + Is the named resource a directory? Return ``True`` or ``False`` + accordingly. ``resource_listdir(package_or_requirement, resource_name)`` - List the contents of the named resource directory - + List the contents of the named resource directory, just like ``os.listdir`` + except that it works even if the resource is in a zipfile. + +Note that only ``resource_exists()`` and ``resource_isdir()`` are insensitive +as to the resource type. You cannot use ``resource_listdir()`` on a file +resource, and you can't use ``resource_string()`` or ``resource_stream()`` on +directory resources. Using an inappropriate method for the resource type may +result in an exception or undefined behavior, depending on the platform and +distribution format involved. + Resource Extraction ------------------- @@ -141,19 +179,19 @@ ``set_extraction_path(path)`` Set the base path where resources will be extracted to, if needed. - + If you do not call this routine before any extractions take place, the path defaults to the return value of ``get_default_cache()``. (Which is based on the ``PYTHON_EGG_CACHE`` environment variable, with various platform-specific fallbacks. See that routine's documentation for more details.) - + Resources are extracted to subdirectories of this path based upon information given by the ``IResourceProvider``. You may set this to a temporary directory, but then you must call ``cleanup_resources()`` to delete the extracted files when done. There is no guarantee that ``cleanup_resources()`` will be able to remove all extracted files. - + (Note: you may not change the extraction path for a given resource manager once resources have been extracted, unless you first call ``cleanup_resources()``.) @@ -182,13 +220,13 @@ ``get_cache_path(archive_name, names=())`` Return absolute location in cache for `archive_name` and `names` - + The parent directory of the resulting path will be created if it does not already exist. `archive_name` should be the base filename of the enclosing egg (which may not be the name of the enclosing zipfile!), including its ".egg" extension. `names`, if provided, should be a sequence of path name parts "under" the egg's extraction location. - + This method should only be called by resource providers that need to obtain an extraction location, and only for names they intend to extract, as it tracks the generated names for possible cleanup later. @@ -198,12 +236,71 @@ Resource providers should call this method ONLY after successfully extracting a compressed resource. They must NOT call it on resources that are already in the filesystem. - + `tempname` is the current (temporary) name of the file, and `filename` is the name it will be renamed to by the caller after this routine returns. +Metadata API +============ + +The metadata API is used to access metadata resources bundled in a pluggable +distribution. Metadata resources are virtual files or directories containing +information about the distribution, such as might be used by an extensible +application or framework to connect "plugins". Like other kinds of resources, +metadata resource names are ``/``-separated and should not contain ``..`` or +begin with a ``/``. You should not use ``os.path`` routines to manipulate +resource paths. + +The metadata API is provided by objects implementing the ``IMetadataProvider`` +interface. ``Distribution`` objects created with a ``metadata`` setting +implement this interface, as do objects returned by the ``get_provider()`` +function: + +``get_provider(package_or_requirement)`` + If a package name is supplied, return an ``IMetadataProvider`` for the + package. If a ``Requirement`` is supplied, resolve it by returning a + ``Distribution`` from the current working set (searching the current + ``Environment`` if necessary and adding the newly found ``Distribution`` + to the working set). If the named package can't be imported, or the + ``Requirement`` can't be satisfied, an exception is raised. + + Note also that if you supply a package name, and the package is not part + of a pluggable distribution (i.e., it has no metadata), then you will still + get an ``IMetadataProvider`` object, but it will just be an empty one that + answers ``False`` when asked if any given metadata resource file or + directory exists. + +The methods provided by ``IMetadataProvider`` (and ``Distribution`` objects +with a ``metadata`` attribute set) are: + +``has_metadata(name)`` + Does the named metadata resource exist? + +``metadata_isdir(name)`` + Is the named metadata resource a directory? + +``metadata_listdir(name)`` + List of metadata names in the directory (like ``os.listdir()``) + +``get_metadata(name)`` + Return the named metadata resource as a string. The data is read in binary + mode; i.e., the exact bytes of the resource file are returned. + +``get_metadata_lines(name)`` + Yield named metadata resource as list of non-blank non-comment lines. This + is short for calling ``yield_lines(provider.get_metadata(name))``. See the + section on `yield_lines()`_ below for more information on the syntax it + recognizes. + +``run_script(script_name, namespace)`` + Execute the named script in the supplied namespace dictionary. Raises + ``ResolutionError`` if there is no script by that name in the ``scripts`` + metadata directory. `namespace` should be a Python dictionary, usually + a module dictionary if the script is being run as a module. + + Exceptions ========== @@ -275,6 +372,8 @@ candidates, and therefore are not as new as a version string that does not contain them. +.. _yield_lines(): + ``yield_lines(strs)`` Yield non-empty/non-comment lines from a string/unicode or a possibly- nested sequence thereof. If `strs` is an instance of ``basestring``, it @@ -336,7 +435,7 @@ ``get_platform()`` Return this platform's identifier string. For Windows, the return value - is ``"win32"``, and for Mac OS X it is a string of the form + is ``"win32"``, and for Mac OS X it is a string of the form ``"macosx-10.4-ppc"``. All other platforms return the same uname-based string that the ``distutils.util.get_platform()`` function returns. @@ -375,5 +474,5 @@ (notably Cygwin and Mac OS X) the ``normcase`` function does not accurately reflect the platform's case-sensitivity, so there is always the possibility of two apparently-different paths being equal on such platforms. - + From loewis at users.sourceforge.net Sun Aug 7 23:09:01 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 14:09:01 -0700 Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.69, 1.1193.2.70 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24031/Misc Modified Files: Tag: release24-maint NEWS Log Message: Patch #1239112: Correct LINKCC C++ test. Fixes #1189330. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.69 retrieving revision 1.1193.2.70 diff -u -d -r1.1193.2.69 -r1.1193.2.70 --- NEWS 7 Aug 2005 20:50:37 -0000 1.1193.2.69 +++ NEWS 7 Aug 2005 21:08:54 -0000 1.1193.2.70 @@ -93,6 +93,9 @@ Build ----- +- Bug #1189330: configure did not correctly determine the necessary + value of LINKCC if python was built with GCC 4.0. + - Upgrade Windows build to zlib 1.2.3 which eliminates a potential security vulnerability in zlib 1.2.1 and 1.2.2. From loewis at users.sourceforge.net Sun Aug 7 23:09:27 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 14:09:27 -0700 Subject: [Python-checkins] python/dist/src configure, 1.462.2.8, 1.462.2.9 configure.in, 1.475.2.8, 1.475.2.9 Message-ID: Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24031 Modified Files: Tag: release24-maint configure configure.in Log Message: Patch #1239112: Correct LINKCC C++ test. Fixes #1189330. Index: configure =================================================================== RCS file: /cvsroot/python/python/dist/src/configure,v retrieving revision 1.462.2.8 retrieving revision 1.462.2.9 diff -u -d -r1.462.2.8 -r1.462.2.9 --- configure 28 Mar 2005 23:23:02 -0000 1.462.2.8 +++ configure 7 Aug 2005 21:08:42 -0000 1.462.2.9 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 1.475.2.7 . +# From configure.in Revision: 1.475.2.8 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for python 2.4. # @@ -3265,9 +3265,11 @@ if test -z "$CXX"; then LINKCC="\$(PURIFY) \$(CC)" else - echo 'void foo();int main(){foo();}void foo(){}' > conftest.$ac_ext - $CXX -c conftest.$ac_ext 2>&5 - if $CC -o conftest$ac_exeext conftest.$ac_objext 2>&5 \ + echo 'extern "C" void foo();int main(){foo();}' > conftest_a.cc + $CXX -c conftest_a.cc # 2>&5 + echo 'void foo(){}' > conftest_b.$ac_ext + $CC -c conftest_b.$ac_ext # 2>&5 + if $CC -o conftest$ac_exeext conftest_a.$ac_objext conftest_b.$ac_objext 2>&5 \ && test -s conftest$ac_exeext && ./conftest$ac_exeext then LINKCC="\$(PURIFY) \$(CC)" Index: configure.in =================================================================== RCS file: /cvsroot/python/python/dist/src/configure.in,v retrieving revision 1.475.2.8 retrieving revision 1.475.2.9 diff -u -d -r1.475.2.8 -r1.475.2.9 --- configure.in 28 Mar 2005 23:23:34 -0000 1.475.2.8 +++ configure.in 7 Aug 2005 21:08:53 -0000 1.475.2.9 @@ -471,9 +471,11 @@ if test -z "$CXX"; then LINKCC="\$(PURIFY) \$(CC)" else - echo 'void foo();int main(){foo();}void foo(){}' > conftest.$ac_ext - $CXX -c conftest.$ac_ext 2>&5 - if $CC -o conftest$ac_exeext conftest.$ac_objext 2>&5 \ + echo 'extern "C" void foo();int main(){foo();}' > conftest_a.cc + $CXX -c conftest_a.cc # 2>&5 + echo 'void foo(){}' > conftest_b.$ac_ext + $CC -c conftest_b.$ac_ext # 2>&5 + if $CC -o conftest$ac_exeext conftest_a.$ac_objext conftest_b.$ac_objext 2>&5 \ && test -s conftest$ac_exeext && ./conftest$ac_exeext then LINKCC="\$(PURIFY) \$(CC)" From loewis at users.sourceforge.net Sun Aug 7 23:09:33 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 14:09:33 -0700 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1330,1.1331 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24327/Misc Modified Files: NEWS Log Message: Patch #1239112: Correct LINKCC C++ test. Fixes #1189330. Backported to 2.4. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1330 retrieving revision 1.1331 diff -u -d -r1.1330 -r1.1331 --- NEWS 7 Aug 2005 20:51:04 -0000 1.1330 +++ NEWS 7 Aug 2005 21:09:30 -0000 1.1331 @@ -391,6 +391,9 @@ Build ----- +- Bug #1189330: configure did not correctly determine the necessary + value of LINKCC if python was built with GCC 4.0. + - Upgrade Windows build to zlib 1.2.3 which eliminates a potential security vulnerability in zlib 1.2.1 and 1.2.2. From loewis at users.sourceforge.net Sun Aug 7 23:09:33 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 07 Aug 2005 14:09:33 -0700 Subject: [Python-checkins] python/dist/src configure, 1.472, 1.473 configure.in, 1.485, 1.486 Message-ID: Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24327 Modified Files: configure configure.in Log Message: Patch #1239112: Correct LINKCC C++ test. Fixes #1189330. Backported to 2.4. Index: configure =================================================================== RCS file: /cvsroot/python/python/dist/src/configure,v retrieving revision 1.472 retrieving revision 1.473 diff -u -d -r1.472 -r1.473 --- configure 2 Jun 2005 13:08:55 -0000 1.472 +++ configure 7 Aug 2005 21:09:30 -0000 1.473 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 1.484 . +# From configure.in Revision: 1.485 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for python 2.5. # @@ -3265,9 +3265,11 @@ if test -z "$CXX"; then LINKCC="\$(PURIFY) \$(CC)" else - echo 'void foo();int main(){foo();}void foo(){}' > conftest.$ac_ext - $CXX -c conftest.$ac_ext 2>&5 - if $CC -o conftest$ac_exeext conftest.$ac_objext 2>&5 \ + echo 'extern "C" void foo();int main(){foo();}' > conftest_a.cc + $CXX -c conftest_a.cc # 2>&5 + echo 'void foo(){}' > conftest_b.$ac_ext + $CC -c conftest_b.$ac_ext # 2>&5 + if $CC -o conftest$ac_exeext conftest_a.$ac_objext conftest_b.$ac_objext 2>&5 \ && test -s conftest$ac_exeext && ./conftest$ac_exeext then LINKCC="\$(PURIFY) \$(CC)" Index: configure.in =================================================================== RCS file: /cvsroot/python/python/dist/src/configure.in,v retrieving revision 1.485 retrieving revision 1.486 diff -u -d -r1.485 -r1.486 --- configure.in 2 Jun 2005 13:09:24 -0000 1.485 +++ configure.in 7 Aug 2005 21:09:30 -0000 1.486 @@ -471,9 +471,11 @@ if test -z "$CXX"; then LINKCC="\$(PURIFY) \$(CC)" else - echo 'void foo();int main(){foo();}void foo(){}' > conftest.$ac_ext - $CXX -c conftest.$ac_ext 2>&5 - if $CC -o conftest$ac_exeext conftest.$ac_objext 2>&5 \ + echo 'extern "C" void foo();int main(){foo();}' > conftest_a.cc + $CXX -c conftest_a.cc # 2>&5 + echo 'void foo(){}' > conftest_b.$ac_ext + $CC -c conftest_b.$ac_ext # 2>&5 + if $CC -o conftest$ac_exeext conftest_a.$ac_objext conftest_b.$ac_objext 2>&5 \ && test -s conftest$ac_exeext && ./conftest$ac_exeext then LINKCC="\$(PURIFY) \$(CC)" From bwarsaw at users.sourceforge.net Mon Aug 8 06:03:43 2005 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Sun, 07 Aug 2005 21:03:43 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.7,1.8 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21787 Modified Files: pep-0347.txt Log Message: Fixed some minor typos. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- pep-0347.txt 7 Aug 2005 16:11:59 -0000 1.7 +++ pep-0347.txt 8 Aug 2005 04:03:40 -0000 1.8 @@ -15,21 +15,21 @@ ======== The Python source code is currently managed in a CVS repository on -sourceforge.net. This PEP proposes to move it to a subversion +sourceforge.net. This PEP proposes to move it to a Subversion repository on svn.python.org. Rationale ========= -This change has two aspects: moving from CVS to subversion, and moving +This change has two aspects: moving from CVS to Subversion, and moving from SourceForge to python.org. For each, a rationale will be given. Moving to Subversion -------------------- -CVS has a number of limitations that have been elimintation by +CVS has a number of limitations that have been eliminated by Subversion. For the development of Python, the most notable improvements are: @@ -41,7 +41,7 @@ transactional. - atomic, fast tagging: a cvs tag might take many minutes; a - subversion tag (svn cp) will complete quickly, and atomically. + Subversion tag (svn cp) will complete quickly, and atomically. Likewise, branches are very efficient. - support for offline diffs, which is useful when creating patches. @@ -128,10 +128,10 @@ plus for src (called python), plus distutils. Reorganizing the repository is best done in the CVS tree, as shown below. -Fsfs should be used as the repository format (requires Subversion -1.1). Fsfs has the advantage of being more backup-friendly, as it -allows incremental repository backups, without requiring any dump -commands to be run. +The fsfs backend should be used as the repository format (which +requires Subversion 1.1). The fsfs has the advantage of being more +backup-friendly, as it allows incremental repository backups, without +requiring any dump commands to be run. The conversion should be done using the cvs2svn utility, available e.g. in the cvs2svn Debian package. As cvs2svn does not currently @@ -205,7 +205,7 @@ across projects. - Nick Bastin has offered to host a Perforce repository, instead - of using subversion. Details of that offer are not clear yet. + of using Subversion. Details of that offer are not clear yet. - Several people suggested to create the project/trunk structure through standard cvs2svn, followed by renames. This would have @@ -230,8 +230,7 @@ decided. * Subversion over WebDAV, using SSL client certificates. This would - work, but would require us to administrate a certificate - authority. + work, but would require us to administer a certificate authority. Copyright From loewis at users.sourceforge.net Mon Aug 8 09:18:20 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Mon, 08 Aug 2005 00:18:20 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.8,1.9 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14385 Modified Files: pep-0347.txt Log Message: Change authentication method to svn+ssh. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- pep-0347.txt 8 Aug 2005 04:03:40 -0000 1.8 +++ pep-0347.txt 8 Aug 2005 07:18:17 -0000 1.9 @@ -71,9 +71,8 @@ To move the Python CVS repository, the following steps need to be executed. The steps are elaborated upon in the following sections. -1. Assign passwords for all current committers for use on - svn.python.org. User names on SF and svn.python.org should be - identical, unless some committer requests a different user name. +1. Collect SSH keys for all current committers, along with usernames + to appear in commit messages. 2. At the beginning of the migration, announce that the repository on SourceForge closed. @@ -88,14 +87,28 @@ 6. Disable CVS access on SF. -Assign Passwords +Collect SSH keys ---------------- -Currently, access to Subversion on svn.python.org uses WebDAV over -https, using basic authentication. For this to work, authorized users -need to provide a password. This mechanism should be used, at least -initially, for the Python CVS as well, since various committers also -have a username/password pair for the www SVN repository already. +After some discussion, svn+ssh was selected as the best method +for write access to the repository. Developers can continue to +use their SSH keys, but they must be installed on python.org. + +In order to avoid having to create a new Unix user for each +developer, a single account should be used, with command= +attributes in the authorized_keys files. + +The lines in the authorized_keys file should read like this +(wrapped for better readability):: + + command="/usr/bin/svnserve --root=/svnroot -t + --tunnel-user=''",no-port-forwarding, + no-X11-forwarding,no-agent-forwarding,no-pty + ssh-dss + +As the usernames, the real names should be used instead of +the SF account names, so that people can be better identified +in log messages. Downloading the CVS Repository @@ -174,7 +187,8 @@ The repository should be published at https://svn.python.org/projects. Read-write access should be granted through basic authentication to all current SF committers; read-only anonymous access should also be -granted. +granted. Read-write access will go through +svn+ssh://pythondev at svn.python.org/projects. As an option, websvn (available e.g. from the Debian websvn package) could be provided. Unfortunately, in the test installation, websvn @@ -220,21 +234,21 @@ to the additional workload; migrating the repository again if they get overworked is an option. -- People have expressed dislike of the basic auth (username/password) - authentication. Two alternatives have been suggested: +- Different authentication strategies were discussed. As + alternatives to svn+ssh were suggested - * Subversion over SSH, using SSH key pairs for a single Unix - account, restricted to the execution of svnserve. The pydotorg - admins have ruled out creation of one account per committer; - whether a single account would be acceptable is not yet - decided. + * Subversion over WebDAV, using SSL and basic authentication, + with pydotorg-generated passwords mailed to the user. People + did not like that approach, since they would need to store + the password on disk (because they can't remember it); this + is a security risk. * Subversion over WebDAV, using SSL client certificates. This would work, but would require us to administer a certificate authority. Copyright ---------- +========= This document has been placed in the public domain. From goodger at users.sourceforge.net Tue Aug 9 03:17:08 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Mon, 08 Aug 2005 18:17:08 -0700 Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.9,1.10 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30980 Modified Files: pep-0347.txt Log Message: addition for readability Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- pep-0347.txt 8 Aug 2005 07:18:17 -0000 1.9 +++ pep-0347.txt 9 Aug 2005 01:17:05 -0000 1.10 @@ -142,9 +142,9 @@ repository is best done in the CVS tree, as shown below. The fsfs backend should be used as the repository format (which -requires Subversion 1.1). The fsfs has the advantage of being more -backup-friendly, as it allows incremental repository backups, without -requiring any dump commands to be run. +requires Subversion 1.1). The fsfs backend has the advantage of being +more backup-friendly, as it allows incremental repository backups, +without requiring any dump commands to be run. The conversion should be done using the cvs2svn utility, available e.g. in the cvs2svn Debian package. As cvs2svn does not currently From gvanrossum at users.sourceforge.net Tue Aug 9 04:46:15 2005 From: gvanrossum at users.sourceforge.net (gvanrossum@users.sourceforge.net) Date: Mon, 08 Aug 2005 19:46:15 -0700 Subject: [Python-checkins] python/nondist/peps pep-0348.txt,1.5,1.6 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13066 Modified Files: pep-0348.txt Log Message: Fix docutils warning/2. Index: pep-0348.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0348.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- pep-0348.txt 7 Aug 2005 04:14:04 -0000 1.5 +++ pep-0348.txt 9 Aug 2005 02:46:12 -0000 1.6 @@ -494,7 +494,7 @@ http://mail.python.org/pipermail/python-dev/2005-July/055019.html .. [#python-dev5] python-dev email (PEP, take 2: Exception Reorganization for -Python 3.0) + Python 3.0) http://mail.python.org/pipermail/python-dev/2005-August/055159.html .. [#python-dev6] python-dev email (Exception Reorg PEP checked in) From bcannon at users.sourceforge.net Tue Aug 9 06:26:30 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon, 08 Aug 2005 21:26:30 -0700 Subject: [Python-checkins] python/nondist/peps pep-0348.txt,1.6,1.7 Message-ID: Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27247 Modified Files: pep-0348.txt Log Message: Scale back proposal even more: VMError and AnyDeprecationWarning have been removed along with EOFError no longer inheriting from IOError. TerminalException was renamed TerminatingException. At this point the only changes to the exception hierarchy are the addition of BaseException and TerminatingException, and the change of inheritance for KeyboardInterrupt, SystemExit, and NotImplementedError. Index: pep-0348.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0348.txt,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- pep-0348.txt 9 Aug 2005 02:46:12 -0000 1.6 +++ pep-0348.txt 9 Aug 2005 04:26:28 -0000 1.7 @@ -7,7 +7,7 @@ Type: Standards Track Content-Type: text/x-rst Created: 28-Jul-2005 -Post-History: 03-Aug-2005 +Post-History: Abstract @@ -104,7 +104,7 @@ .. parsed-literal:: +-- BaseException (new; broader inheritance for subclasses) - +-- TerminalException (new; stricter inheritance for subclasses) + +-- TerminatingException (new; stricter inheritance for subclasses) +-- KeyboardInterrupt +-- SystemExit +-- Exception @@ -118,12 +118,13 @@ +-- AttributeError +-- EnvironmentError +-- IOError - +-- EOFError (broader inheritance) + +-- EOFError +-- OSError +-- ImportError +-- LookupError +-- IndexError +-- KeyError + +-- MemoryError +-- NameError +-- UnboundLocalError +-- NotImplementedError (stricter inheritance) @@ -137,15 +138,12 @@ +-- UnicodeEncodeError +-- UnicodeTranslateError +-- ValueError - +-- VMError (new; broader inheritance for subclasses) - +-- MemoryError - +-- SystemError +-- ReferenceError +-- StopIteration + +-- SystemError +-- Warning - +-- AnyDeprecationWarning (new; broader inheritance for subclasses) - +-- PendingDeprecationWarning - +-- DeprecationWarning + +-- PendingDeprecationWarning + +-- DeprecationWarning +-- FutureWarning +-- SyntaxWarning +-- RuntimeWarning @@ -171,30 +169,17 @@ The superclass that all exceptions must inherit from. -TerminalException -''''''''''''''''' +TerminatingException +'''''''''''''''''''' Superclass for exceptions that are meant to the termination of the interpreter. It does not inherit from Exception so that subclasses are not caught by bare ``except`` clauses. - -VMError -''''''' - -Superclass for exceptions that deal directly with the virtual -machine. - - -AnyDeprecationWarning -''''''''''''''''''''' - -A common superclass for all deprecation-related exceptions. While -having DeprecationWarning inherit from PendingDeprecationWarning was -suggested (a DeprecationWarning can be viewed as a -PendingDeprecationWarning that is happening now), the logic was not -agreed upon by a majority. But since the exceptions are related, -creating a common superclass is warranted. +Naming based on the idea that the interpreter is trying to terminate when these +exceptions are raised. An earlier proposal suggested "TerminalException" but +avoidance of any confusion with an actual terminal along with "terminal" being +more fatalistic than "terminating" led to the current name choice. Removed Exceptions @@ -221,15 +206,6 @@ Exception. -EOFError -'''''''' - -Subclasses IOError. - -Since an EOF comes from I/O it only makes sense that it be considered -an I/O error. - - Required Superclass for ``raise`` ================================= @@ -446,6 +422,30 @@ causing existing Python programmers extra pain, the renamings were removed. +Have EOFError Subclass IOError +------------------------------ + +The original thought was that sine EOFError deals directly with I/O, it should +subclass IOError. But since EOFError is used more as a signal that an event +has occurred (the exhaustion of an I/O port), it should not subclass such a +specific error exception. + + +Have MemoryError and SystemError Have a Common Superclass +--------------------------------------------------------- + +Both classes deal with the interpreter, so why not have them have a common +superclass? Because one of them means that the interpreter is in a state that +it should not recover from while the other does not. + + +Common Superclass for PendingDeprecationWarning and DeprecationWarning +---------------------------------------------------------------------- + +Grouping the deprecation warning exceptions together makes intuitive sense. +But this sensical idea does not extend well when one considers how rarely +either warning is used, let along at the same time. + Acknowledgements ================ From loewis at users.sourceforge.net Tue Aug 9 17:01:04 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Tue, 09 Aug 2005 08:01:04 -0700 Subject: [Python-checkins] python/dist/src/Modules posixmodule.c, 2.337, 2.338 Message-ID: Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2103/Modules Modified Files: posixmodule.c Log Message: Patch #1180695: Implement nanosecond stat resolution on FreeBSD, add st_gen, st_birthtime. Index: posixmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/posixmodule.c,v retrieving revision 2.337 retrieving revision 2.338 diff -u -d -r2.337 -r2.338 --- posixmodule.c 5 Jul 2005 15:21:58 -0000 2.337 +++ posixmodule.c 9 Aug 2005 15:00:59 -0000 2.338 @@ -706,6 +706,12 @@ #ifdef HAVE_STRUCT_STAT_ST_FLAGS {"st_flags", "user defined flags for file"}, #endif +#ifdef HAVE_STRUCT_STAT_ST_GEN + {"st_gen", "generation number"}, +#endif +#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME + {"st_birthtime", "time of creation"}, +#endif {0} }; @@ -733,6 +739,18 @@ #define ST_FLAGS_IDX ST_RDEV_IDX #endif +#ifdef HAVE_STRUCT_STAT_ST_GEN +#define ST_GEN_IDX (ST_RDEV_IDX+1) +#else +#define ST_GEN_IDX ST_RDEV_IDX +#endif + +#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME +#define ST_BIRTHTIME_IDX (ST_GEN_IDX+1) +#else +#define ST_BIRTHTIME_IDX ST_GEN_IDX +#endif + static PyStructSequence_Desc stat_result_desc = { "stat_result", /* name */ stat_result__doc__, /* doc */ @@ -878,8 +896,14 @@ mnsec = st.st_mtim.tv_nsec; cnsec = st.st_ctim.tv_nsec; #else +#ifdef HAVE_STAT_TV_NSEC2 + ansec = st.st_atimespec.tv_nsec; + mnsec = st.st_mtimespec.tv_nsec; + cnsec = st.st_ctimespec.tv_nsec; +#else ansec = mnsec = cnsec = 0; #endif +#endif fill_time(v, 7, st.st_atime, ansec); fill_time(v, 8, st.st_mtime, mnsec); fill_time(v, 9, st.st_ctime, cnsec); @@ -896,6 +920,29 @@ PyStructSequence_SET_ITEM(v, ST_RDEV_IDX, PyInt_FromLong((long)st.st_rdev)); #endif +#ifdef HAVE_STRUCT_STAT_ST_GEN + PyStructSequence_SET_ITEM(v, ST_GEN_IDX, + PyInt_FromLong((long)st.st_gen)); +#endif +#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME + { + PyObject *val; + unsigned long bsec,bnsec; + bsec = (long)st.st_birthtime; +#ifdef HAVE_STAT_TV_NSEC2 + bnsec = st.st_birthtimespec.tv_nsec; +#else + bnsec = 0; +#endif + if (_stat_float_times) { + val = PyFloat_FromDouble(bsec + 1e-9*bnsec); + } else { + val = PyInt_FromLong((long)bsec); + } + PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX, + val); + } +#endif #ifdef HAVE_STRUCT_STAT_ST_FLAGS PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, PyInt_FromLong((long)st.st_flags)); From loewis at users.sourceforge.net Tue Aug 9 17:01:28 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Tue, 09 Aug 2005 08:01:28 -0700 Subject: [Python-checkins] python/dist/src/Doc/lib libos.tex,1.164,1.165 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2103/Doc/lib Modified Files: libos.tex Log Message: Patch #1180695: Implement nanosecond stat resolution on FreeBSD, add st_gen, st_birthtime. Index: libos.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libos.tex,v retrieving revision 1.164 retrieving revision 1.165 diff -u -d -r1.164 -r1.165 --- libos.tex 18 Jul 2005 08:16:33 -0000 1.164 +++ libos.tex 9 Aug 2005 15:00:50 -0000 1.165 @@ -996,6 +996,12 @@ \member{st_rdev} (type of device if an inode device). \member{st_flags} (user defined flags for file). +On other Unix systems (such as FreeBSD), the following attributes +may be available (but may be only filled out of root tries to +use them: +\member{st_gen} (file generation number), +\member{st_birthtime} (time of file creation). + On Mac OS systems, the following attributes may also be available: \member{st_rsize}, \member{st_creator}, @@ -1037,6 +1043,7 @@ \versionchanged [Added access to values as attributes of the returned object]{2.2} +\versionchanged[Added st_gen, st_birthtime]{2.5} \end{funcdesc} \begin{funcdesc}{stat_float_times}{\optional{newvalue}} From loewis at users.sourceforge.net Tue Aug 9 17:01:29 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Tue, 09 Aug 2005 08:01:29 -0700 Subject: [Python-checkins] python/dist/src configure, 1.473, 1.474 configure.in, 1.486, 1.487 pyconfig.h.in, 1.107, 1.108 Message-ID: Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2103 Modified Files: configure configure.in pyconfig.h.in Log Message: Patch #1180695: Implement nanosecond stat resolution on FreeBSD, add st_gen, st_birthtime. Index: configure =================================================================== RCS file: /cvsroot/python/python/dist/src/configure,v retrieving revision 1.473 retrieving revision 1.474 diff -u -d -r1.473 -r1.474 --- configure 7 Aug 2005 21:09:30 -0000 1.473 +++ configure 9 Aug 2005 14:59:51 -0000 1.474 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 1.485 . +# From configure.in Revision: 1.486 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for python 2.5. # @@ -16526,6 +16526,226 @@ fi +echo "$as_me:$LINENO: checking for struct stat.st_gen" >&5 +echo $ECHO_N "checking for struct stat.st_gen... $ECHO_C" >&6 +if test "${ac_cv_member_struct_stat_st_gen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_gen) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_gen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_gen) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_gen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_member_struct_stat_st_gen=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_gen" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_gen" >&6 +if test $ac_cv_member_struct_stat_st_gen = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_GEN 1 +_ACEOF + + +fi + +echo "$as_me:$LINENO: checking for struct stat.st_birthtime" >&5 +echo $ECHO_N "checking for struct stat.st_birthtime... $ECHO_C" >&6 +if test "${ac_cv_member_struct_stat_st_birthtime+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_birthtime) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_birthtime=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_birthtime) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_member_struct_stat_st_birthtime=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_member_struct_stat_st_birthtime=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_birthtime" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_birthtime" >&6 +if test $ac_cv_member_struct_stat_st_birthtime = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1 +_ACEOF + + +fi + echo "$as_me:$LINENO: checking for struct stat.st_blocks" >&5 echo $ECHO_N "checking for struct stat.st_blocks... $ECHO_C" >&6 if test "${ac_cv_member_struct_stat_st_blocks+set}" = set; then @@ -20266,6 +20486,73 @@ fi +# Look for BSD style subsecond timestamps in struct stat +echo "$as_me:$LINENO: checking for tv_nsec2 in struct stat" >&5 +echo $ECHO_N "checking for tv_nsec2 in struct stat... $ECHO_C" >&6 +if test "${ac_cv_stat_tv_nsec2+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ + +struct stat st; +st.st_mtimespec.tv_nsec = 1; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_stat_tv_nsec2=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_stat_tv_nsec2=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +echo "$as_me:$LINENO: result: $ac_cv_stat_tv_nsec2" >&5 +echo "${ECHO_T}$ac_cv_stat_tv_nsec2" >&6 +if test "$ac_cv_stat_tv_nsec2" = yes +then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_STAT_TV_NSEC2 1 +_ACEOF + +fi + # On HP/UX 11.0, mvwdelch is a block with a return statement echo "$as_me:$LINENO: checking whether mvwdelch is an expression" >&5 echo $ECHO_N "checking whether mvwdelch is an expression... $ECHO_C" >&6 Index: configure.in =================================================================== RCS file: /cvsroot/python/python/dist/src/configure.in,v retrieving revision 1.486 retrieving revision 1.487 diff -u -d -r1.486 -r1.487 --- configure.in 7 Aug 2005 21:09:30 -0000 1.486 +++ configure.in 9 Aug 2005 15:00:36 -0000 1.487 @@ -2424,6 +2424,8 @@ AC_CHECK_MEMBERS([struct stat.st_rdev]) AC_CHECK_MEMBERS([struct stat.st_blksize]) AC_CHECK_MEMBERS([struct stat.st_flags]) +AC_CHECK_MEMBERS([struct stat.st_gen]) +AC_CHECK_MEMBERS([struct stat.st_birthtime]) AC_STRUCT_ST_BLOCKS AC_MSG_CHECKING(for time.h that defines altzone) @@ -3042,6 +3044,23 @@ [Define if you have struct stat.st_mtim.tv_nsec]) fi +# Look for BSD style subsecond timestamps in struct stat +AC_MSG_CHECKING(for tv_nsec2 in struct stat) +AC_CACHE_VAL(ac_cv_stat_tv_nsec2, +AC_TRY_COMPILE([#include ], [ +struct stat st; +st.st_mtimespec.tv_nsec = 1; +], +ac_cv_stat_tv_nsec2=yes, +ac_cv_stat_tv_nsec2=no, +ac_cv_stat_tv_nsec2=no)) +AC_MSG_RESULT($ac_cv_stat_tv_nsec2) +if test "$ac_cv_stat_tv_nsec2" = yes +then + AC_DEFINE(HAVE_STAT_TV_NSEC2, 1, + [Define if you have struct stat.st_mtimensec]) +fi + # On HP/UX 11.0, mvwdelch is a block with a return statement AC_MSG_CHECKING(whether mvwdelch is an expression) AC_CACHE_VAL(ac_cv_mvwdelch_is_expression, Index: pyconfig.h.in =================================================================== RCS file: /cvsroot/python/python/dist/src/pyconfig.h.in,v retrieving revision 1.107 retrieving revision 1.108 diff -u -d -r1.107 -r1.108 --- pyconfig.h.in 2 Jun 2005 13:09:25 -0000 1.107 +++ pyconfig.h.in 9 Aug 2005 15:00:38 -0000 1.108 @@ -455,6 +455,9 @@ /* Define if you have struct stat.st_mtim.tv_nsec */ #undef HAVE_STAT_TV_NSEC +/* Define if you have struct stat.st_mtimensec */ +#undef HAVE_STAT_TV_NSEC2 + /* Define if your compiler supports variable length function prototypes (e.g. void fprintf(FILE *, char *, ...);) *and* */ #undef HAVE_STDARG_PROTOTYPES @@ -483,6 +486,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STROPTS_H +/* Define to 1 if `st_birthtime' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_BIRTHTIME + /* Define to 1 if `st_blksize' is member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BLKSIZE @@ -492,6 +498,9 @@ /* Define to 1 if `st_flags' is member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_FLAGS +/* Define to 1 if `st_gen' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_GEN + /* Define to 1 if `st_rdev' is member of `struct stat'. */ #undef HAVE_STRUCT_STAT_ST_RDEV From loewis at users.sourceforge.net Tue Aug 9 17:01:31 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Tue, 09 Aug 2005 08:01:31 -0700 Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1331,1.1332 Message-ID: Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2103/Misc Modified Files: NEWS Log Message: Patch #1180695: Implement nanosecond stat resolution on FreeBSD, add st_gen, st_birthtime. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1331 retrieving revision 1.1332 diff -u -d -r1.1331 -r1.1332 --- NEWS 7 Aug 2005 21:09:30 -0000 1.1331 +++ NEWS 9 Aug 2005 15:00:51 -0000 1.1332 @@ -121,6 +121,9 @@ Extension Modules ----------------- +- Patch #1180695: Add nanosecond stat resolution, and st_gen, + st_birthtime for FreeBSD. + - Patch #1231069: The fcntl.ioctl function now uses the 'I' code for the request code argument, which results in more C-like behaviour for large or negative values. From fdrake at users.sourceforge.net Tue Aug 9 17:24:08 2005 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Tue, 09 Aug 2005 08:24:08 -0700 Subject: [Python-checkins] python/dist/src/Doc/lib libos.tex,1.165,1.166 Message-ID: Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8121/lib Modified Files: libos.tex Log Message: fix minor markup errors Index: libos.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libos.tex,v retrieving revision 1.165 retrieving revision 1.166 diff -u -d -r1.165 -r1.166 --- libos.tex 9 Aug 2005 15:00:50 -0000 1.165 +++ libos.tex 9 Aug 2005 15:24:05 -0000 1.166 @@ -796,7 +796,7 @@ directory. Availability: Macintosh, \UNIX, Windows. -\versionchanged[On Windows NT/2k/XP and Unix, if \var{path} is a Unicode +\versionchanged[On Windows NT/2k/XP and \UNIX, if \var{path} is a Unicode object, the result will be a list of Unicode objects.]{2.3} \end{funcdesc} @@ -989,14 +989,14 @@ reported if the system supports that. On Mac OS, the times are always floats. See \function{stat_float_times} for further discussion. ]{2.3} -On some Unix systems (such as Linux), the following attributes may +On some \UNIX{} systems (such as Linux), the following attributes may also be available: \member{st_blocks} (number of blocks allocated for file), \member{st_blksize} (filesystem blocksize), \member{st_rdev} (type of device if an inode device). \member{st_flags} (user defined flags for file). -On other Unix systems (such as FreeBSD), the following attributes +On other \UNIX{} systems (such as FreeBSD), the following attributes may be available (but may be only filled out of root tries to use them: \member{st_gen} (file generation number), From pje at users.sourceforge.net Tue Aug 9 17:50:41 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Tue, 09 Aug 2005 08:50:41 -0700 Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.62, 1.63 Message-ID: Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13834 Modified Files: pkg_resources.py Log Message: Fix a bug introduced by making split_sections() not lowercase section headings. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.62 retrieving revision 1.63 diff -u -d -r1.62 -r1.63 --- pkg_resources.py 7 Aug 2005 05:52:36 -0000 1.62 +++ pkg_resources.py 9 Aug 2005 15:50:39 -0000 1.63 @@ -1597,8 +1597,6 @@ - - class EntryPoint(object): """Object representing an importable location""" @@ -1812,9 +1810,9 @@ dm = self.__dep_map = {None: []} for name in 'requires.txt', 'depends.txt': for extra,reqs in split_sections(self._get_metadata(name)): - dm.setdefault(extra.lower(),[]).extend(parse_requirements(reqs)) + if extra: extra = extra.lower() + dm.setdefault(extra,[]).extend(parse_requirements(reqs)) return dm - _dep_map = property(_dep_map) def requires(self,extras=()): From pje at users.sourceforge.net Thu Aug 11 02:37:46 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Thu, 11 Aug 2005 02:37:46 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools package_index.py, 1.16, 1.17 Message-ID: <20050811003746.BE48C1E400A@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32307/setuptools Modified Files: package_index.py Log Message: Fix bugs reported by Ian Bicking, Walter Doerwald, and Vincenzo Di Massa. Index: package_index.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/package_index.py,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- package_index.py 7 Aug 2005 01:03:35 -0000 1.16 +++ package_index.py 11 Aug 2005 00:37:37 -0000 1.17 @@ -7,6 +7,8 @@ EGG_FRAGMENT = re.compile('^egg=(\\w+(-\\w+)?)$') HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I) +# this is here to fix emacs' cruddy broken syntax highlighting: ' + URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):',re.I).match EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split() @@ -37,8 +39,6 @@ - - def distros_for_url(url, metadata=None): """Yield egg or source distribution objects that might be found at a URL""" @@ -371,10 +371,10 @@ def _download_to(self, url, filename): self.info("Downloading %s", url) - # Download the file fp, tfp = None, None try: + url = url.split('#', 1)[0] fp = self.open_url(url) if isinstance(fp, urllib2.HTTPError): raise DistutilsError( From pje at users.sourceforge.net Thu Aug 11 02:37:46 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Thu, 11 Aug 2005 02:37:46 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.63, 1.64 Message-ID: <20050811003746.C4ED61E400C@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32307 Modified Files: pkg_resources.py Log Message: Fix bugs reported by Ian Bicking, Walter Doerwald, and Vincenzo Di Massa. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.63 retrieving revision 1.64 diff -u -d -r1.63 -r1.64 --- pkg_resources.py 9 Aug 2005 15:50:39 -0000 1.63 +++ pkg_resources.py 11 Aug 2005 00:37:37 -0000 1.64 @@ -1794,8 +1794,8 @@ self._version = safe_version(line.split(':',1)[1].strip()) return self._version else: - raise AttributeError( - "Missing 'Version:' header in PKG-INFO", self + raise ValueError( + "Missing 'Version:' header and/or PKG-INFO file", self ) version = property(version) From pje at users.sourceforge.net Thu Aug 11 02:37:47 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Thu, 11 Aug 2005 02:37:47 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command build_py.py, 1.2, 1.3 easy_install.py, 1.20, 1.21 Message-ID: <20050811003747.07D801E400A@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32307/setuptools/command Modified Files: build_py.py easy_install.py Log Message: Fix bugs reported by Ian Bicking, Walter Doerwald, and Vincenzo Di Massa. Index: build_py.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/build_py.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- build_py.py 5 Apr 2004 20:21:53 -0000 1.2 +++ build_py.py 11 Aug 2005 00:37:37 -0000 1.3 @@ -39,7 +39,7 @@ def get_data_files(self): """Generate list of '(package,src_dir,build_dir,filenames)' tuples""" data = [] - for package in self.packages: + for package in self.packages or (): # Locate package source directory src_dir = self.get_package_dir(package) Index: easy_install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/easy_install.py,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- easy_install.py 7 Aug 2005 01:03:36 -0000 1.20 +++ easy_install.py 11 Aug 2005 00:37:37 -0000 1.21 @@ -269,7 +269,6 @@ "%r already exists in %s; can't do a checkout there" % (spec.key, self.build_directory) ) - @@ -281,7 +280,8 @@ - + + @@ -381,7 +381,7 @@ if dist not in requirement: return - if deps or self.always_copy: + if deps or self.always_copy: log.info("Processing dependencies for %s", requirement) else: return @@ -448,7 +448,7 @@ setup_base = dist_filename ensure_directory(dst); shutil.move(setup_base, dst) return dst - + def install_script(self, dist, script_name, script_text, dev_path=None): log.info("Installing %s script to %s", script_name,self.script_dir) target = os.path.join(self.script_dir, script_name) @@ -502,10 +502,11 @@ if os.path.isfile(dist_filename): unpack_archive(dist_filename, tmpdir, self.unpack_progress) elif os.path.isdir(dist_filename): - # note that setup_base==tmpdir here if this is a svn checkout setup_base = os.path.abspath(dist_filename) - if setup_base==tmpdir and self.build_directory and spec is not None: + if (setup_base.startswith(tmpdir) # something we downloaded + and self.build_directory and spec is not None + ): setup_base = self.maybe_move(spec, dist_filename, setup_base) # Find the setup.py file @@ -530,7 +531,6 @@ else: return self.build_and_install(setup_script, setup_base) - def egg_distribution(self, egg_path): if os.path.isdir(egg_path): metadata = PathMetadata(egg_path,os.path.join(egg_path,'EGG-INFO')) @@ -1091,7 +1091,7 @@ self.paths.pop() # skip it self.dirty = True # we cleaned up, so we're dirty now :) continue - seen[path] = 1 + seen[path] = 1 while self.paths and not self.paths[-1].strip(): self.paths.pop() From rhettinger at users.sourceforge.net Thu Aug 11 09:58:55 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu, 11 Aug 2005 09:58:55 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_set.py,1.19,1.20 Message-ID: <20050811075855.F0ED91E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26888/Lib/test Modified Files: test_set.py Log Message: * Add short-circuit code for in-place operations with self (such as s|=s, s&=s, s-=s, or s^=s). Add related tests. * Improve names for several variables and functions. * Provide alternate table access functions (next, contains, add, and discard) that work with an entry argument instead of just a key. This improves set-vs-set operations because we already have a hash value for each key and can avoid unnecessary calls to PyObject_Hash(). Provides a 5% to 20% speed-up for quick hashing elements like strings and integers. Provides much more substantial improvements for slow hashing elements like tuples or objects defining a custom __hash__() function. * Have difference operations resize() when 1/5 of the elements are dummies. Formerly, it was 1/6. The new ratio triggers less frequently and only in cases that it can resize quicker and with greater benefit. The right answer is probably either 1/4, 1/5, or 1/6. Picked the middle value for an even trade-off between resize time and the space/time costs of dummy entries. Index: test_set.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_set.py,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- test_set.py 1 Aug 2005 21:39:28 -0000 1.19 +++ test_set.py 11 Aug 2005 07:58:45 -0000 1.20 @@ -370,6 +370,18 @@ else: self.assert_(c not in self.s) + def test_inplace_on_self(self): + t = self.s.copy() + t |= t + self.assertEqual(t, self.s) + t &= t + self.assertEqual(t, self.s) + t -= t + self.assertEqual(t, self.thetype()) + t = self.s.copy() + t ^= t + self.assertEqual(t, self.thetype()) + def test_weakref(self): s = self.thetype('gallahad') p = proxy(s) From rhettinger at users.sourceforge.net Thu Aug 11 09:58:56 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu, 11 Aug 2005 09:58:56 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.45,1.46 Message-ID: <20050811075856.1C4B31E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26888/Objects Modified Files: setobject.c Log Message: * Add short-circuit code for in-place operations with self (such as s|=s, s&=s, s-=s, or s^=s). Add related tests. * Improve names for several variables and functions. * Provide alternate table access functions (next, contains, add, and discard) that work with an entry argument instead of just a key. This improves set-vs-set operations because we already have a hash value for each key and can avoid unnecessary calls to PyObject_Hash(). Provides a 5% to 20% speed-up for quick hashing elements like strings and integers. Provides much more substantial improvements for slow hashing elements like tuples or objects defining a custom __hash__() function. * Have difference operations resize() when 1/5 of the elements are dummies. Formerly, it was 1/6. The new ratio triggers less frequently and only in cases that it can resize quicker and with greater benefit. The right answer is probably either 1/4, 1/5, or 1/6. Picked the middle value for an even trade-off between resize time and the space/time costs of dummy entries. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.45 retrieving revision 1.46 diff -u -d -r1.45 -r1.46 --- setobject.c 7 Aug 2005 13:02:53 -0000 1.45 +++ setobject.c 11 Aug 2005 07:58:44 -0000 1.46 @@ -1,3 +1,4 @@ + /* set object implementation Written and maintained by Raymond D. Hettinger Derived from Lib/sets.py and Objects/dictobject.c. @@ -226,7 +227,6 @@ typedef setentry *(*lookupfunc)(PySetObject *, PyObject *, long); assert(so->lookup != NULL); - entry = so->lookup(so, key, hash); if (entry->key == NULL) { /* UNUSED */ @@ -336,18 +336,30 @@ return 0; } -/* CAUTION: set_add_internal() must guarantee that it won't resize the table */ +/* CAUTION: set_add_key/entry() must guarantee it won't resize the table */ + static int -set_add_internal(register PySetObject *so, PyObject *key) +set_add_entry(register PySetObject *so, setentry *entry) +{ + register int n_used; + + assert(so->fill <= so->mask); /* at least one empty slot */ + n_used = so->used; + Py_INCREF(entry->key); + set_insert_key(so, entry->key, entry->hash); + if (!(so->used > n_used && so->fill*3 >= (so->mask+1)*2)) + return 0; + return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); +} + +static int +set_add_key(register PySetObject *so, PyObject *key) { register long hash; register int n_used; - if (PyString_CheckExact(key)) { - hash = ((PyStringObject *)key)->ob_shash; - if (hash == -1) - hash = PyObject_Hash(key); - } else { + if (!PyString_CheckExact(key) || + (hash = ((PyStringObject *) key)->ob_shash) == -1) { hash = PyObject_Hash(key); if (hash == -1) return -1; @@ -365,7 +377,23 @@ #define DISCARD_FOUND 1 static int -set_discard_internal(PySetObject *so, PyObject *key) +set_discard_entry(PySetObject *so, setentry *oldentry) +{ register setentry *entry; + PyObject *old_key; + + entry = (so->lookup)(so, oldentry->key, oldentry->hash); + if (entry->key == NULL || entry->key == dummy) + return DISCARD_NOTFOUND; + old_key = entry->key; + Py_INCREF(dummy); + entry->key = dummy; + so->used--; + Py_DECREF(old_key); + return DISCARD_FOUND; +} + +static int +set_discard_key(PySetObject *so, PyObject *key) { register long hash; register setentry *entry; @@ -457,39 +485,39 @@ * Iterate over a set table. Use like so: * * int pos; - * PyObject *key; + * setentry *entry; * pos = 0; # important! pos should not otherwise be changed by you - * while (set_next_internal(yourset, &pos, &key)) { - * Refer to borrowed reference in key. + * while (set_next(yourset, &pos, &entry)) { + * Refer to borrowed reference in entry->key. * } * - * CAUTION: In general, it isn't safe to use set_next_internal in a loop that + * CAUTION: In general, it isn't safe to use set_next in a loop that * mutates the table. */ static int -set_next_internal(PySetObject *so, int *pos, PyObject **key) +set_next(PySetObject *so, int *pos_ptr, setentry **entry_ptr) { register int i, mask; - register setentry *entry; + register setentry *table; assert (PyAnySet_Check(so)); - i = *pos; + i = *pos_ptr; if (i < 0) return 0; - entry = so->table; + table = so->table; mask = so->mask; - while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) + while (i <= mask && (table[i].key == NULL || table[i].key == dummy)) i++; - *pos = i+1; + *pos_ptr = i+1; if (i > mask) return 0; - if (key) - *key = entry[i].key; + if (table[i].key) + *entry_ptr = &table[i]; return 1; } static int -set_merge_internal(PySetObject *so, PyObject *otherset) +set_merge(PySetObject *so, PyObject *otherset) { PySetObject *other; register int i; @@ -525,7 +553,7 @@ } static int -set_contains_internal(PySetObject *so, PyObject *key) +set_contains_key(PySetObject *so, PyObject *key) { long hash; @@ -539,6 +567,15 @@ return key != NULL && key != dummy; } +static int +set_contains_entry(PySetObject *so, setentry *entry) +{ + PyObject *key; + + key = (so->lookup)(so, entry->key, entry->hash)->key; + return key != NULL && key != dummy; +} + /***** Set iterator type ***********************************************/ static PyTypeObject PySetIter_Type; /* Forward */ @@ -667,13 +704,13 @@ PyObject *key, *it; if (PyAnySet_Check(other)) - return set_merge_internal(so, other); + return set_merge(so, other); if (PyDict_Check(other)) { PyObject *key, *value; int pos = 0; while (PyDict_Next(other, &pos, &key, &value)) { - if (set_add_internal(so, key) == -1) + if (set_add_key(so, key) == -1) return -1; } return 0; @@ -684,7 +721,7 @@ return -1; while ((key = PyIter_Next(it)) != NULL) { - if (set_add_internal(so, key) == -1) { + if (set_add_key(so, key) == -1) { Py_DECREF(it); Py_DECREF(key); return -1; @@ -833,10 +870,10 @@ set_traverse(PySetObject *so, visitproc visit, void *arg) { int pos = 0; - PyObject *key; + setentry *entry; - while (set_next_internal(so, &pos, &key)) - Py_VISIT(key); + while (set_next(so, &pos, &entry)) + Py_VISIT(entry->key); return 0; } @@ -897,14 +934,14 @@ PyObject *tmpkey; int result; - result = set_contains_internal(so, key); + result = set_contains_key(so, key); if (result == -1 && PyAnySet_Check(key)) { PyErr_Clear(); tmpkey = make_new_set(&PyFrozenSet_Type, NULL); if (tmpkey == NULL) return -1; set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - result = set_contains_internal(so, tmpkey); + result = set_contains_key(so, tmpkey); set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); Py_DECREF(tmpkey); } @@ -943,6 +980,15 @@ PyDoc_STRVAR(copy_doc, "Return a shallow copy of a set."); static PyObject * +set_clear(PySetObject *so) +{ + set_clear_internal(so); + Py_RETURN_NONE; +} + +PyDoc_STRVAR(clear_doc, "Remove all elements from this set."); + +static PyObject * set_union(PySetObject *so, PyObject *other) { PySetObject *result; @@ -991,6 +1037,11 @@ PySetObject *result; PyObject *key, *it, *tmp; + if ((PyObject *)so == other) { + Py_INCREF(other); + return other; + } + result = (PySetObject *)make_new_set(so->ob_type, NULL); if (result == NULL) return NULL; @@ -1001,11 +1052,12 @@ other = tmp; } - if (PyAnySet_Check(other)) { + if (PyAnySet_Check(other)) { int pos = 0; - while (set_next_internal((PySetObject *)other, &pos, &key)) { - if (set_contains_internal(so, key)) { - if (set_add_internal(result, key) == -1) { + setentry *entry; + while (set_next((PySetObject *)other, &pos, &entry)) { + if (set_contains_entry(so, entry)) { + if (set_add_entry(result, entry) == -1) { Py_DECREF(result); return NULL; } @@ -1021,8 +1073,8 @@ } while ((key = PyIter_Next(it)) != NULL) { - if (set_contains_internal(so, key)) { - if (set_add_internal(result, key) == -1) { + if (set_contains_key(so, key)) { + if (set_add_key(result, key) == -1) { Py_DECREF(it); Py_DECREF(result); Py_DECREF(key); @@ -1087,32 +1139,48 @@ return (PyObject *)so; } -static PyObject * -set_difference_update(PySetObject *so, PyObject *other) +int +set_difference_update_internal(PySetObject *so, PyObject *other) { - PyObject *key, *it; + if ((PyObject *)so == other) + return set_clear_internal(so); - it = PyObject_GetIter(other); - if (it == NULL) - return NULL; + if (PyAnySet_Check(other)) { + setentry *entry; + int pos = 0; - while ((key = PyIter_Next(it)) != NULL) { - if (set_discard_internal(so, key) == -1) { - Py_DECREF(it); + while (set_next((PySetObject *)other, &pos, &entry)) + set_discard_entry(so, entry); + } else { + PyObject *key, *it; + it = PyObject_GetIter(other); + if (it == NULL) + return -1; + + while ((key = PyIter_Next(it)) != NULL) { + if (set_discard_key(so, key) == -1) { + Py_DECREF(it); + Py_DECREF(key); + return -1; + } Py_DECREF(key); - return NULL; } - Py_DECREF(key); + Py_DECREF(it); + if (PyErr_Occurred()) + return -1; } - Py_DECREF(it); - if (PyErr_Occurred()) - return NULL; - /* If more than 1/6 are dummies, then resize them away. */ - if ((so->fill - so->used) * 6 < so->mask) + /* If more than 1/5 are dummies, then resize them away. */ + if ((so->fill - so->used) * 5 < so->mask) + return 0; + return set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4); +} + +static PyObject * +set_difference_update(PySetObject *so, PyObject *other) +{ + if (set_difference_update_internal(so, other) != -1) Py_RETURN_NONE; - if (set_table_resize(so, so->used>50000 ? so->used*2 : so->used*4) == -1) - return NULL; - Py_RETURN_NONE; + return NULL; } PyDoc_STRVAR(difference_update_doc, @@ -1121,18 +1189,16 @@ static PyObject * set_difference(PySetObject *so, PyObject *other) { - PyObject *tmp, *key, *result; + PyObject *result; + setentry *entry; int pos = 0; if (!PyAnySet_Check(other) && !PyDict_Check(other)) { result = set_copy(so); if (result == NULL) + return NULL; + if (set_difference_update_internal((PySetObject *)result, other) != -1) return result; - tmp = set_difference_update((PySetObject *)result, other); - if (tmp != NULL) { - Py_DECREF(tmp); - return result; - } Py_DECREF(result); return NULL; } @@ -1142,18 +1208,21 @@ return NULL; if (PyDict_Check(other)) { - while (set_next_internal(so, &pos, &key)) { - if (!PyDict_Contains(other, key)) { - if (set_add_internal((PySetObject *)result, key) == -1) + while (set_next(so, &pos, &entry)) { + setentry entrycopy; + entrycopy.hash = entry->hash; + entrycopy.key = entry->key; + if (!PyDict_Contains(other, entry->key)) { + if (set_add_entry((PySetObject *)result, &entrycopy) == -1) return NULL; } } return result; } - while (set_next_internal(so, &pos, &key)) { - if (!set_contains_internal((PySetObject *)other, key)) { - if (set_add_internal((PySetObject *)result, key) == -1) + while (set_next(so, &pos, &entry)) { + if (!set_contains_entry((PySetObject *)other, entry)) { + if (set_add_entry((PySetObject *)result, entry) == -1) return NULL; } } @@ -1197,16 +1266,20 @@ PySetObject *otherset; PyObject *key; int pos = 0; + setentry *entry; + + if ((PyObject *)so == other) + return set_clear(so); if (PyDict_Check(other)) { PyObject *value; int rv; while (PyDict_Next(other, &pos, &key, &value)) { - rv = set_discard_internal(so, key); + rv = set_discard_key(so, key); if (rv == -1) return NULL; if (rv == DISCARD_NOTFOUND) { - if (set_add_internal(so, key) == -1) + if (set_add_key(so, key) == -1) return NULL; } } @@ -1222,14 +1295,14 @@ return NULL; } - while (set_next_internal(otherset, &pos, &key)) { - int rv = set_discard_internal(so, key); + while (set_next(otherset, &pos, &entry)) { + int rv = set_discard_entry(so, entry); if (rv == -1) { Py_XDECREF(otherset); return NULL; } if (rv == DISCARD_NOTFOUND) { - if (set_add_internal(so, key) == -1) { + if (set_add_entry(so, entry) == -1) { Py_XDECREF(otherset); return NULL; } @@ -1312,7 +1385,7 @@ for (i=so->used ; i ; entry++, i--) { while (entry->key == NULL || entry->key==dummy) entry++; - if (!set_contains_internal((PySetObject *)other, entry->key)) + if (!set_contains_entry((PySetObject *)other, entry)) Py_RETURN_FALSE; } Py_RETURN_TRUE; @@ -1448,16 +1521,16 @@ static int set_tp_print(PySetObject *so, FILE *fp, int flags) { - PyObject *key; + setentry *entry; int pos=0; char *emit = ""; /* No separator emitted on first pass */ char *separator = ", "; fprintf(fp, "%s([", so->ob_type->tp_name); - while (set_next_internal(so, &pos, &key)) { + while (set_next(so, &pos, &entry)) { fputs(emit, fp); emit = separator; - if (PyObject_Print(key, fp, 0) != 0) + if (PyObject_Print(entry->key, fp, 0) != 0) return -1; } fputs("])", fp); @@ -1465,18 +1538,9 @@ } static PyObject * -set_clear(PySetObject *so) -{ - set_clear_internal(so); - Py_RETURN_NONE; -} - -PyDoc_STRVAR(clear_doc, "Remove all elements from this set."); - -static PyObject * set_add(PySetObject *so, PyObject *key) { - if (set_add_internal(so, key) == -1) + if (set_add_key(so, key) == -1) return NULL; Py_RETURN_NONE; } @@ -1503,7 +1567,7 @@ return result; } - rv = set_discard_internal(so, key); + rv = set_discard_key(so, key); if (rv == -1) return NULL; else if (rv == DISCARD_NOTFOUND) { @@ -1534,7 +1598,7 @@ return result; } - if (set_discard_internal(so, key) == -1) + if (set_discard_key(so, key) == -1) return NULL; Py_RETURN_NONE; } From pje at users.sourceforge.net Thu Aug 11 16:59:05 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Thu, 11 Aug 2005 16:59:05 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command install.py, 1.3, 1.4 Message-ID: <20050811145905.44A321E4003@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13707/setuptools/command Modified Files: install.py Log Message: Fixed breakage of bdist_* commands that call the 'install' command. Index: install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/install.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- install.py 6 Aug 2005 19:29:49 -0000 1.3 +++ install.py 11 Aug 2005 14:58:54 -0000 1.4 @@ -1,8 +1,8 @@ -import setuptools +import setuptools, sys from distutils.command.install import install as _install class install(_install): - """Build dependencies before installation""" + """Use easy_install to install the package, w/dependencies""" def handle_extra_path(self): # We always ignore extra_path, because we always install eggs @@ -11,6 +11,16 @@ self.extra_dirs = '' def run(self): + calling_module = sys._getframe(1).f_globals.get('__name__','') + if calling_module != 'distutils.dist': + # We're not being run from the command line, so use old-style + # behavior. This is a bit kludgy, because a command might use + # dist.run_command() to run 'install', but bdist_dumb and + # bdist_wininst both call run directly at the moment. + # When this is part of the distutils, the old install behavior + # should probably be requested with a flag, or a different method. + return _install.run(self) + from setuptools.command.easy_install import easy_install cmd = easy_install( self.distribution, args="x", ignore_conflicts_at_my_risk=1 @@ -28,4 +38,3 @@ cmd.run() setuptools.bootstrap_install_from = None - From geraldocarvalho278346 at yahoo.com.br Thu Aug 11 23:31:34 2005 From: geraldocarvalho278346 at yahoo.com.br (Geraldo Carvalho) Date: Thu, 11 Aug 2005 18:31:34 -0300 Subject: [Python-checkins] mala direta, lista de emails, divulga??o de sites Message-ID: <20050811213300.180681E4009@bag.python.org> emails, e-mails por estados, e-mails cidade, cadastro e-mail, mala direta por e-mail, listas emails, e-mail regi?es, propaganda email, enviar email an?nimo, envio mala direta, estados, campanha, cidade, envio, publicidade e-mails, Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm campanhas e-mail, lista e-mail, programas e-mails, e-mails estado, publicidade emails, marketing digital, cidade, divulgar, lista email, email cidades, campanha e-mail, e-mail estado, listas email, lista emails, propaganda por e-mails, mala direta email, publicidade, cidades, marketing emails, cidade, email por regi?es, envio propaganda, listas e-mails, e-mails regi?es, divulgar e-mails, envio mala-direta, e-mail cidades, email estado, e-mails por Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm regi?o, marketing por emails, propaganda, software email em massa, propaganda digital e-mail, programas email, email, mala direta, propaganda e-mail, marketing e-mails, e-mail, mala-direta email, propaganda digital, emails por regi?o, email segmentado, estado, campanhas e-mails, e-mails cidades, e-mails segmentados, email por estado, marketing por email, emails segmentado, divulga??o, e-mails estados, cidade, campanha e-mails, software, email segmentados, regi?o, enviar e-mails an?nimo, enviar emails an?nimo, mala direta emails, marketing email, emails segmentados, programas e-mail, e-mails por cidade, lista e-mails, propaganda, mala direta por e-mails, campanha email, software spam internet, Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm emails estado, publicidade e-mail, e-mail por cidades, enviar e-mail an?nimo, software propaganda internet, emails cidade, emails, campanhas emails, mala-direta e-mail, publicidade email, mala direta e-mails, e-mail regi?o, listas, listas segmentadas, marketing, marketing digital por emails, email regi?o, divulga??o e-mail, emails por cidade, mala-direta por email, marketing digital por e-mails, listas email, lista segmentada, cidades, cadastro email, divulgue seu produto, mala-direta por e-mails, e-mail por estado, segmentos, email por cidades, propaganda por e-mail, emails cidades, publicidade por emails, envio e-mail, e-mails por estado, mala direta, mala-direta, mala-direta por emails, e-mail segmentado, marketing digital emails, cidades, divulga??o e-mails, marketing, e-mail estados, cidades, marketing por e-mail, envio emails, marketing digital email, propaganda Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm por email, envio an?nimo email, divulgue sua propaganda, propaganda digital emails, cidade, emails por cidades, e-mails segmentado, propaganda por emails, divulgar email, e-mail cidade, enviar e-mails, e-mails, cadastro emails, e-mail por cidade, envio email, cadastro, lista, envio e-mails, propaganda digital email, publicidade por e-mails, marketing digital, e-mail por regi?o, email por estados, divulga??o, emails por estados, segmentados, mala-direta emails, envio publicidade, campanhas, mala direta por emails, e-mail por estados, marketing por e-mails, emails por estado, mala-direta e-mails, marketing digital e-mail, divulgar emails, emails regi?es, publicidade, email por regi?o, e-mails por regi?es, listas e-mail, divulga??o emails, mala-direta por e-mail, enviar e-mail, enviar email, Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm divulga??o email, cidades, publicidade por e-mail, enviar, emails por regi?es, marketing digital por e-mail, email por cidade, campanhas email, marketing digital por email, marketing digital e-mails, propaganda e-mails, e-mail segmentados, envio an?nimo e-mail, software publicidade internet, segmentados, envio an?nimo e-mails, lista mala direta, programa email an?nimo, mala direta internet, publicidade email, mala direta segmentada, emails segmentados, marketing digital, mala direta email, publicidade, spam, mala direta e-mail, email regi?es, e-mails regi?o, mala direta por email, marketing e-mail, regi?es, cadastro e-mails, publicidade por email, emails regi?o, divulgar, enviar emails, campanha emails, propaganda emails, email cidade, envio an?nimo emails, email estados, divulgar e-mail, programas emails, e-mails por estados, e-mails cidade, cadastro e-mail, mala direta por e-mail, listas emails, e-mail regi?es, propaganda email, enviar email an?nimo, envio Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm mala direta, estados, campanha, cidade, envio, publicidade e-mails, campanhas e-mail, lista e-mail, programas e-mails, e-mails estado, publicidade emails, marketing digital, cidade, divulgar, lista email, emails estados, propaganda digital e-mails, e-mail por regi?es, e-mails por cidades, email cidades, campanha e-mail, e-mail estado, listas email, lista emails, propaganda por e-mails, mala direta email, publicidade, cidades, marketing emails, cidade, email por regi?es, envio propaganda, listas e-mails, e-mails regi?es, divulgar e-mails, envio mala-direta, e-mail cidades, email estado, e-mails por regi?o, marketing por emails, propaganda, software email em massa, propaganda digital e-mail, programas email, email, mala direta, propaganda e-mail, marketing e-mails, e-mail, mala-direta email, propaganda Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm digital, emails por regi?o, email segmentado, estado, campanhas e-mails, e-mails cidades, e-mails segmentados, email por estado, marketing por email, emails segmentado, divulga??o, e-mails estados, cidade, campanha e-mails, software, email segmentados, regi?o, enviar e-mails an?nimo, enviar emails an?nimo, mala direta emails, marketing email, emails segmentados, programas e-mail, e-mails por cidade, lista e-mails, propaganda, mala direta por e-mails, campanha email, software spam internet, emails Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm estado, publicidade e-mail, e-mail por cidades, enviar e-mail an?nimo, software propaganda internet, emails cidade, emails, campanhas emails, mala-direta e-mail, publicidade email, mala direta e-mails, e-mail regi?o, listas, listas segmentadas, marketing, marketing digital por emails, email regi?o, divulga??o e-mail, emails por cidade, mala-direta por email, marketing digital por e-mails, listas email, lista segmentada, cidades, cadastro email, divulgue seu produto, mala-direta por e-mails, e-mail por estado, segmentos, email por cidades, propaganda por e-mail, emails cidades, publicidade por emails, envio e-mail Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm mails por estado, mala direta, mala-direta, mala-direta por emails, e-mail segmentado, marketing digital emails, cidades, divulga??o e-mails, marketing, e-mail estados, cidades, marketing por e-mail, envio emails, marketing digital email, propaganda por email, envio an?nimo email, divulgue sua propaganda, propaganda digital emails, cidade, emails por cidades, e-mails segmentado, propaganda por emails, divulgar email, e-mail cidade, enviar e-mails, e-mails, cadastro emails, e-mail por cidade, envio email, cadastro, lista, envio e-mails, propaganda digital email, publicidade por e-mails, marketing digital, e-mail por regi?o, email por estados, divulga??o, emails por estados, segmentados, mala-direta emails, envio publicidade, campanhas, mala direta por emails, e-mail por estados, marketing por e-mail Visite agora clicando em qualquer um dos 3 links: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm mails, emails por estado, mala-direta e-mails, marketing digital e-mail, divulgar emails, emails regi?es, publicidade, email por regi?o, e-mails por regi?es, listas e-mail, divulga??o emails, mala-direta por e-mail, enviar e-mail, enviar email, divulga??o email, cidades, publicidade por e-mail, enviar, emails por regi?es, marketing digital por e-mail, email por cidade, campanhas email, marketing digital por email, marketing digital e-mails, propaganda e-mails, e-mail segmentados, envio an?nimo e-mail, software publicidade internet, segmentados, envio an?nimo e-mails, lista mala direta, programa email an?nimo, mala direta internet, publicidade email, mala direta segmentada, emails segmentados, marketing digital, mala direta email, publicidade, spam mails por estado, mala direta, mala-direta, mala-direta por emails, e-mail segmentado, marketing digital emails, cidades, divulga??o e-mails, marketing, e-mail estados, cidades, marketing por e-mail, envio emails, marketing digital email, propaganda por email. From akuchling at users.sourceforge.net Fri Aug 12 16:02:42 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Fri, 12 Aug 2005 16:02:42 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libbinascii.tex, 1.23, 1.24 Message-ID: <20050812140242.C0F131E4007@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8122 Modified Files: libbinascii.tex Log Message: Document 'istext' parameter Index: libbinascii.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libbinascii.tex,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- libbinascii.tex 28 Nov 2001 07:26:15 -0000 1.23 +++ libbinascii.tex 12 Aug 2005 14:02:32 -0000 1.24 @@ -51,10 +51,13 @@ Convert binary data to a line(s) of \ASCII{} characters in quoted-printable encoding. The return value is the converted line(s). If the optional argument \var{quotetabs} is present and true, all tabs -and spaces will be encoded. If the optional argument \var{header} is +and spaces will be encoded. +If the optional argument \var{istext} is present and true, +newlines are not encoded but trailing whitespace will be encoded. +If the optional argument \var{header} is present and true, spaces will be encoded as underscores per RFC1522. If the optional argument \var{header} is present and false, newline -characters will be encoded as well, otherwise linefeed conversion might +characters will be encoded as well; otherwise linefeed conversion might corrupt the binary data stream. \end{funcdesc} From akuchling at users.sourceforge.net Fri Aug 12 16:08:20 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Fri, 12 Aug 2005 16:08:20 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libbinascii.tex, 1.23, 1.23.28.1 Message-ID: <20050812140820.BC8421E4007@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9582 Modified Files: Tag: release24-maint libbinascii.tex Log Message: Document 'istext' parameter Index: libbinascii.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libbinascii.tex,v retrieving revision 1.23 retrieving revision 1.23.28.1 diff -u -d -r1.23 -r1.23.28.1 --- libbinascii.tex 28 Nov 2001 07:26:15 -0000 1.23 +++ libbinascii.tex 12 Aug 2005 14:08:10 -0000 1.23.28.1 @@ -51,10 +51,13 @@ Convert binary data to a line(s) of \ASCII{} characters in quoted-printable encoding. The return value is the converted line(s). If the optional argument \var{quotetabs} is present and true, all tabs -and spaces will be encoded. If the optional argument \var{header} is +and spaces will be encoded. +If the optional argument \var{istext} is present and true, +newlines are not encoded but trailing whitespace will be encoded. +If the optional argument \var{header} is present and true, spaces will be encoded as underscores per RFC1522. If the optional argument \var{header} is present and false, newline -characters will be encoded as well, otherwise linefeed conversion might +characters will be encoded as well; otherwise linefeed conversion might corrupt the binary data stream. \end{funcdesc} From nascheme at users.sourceforge.net Fri Aug 12 19:35:07 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Fri, 12 Aug 2005 19:35:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_unicode.py, 1.94, 1.95 Message-ID: <20050812173507.7F0591E4007@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19776/Lib/test Modified Files: test_unicode.py Log Message: Change the %s format specifier for str objects so that it returns a unicode instance if the argument is not an instance of basestring and calling __str__ on the argument returns a unicode instance. Index: test_unicode.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_unicode.py,v retrieving revision 1.94 retrieving revision 1.95 diff -u -d -r1.94 -r1.95 --- test_unicode.py 26 Apr 2005 03:45:26 -0000 1.94 +++ test_unicode.py 12 Aug 2005 17:34:57 -0000 1.95 @@ -388,6 +388,10 @@ self.assertEqual('%i %*.*s' % (10, 5,3,u'abc',), u'10 abc') self.assertEqual('%i%s %*.*s' % (10, 3, 5, 3, u'abc',), u'103 abc') self.assertEqual('%c' % u'a', u'a') + class Wrapper: + def __str__(self): + return u'\u1234' + self.assertEqual('%s' % Wrapper(), u'\u1234') def test_constructor(self): # unicode(obj) tests (this maps to PyObject_Unicode() at C level) From nascheme at users.sourceforge.net Fri Aug 12 19:35:07 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Fri, 12 Aug 2005 19:35:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1332,1.1333 Message-ID: <20050812173507.7E9A21E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19776/Misc Modified Files: NEWS Log Message: Change the %s format specifier for str objects so that it returns a unicode instance if the argument is not an instance of basestring and calling __str__ on the argument returns a unicode instance. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1332 retrieving revision 1.1333 diff -u -d -r1.1332 -r1.1333 --- NEWS 9 Aug 2005 15:00:51 -0000 1.1332 +++ NEWS 12 Aug 2005 17:34:57 -0000 1.1333 @@ -118,6 +118,10 @@ positions. It once again reports a syntax error if a future statement occurs after anything other than a doc string. +- Change the %s format specifier for str objects so that it returns a + unicode instance if the argument is not an instance of basestring and + calling __str__ on the argument returns a unicode instance. + Extension Modules ----------------- From nascheme at users.sourceforge.net Fri Aug 12 19:35:08 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Fri, 12 Aug 2005 19:35:08 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Include object.h,2.130,2.131 Message-ID: <20050812173508.D09E61E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19776/Include Modified Files: object.h Log Message: Change the %s format specifier for str objects so that it returns a unicode instance if the argument is not an instance of basestring and calling __str__ on the argument returns a unicode instance. Index: object.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/object.h,v retrieving revision 2.130 retrieving revision 2.131 diff -u -d -r2.130 -r2.131 --- object.h 23 Sep 2004 02:39:36 -0000 2.130 +++ object.h 12 Aug 2005 17:34:58 -0000 2.131 @@ -371,6 +371,7 @@ PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int); PyAPI_FUNC(void) _PyObject_Dump(PyObject *); PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *); +PyAPI_FUNC(PyObject *) _PyObject_Str(PyObject *); PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *); #ifdef Py_USING_UNICODE PyAPI_FUNC(PyObject *) PyObject_Unicode(PyObject *); From nascheme at users.sourceforge.net Fri Aug 12 19:35:08 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Fri, 12 Aug 2005 19:35:08 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects object.c, 2.226, 2.227 stringobject.c, 2.230, 2.231 Message-ID: <20050812173508.E0BA51E400F@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19776/Objects Modified Files: object.c stringobject.c Log Message: Change the %s format specifier for str objects so that it returns a unicode instance if the argument is not an instance of basestring and calling __str__ on the argument returns a unicode instance. Index: object.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v retrieving revision 2.226 retrieving revision 2.227 diff -u -d -r2.226 -r2.227 --- object.c 26 Apr 2005 03:45:25 -0000 2.226 +++ object.c 12 Aug 2005 17:34:57 -0000 2.227 @@ -331,22 +331,48 @@ } PyObject * -PyObject_Str(PyObject *v) +_PyObject_Str(PyObject *v) { PyObject *res; - + int type_ok; if (v == NULL) return PyString_FromString(""); if (PyString_CheckExact(v)) { Py_INCREF(v); return v; } +#ifdef Py_USING_UNICODE + if (PyUnicode_CheckExact(v)) { + Py_INCREF(v); + return v; + } +#endif if (v->ob_type->tp_str == NULL) return PyObject_Repr(v); res = (*v->ob_type->tp_str)(v); if (res == NULL) return NULL; + type_ok = PyString_Check(res); +#ifdef Py_USING_UNICODE + type_ok = type_ok || PyUnicode_Check(res); +#endif + if (!type_ok) { + PyErr_Format(PyExc_TypeError, + "__str__ returned non-string (type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + return res; +} + +PyObject * +PyObject_Str(PyObject *v) +{ + PyObject *res = _PyObject_Str(v); + if (res == NULL) + return NULL; #ifdef Py_USING_UNICODE if (PyUnicode_Check(res)) { PyObject* str; @@ -358,13 +384,7 @@ return NULL; } #endif - if (!PyString_Check(res)) { - PyErr_Format(PyExc_TypeError, - "__str__ returned non-string (type %.200s)", - res->ob_type->tp_name); - Py_DECREF(res); - return NULL; - } + assert(PyString_Check(res)); return res; } Index: stringobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/stringobject.c,v retrieving revision 2.230 retrieving revision 2.231 diff -u -d -r2.230 -r2.231 --- stringobject.c 29 Jun 2005 23:29:54 -0000 2.230 +++ stringobject.c 12 Aug 2005 17:34:57 -0000 2.231 @@ -3853,7 +3853,6 @@ return 1; } - /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) FORMATBUFLEN is the length of the buffer in which the floats, ints, & @@ -4079,7 +4078,9 @@ break; case 's': #ifdef Py_USING_UNICODE - if (PyUnicode_Check(v)) { + temp = _PyObject_Str(v); + if (temp != NULL && PyUnicode_Check(temp)) { + Py_DECREF(temp); fmt = fmt_start; argidx = argidx_start; goto unicode; @@ -4087,16 +4088,11 @@ #endif /* Fall through */ case 'r': - if (c == 's') - temp = PyObject_Str(v); - else + if (c == 'r') temp = PyObject_Repr(v); if (temp == NULL) goto error; if (!PyString_Check(temp)) { - /* XXX Note: this should never happen, - since PyObject_Repr() and - PyObject_Str() assure this */ PyErr_SetString(PyExc_TypeError, "%s argument has non-string str()"); Py_DECREF(temp); From rhettinger at users.sourceforge.net Fri Aug 12 22:48:50 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri, 12 Aug 2005 22:48:50 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.46,1.47 Message-ID: <20050812204850.B36C91E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1026 Modified Files: setobject.c Log Message: * Fix SF #1257731. Make __contains__(), remove(), and discard() only do a frozenset conversion when the initial search attempt fails with a TypeError and the key is some type of set. Add a testcase. * Eliminate a duplicate if-stmt. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- setobject.c 11 Aug 2005 07:58:44 -0000 1.46 +++ setobject.c 12 Aug 2005 20:48:39 -0000 1.47 @@ -932,20 +932,22 @@ set_contains(PySetObject *so, PyObject *key) { PyObject *tmpkey; - int result; + int rv; - result = set_contains_key(so, key); - if (result == -1 && PyAnySet_Check(key)) { + rv = set_contains_key(so, key); + if (rv == -1) { + if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) + return -1; PyErr_Clear(); tmpkey = make_new_set(&PyFrozenSet_Type, NULL); if (tmpkey == NULL) return -1; set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - result = set_contains_key(so, tmpkey); + rv = set_contains(so, tmpkey); set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); Py_DECREF(tmpkey); } - return result; + return rv; } static PyObject * @@ -1046,15 +1048,16 @@ if (result == NULL) return NULL; - if (PyAnySet_Check(other) && set_len(other) > set_len((PyObject *)so)) { - tmp = (PyObject *)so; - so = (PySetObject *)other; - other = tmp; - } - if (PyAnySet_Check(other)) { int pos = 0; setentry *entry; + + if (set_len(other) > set_len((PyObject *)so)) { + tmp = (PyObject *)so; + so = (PySetObject *)other; + other = tmp; + } + while (set_next((PySetObject *)other, &pos, &entry)) { if (set_contains_entry(so, entry)) { if (set_add_entry(result, entry) == -1) { @@ -1556,21 +1559,20 @@ PyObject *tmpkey, *result; int rv; - if (PyType_IsSubtype(key->ob_type, &PySet_Type)) { + rv = set_discard_key(so, key); + if (rv == -1) { + if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) + return NULL; + PyErr_Clear(); tmpkey = make_new_set(&PyFrozenSet_Type, NULL); if (tmpkey == NULL) return NULL; - set_swap_bodies((PySetObject *)key, (PySetObject *)tmpkey); + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); result = set_remove(so, tmpkey); - set_swap_bodies((PySetObject *)key, (PySetObject *)tmpkey); + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); Py_DECREF(tmpkey); return result; - } - - rv = set_discard_key(so, key); - if (rv == -1) - return NULL; - else if (rv == DISCARD_NOTFOUND) { + } else if (rv == DISCARD_NOTFOUND) { PyErr_SetObject(PyExc_KeyError, key); return NULL; } @@ -1586,20 +1588,22 @@ set_discard(PySetObject *so, PyObject *key) { PyObject *tmpkey, *result; + int rv; - if (PyType_IsSubtype(key->ob_type, &PySet_Type)) { + rv = set_discard_key(so, key); + if (rv == -1) { + if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) + return NULL; + PyErr_Clear(); tmpkey = make_new_set(&PyFrozenSet_Type, NULL); if (tmpkey == NULL) return NULL; - set_swap_bodies((PySetObject *)key, (PySetObject *)tmpkey); + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); result = set_discard(so, tmpkey); - set_swap_bodies((PySetObject *)key, (PySetObject *)tmpkey); + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); Py_DECREF(tmpkey); return result; } - - if (set_discard_key(so, key) == -1) - return NULL; Py_RETURN_NONE; } From loewis at users.sourceforge.net Sat Aug 13 01:14:16 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sat, 13 Aug 2005 01:14:16 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.10,1.11 Message-ID: <20050812231416.638DB1E4005@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3201 Modified Files: pep-0347.txt Log Message: Add wush.net hosting. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- pep-0347.txt 9 Aug 2005 01:17:05 -0000 1.10 +++ pep-0347.txt 12 Aug 2005 23:14:06 -0000 1.11 @@ -246,6 +246,17 @@ * Subversion over WebDAV, using SSL client certificates. This would work, but would require us to administer a certificate authority. +- Instead of hosting this on python.org, people suggested hosting + it elsewhere. One issue is whether this alternative should be + free or commercial; several people suggested it should better + be commercial, to reduce the load on the volunteers. In + particular: + + * Greg Stein suggested http://www.wush.net/subversion.php. They + offer 5 GB for $90/month, with 200 GB download/month. + The data is on a RAID drive and fully backed up. Anonymous + access and email commit notifications are supported. + Copyright ========= From loewis at users.sourceforge.net Sat Aug 13 01:15:24 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sat, 13 Aug 2005 01:15:24 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.11,1.12 Message-ID: <20050812231524.66FF61E4005@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3525 Modified Files: pep-0347.txt Log Message: Remove Nick Bastin's offer; this was a misinterpretation of his message. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- pep-0347.txt 12 Aug 2005 23:14:06 -0000 1.11 +++ pep-0347.txt 12 Aug 2005 23:15:14 -0000 1.12 @@ -218,9 +218,6 @@ was rejected because a single repository supports moving code across projects. -- Nick Bastin has offered to host a Perforce repository, instead - of using Subversion. Details of that offer are not clear yet. - - Several people suggested to create the project/trunk structure through standard cvs2svn, followed by renames. This would have the disadvantage that old revisions use different path names From rhettinger at users.sourceforge.net Sat Aug 13 01:48:00 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 01:48:00 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_set.py, 1.16.2.1, 1.16.2.2 Message-ID: <20050812234800.0601F1E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8678/Lib/test Modified Files: Tag: release24-maint test_set.py Log Message: * SF bug #1257731: Fix logic in set.__contains__(), set.remove(), and set.discard for handling keys that both inherite from set and define their own __hash__() function. * Fixed O(n) performance issue with set.pop() which should have been an O(1) process. Index: test_set.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_set.py,v retrieving revision 1.16.2.1 retrieving revision 1.16.2.2 diff -u -d -r1.16.2.1 -r1.16.2.2 --- test_set.py 19 Jun 2005 05:53:14 -0000 1.16.2.1 +++ test_set.py 12 Aug 2005 23:47:50 -0000 1.16.2.2 @@ -212,6 +212,19 @@ elem.sub = elem elem.set = set([elem]) + def test_subclass_with_custom_hash(self): + # Bug #1257731 + class H(self.thetype): + def __hash__(self): + return id(self) + s=H() + f=set() + f.add(s) + self.assert_(s in f) + f.remove(s) + f.add(s) + f.discard(s) + class TestSet(TestJointOps): thetype = set From rhettinger at users.sourceforge.net Sat Aug 13 01:48:00 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 01:48:00 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.70, 1.1193.2.71 Message-ID: <20050812234800.1FB3B1E4006@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8678/Misc Modified Files: Tag: release24-maint NEWS Log Message: * SF bug #1257731: Fix logic in set.__contains__(), set.remove(), and set.discard for handling keys that both inherite from set and define their own __hash__() function. * Fixed O(n) performance issue with set.pop() which should have been an O(1) process. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.70 retrieving revision 1.1193.2.71 diff -u -d -r1.1193.2.70 -r1.1193.2.71 --- NEWS 7 Aug 2005 21:08:54 -0000 1.1193.2.70 +++ NEWS 12 Aug 2005 23:47:50 -0000 1.1193.2.71 @@ -12,6 +12,11 @@ Core and builtins ----------------- +- SF bug #1257731: set.discard() and set.remove() did not correctly + handle keys that both inherited from set and defined their own + __hash__() function. Also, changed set.__contains__() to have + identical logic. + - SF bug #1238681: freed pointer is used in longobject.c:long_pow(). - SF bug #1185883: Python's small-object memory allocator took over From rhettinger at users.sourceforge.net Sat Aug 13 01:48:00 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 01:48:00 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c, 1.31.2.1, 1.31.2.2 Message-ID: <20050812234800.2DD771E4007@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8678/Objects Modified Files: Tag: release24-maint setobject.c Log Message: * SF bug #1257731: Fix logic in set.__contains__(), set.remove(), and set.discard for handling keys that both inherite from set and define their own __hash__() function. * Fixed O(n) performance issue with set.pop() which should have been an O(1) process. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.31.2.1 retrieving revision 1.31.2.2 diff -u -d -r1.31.2.1 -r1.31.2.2 --- setobject.c 19 Jun 2005 05:53:15 -0000 1.31.2.1 +++ setobject.c 12 Aug 2005 23:47:50 -0000 1.31.2.2 @@ -145,18 +145,20 @@ set_contains(PySetObject *so, PyObject *key) { PyObject *tmp; - int result; + int rv; - result = PyDict_Contains(so->data, key); - if (result == -1 && PyAnySet_Check(key)) { + rv = PyDict_Contains(so->data, key); + if (rv == -1) { + if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) + return -1; PyErr_Clear(); tmp = frozenset_dict_wrapper(((PySetObject *)(key))->data); if (tmp == NULL) return -1; - result = PyDict_Contains(so->data, tmp); + rv = PyDict_Contains(so->data, tmp); Py_DECREF(tmp); } - return result; + return rv; } static PyObject * @@ -791,19 +793,20 @@ set_remove(PySetObject *so, PyObject *item) { PyObject *tmp, *result; + int rv; - if (PyType_IsSubtype(item->ob_type, &PySet_Type)) { - tmp = frozenset_dict_wrapper(((PySetObject *)(item))->data); - if (tmp == NULL) - return NULL; - result = set_remove(so, tmp); - Py_DECREF(tmp); - return result; - } - - if (PyDict_DelItem(so->data, item) == -1) + rv = PyDict_DelItem(so->data, item); + if (rv == 0) + Py_RETURN_NONE; + if (!PyAnySet_Check(item) || !PyErr_ExceptionMatches(PyExc_TypeError)) return NULL; - Py_RETURN_NONE; + PyErr_Clear(); + tmp = frozenset_dict_wrapper(((PySetObject *)(item))->data); + if (tmp == NULL) + return NULL; + result = set_remove(so, tmp); + Py_DECREF(tmp); + return result; } PyDoc_STRVAR(remove_doc, @@ -815,22 +818,24 @@ set_discard(PySetObject *so, PyObject *item) { PyObject *tmp, *result; + int rv; - if (PyType_IsSubtype(item->ob_type, &PySet_Type)) { - tmp = frozenset_dict_wrapper(((PySetObject *)(item))->data); - if (tmp == NULL) - return NULL; - result = set_discard(so, tmp); - Py_DECREF(tmp); - return result; - } - - if (PyDict_DelItem(so->data, item) == -1) { - if (!PyErr_ExceptionMatches(PyExc_KeyError)) - return NULL; + rv = PyDict_DelItem(so->data, item); + if (rv == 0) + Py_RETURN_NONE; + if (PyErr_ExceptionMatches(PyExc_KeyError)) { PyErr_Clear(); + Py_RETURN_NONE; } - Py_RETURN_NONE; + if (!PyAnySet_Check(item) || !PyErr_ExceptionMatches(PyExc_TypeError)) + return NULL; + PyErr_Clear(); + tmp = frozenset_dict_wrapper(((PySetObject *)(item))->data); + if (tmp == NULL) + return NULL; + result = set_discard(so, tmp); + Py_DECREF(tmp); + return result; } PyDoc_STRVAR(discard_doc, @@ -841,18 +846,18 @@ static PyObject * set_pop(PySetObject *so) { - PyObject *key, *value; - int pos = 0; + PyObject *item, *key; - if (!PyDict_Next(so->data, &pos, &key, &value)) { + if (set_len(so) == 0) { PyErr_SetString(PyExc_KeyError, "pop from an empty set"); return NULL; } - Py_INCREF(key); - if (PyDict_DelItem(so->data, key) == -1) { - Py_DECREF(key); + item = PyObject_CallMethod(so->data, "popitem", NULL); + if (item == NULL) return NULL; - } + key = PyTuple_GET_ITEM(item, 0); + Py_INCREF(key); + Py_DECREF(item); return key; } From rhettinger at users.sourceforge.net Sat Aug 13 01:58:32 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 01:58:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_set.py,1.20,1.21 Message-ID: <20050812235832.E506E1E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10343 Modified Files: test_set.py Log Message: * Fix SF #1257731. Make __contains__(), remove(), and discard() only do a frozenset conversion when the initial search attempt fails with a TypeError and the key is some type of set. Add a testcase. * Eliminate a duplicate if-stmt. Index: test_set.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_set.py,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- test_set.py 11 Aug 2005 07:58:45 -0000 1.20 +++ test_set.py 12 Aug 2005 23:58:22 -0000 1.21 @@ -213,6 +213,19 @@ elem.sub = elem elem.set = set([elem]) + def test_subclass_with_custom_hash(self): + # Bug #1257731 + class H(self.thetype): + def __hash__(self): + return id(self) + s=H() + f=set() + f.add(s) + self.assert_(s in f) + f.remove(s) + f.add(s) + f.discard(s) + class TestSet(TestJointOps): thetype = set From nascheme at users.sourceforge.net Sat Aug 13 02:28:51 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Sat, 13 Aug 2005 02:28:51 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc gdbinit,1.9,1.10 Message-ID: <20050813002851.929E31E4007@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17968/Misc Modified Files: gdbinit Log Message: Fix pystack command. Index: gdbinit =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/gdbinit,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- gdbinit 8 Jan 2005 21:56:43 -0000 1.9 +++ gdbinit 13 Aug 2005 00:28:41 -0000 1.10 @@ -98,7 +98,7 @@ #end define printframe - if $pc > PyEval_EvalFrame && $pc < PyEval_EvalCodeEx + if $pc > PyEval_EvalFrameEx && $pc < PyEval_EvalCodeEx pyframe else frame From goodger at users.sourceforge.net Sat Aug 13 03:37:43 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sat, 13 Aug 2005 03:37:43 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0000.txt, 1.339, 1.340 pep-0001.txt, 1.45, 1.46 Message-ID: <20050813013743.3E7C41E4005@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29141 Modified Files: pep-0000.txt pep-0001.txt Log Message: added new Process PEP type Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.339 retrieving revision 1.340 diff -u -d -r1.339 -r1.340 --- pep-0000.txt 5 Aug 2005 02:59:00 -0000 1.339 +++ pep-0000.txt 13 Aug 2005 01:37:32 -0000 1.340 @@ -30,7 +30,7 @@ Meta-PEPs (PEPs about PEPs or Process) I 0 Index of Python Enhancement Proposals Goodger, Warsaw - I 1 PEP Guidelines Warsaw, Hylton, Goodger + P 1 PEP Guidelines Warsaw, Hylton, Goodger I 2 Procedure for Adding New Modules Faassen I 3 Guidelines for Handling Bug Reports Hylton I 4 Deprecation of Standard Modules von Loewis @@ -103,7 +103,7 @@ S 341 Unifying try-except and try-finally Birkenfeld S 344 Exception Chaining and Embedded Tracebacks Yee S 345 Metadata for Python Software Packages 1.2 Jones - I 347 Migrating the Python CVS to Subversion von Lwis + P 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon S 349 Generalized String Coercion Schemenauer S 754 IEEE 754 Floating Point Special Values Warnes @@ -225,7 +225,7 @@ num title owner --- ----- ----- I 0 Index of Python Enhancement Proposals Goodger, Warsaw - I 1 PEP Guidelines Warsaw, Hylton, Goodger + P 1 PEP Guidelines Warsaw, Hylton, Goodger I 2 Procedure for Adding New Modules Faassen I 3 Guidelines for Handling Bug Reports Hylton I 4 Deprecation of Standard Modules von Loewis @@ -391,7 +391,7 @@ S 344 Exception Chaining and Embedded Tracebacks Yee S 345 Metadata for Python Software Packages 1.2 Jones SR 346 User Defined ("with") Statements Coghlan - I 347 Migrating the Python CVS to Subversion von Lwis + P 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon S 349 Generalized String Coercion Schemenauer SR 666 Reject Foolish Indentation Creighton @@ -401,8 +401,10 @@ Key - I - Informational PEP S - Standards Track PEP + I - Informational PEP + P - Process PEP + A - Accepted proposal R - Rejected proposal D - Deferred proposal Index: pep-0001.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0001.txt,v retrieving revision 1.45 retrieving revision 1.46 diff -u -d -r1.45 -r1.46 --- pep-0001.txt 27 Aug 2004 21:19:48 -0000 1.45 +++ pep-0001.txt 13 Aug 2005 01:37:32 -0000 1.46 @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Barry A. Warsaw, Jeremy Hylton, David Goodger Status: Active -Type: Informational +Type: Process Content-Type: text/x-rst Created: 13-Jun-2000 Post-History: 21-Mar-2001, 29-Jul-2002, 03-May-2003 @@ -15,8 +15,9 @@ PEP stands for Python Enhancement Proposal. A PEP is a design document providing information to the Python community, or describing -a new feature for Python. The PEP should provide a concise technical -specification of the feature and a rationale for the feature. +a new feature for Python or its processes or environment. The PEP +should provide a concise technical specification of the feature and a +rationale for the feature. We intend PEPs to be the primary mechanisms for proposing new features, for collecting community input on an issue, and for @@ -29,16 +30,31 @@ [1]_. -Kinds of PEPs -============= +PEP Types +========= -There are two kinds of PEPs. A Standards Track PEP describes a new -feature or implementation for Python. An Informational PEP describes -a Python design issue, or provides general guidelines or information -to the Python community, but does not propose a new feature. -Informational PEPs do not necessarily represent a Python community -consensus or recommendation, so users and implementors are free to -ignore Informational PEPs or follow their advice. +There are three kinds of PEP: + +1. A **Standards Track** PEP describes a new feature or implementation + for Python. + +2. An **Informational** PEP describes a Python design issue, or + provides general guidelines or information to the Python community, + but does not propose a new feature. Informational PEPs do not + necessarily represent a Python community consensus or + recommendation, so users and implementors are free to ignore + Informational PEPs or follow their advice. + +3. A **Process** PEP describes a process surrounding Python, or + proposes a change to (or an event in) a process. Process PEPs are + like Standards Track PEPs but apply to areas other than the Python + language itself. They may propose an implementation, but not to + Python's codebase; they often require community consensus; unlike + Informational PEPs, they are more than recommendations, and users + are typically not free to ignore them. Examples include release + schedules, procedures, guidelines, changes to the decision-making + process, and changes to the tools or environment used in Python + development. PEP Work Flow @@ -71,14 +87,17 @@ draft must be written in PEP style as described below. If the PEP editor approves, he will assign the PEP a number, label it -as Standards Track or Informational, give it status "Draft", and -create and check-in the initial draft of the PEP. The PEP editor will -not unreasonably deny a PEP. Reasons for denying PEP status include -duplication of effort, being technically unsound, not providing proper -motivation or addressing backwards compatibility, or not in keeping -with the Python philosophy. The BDFL (Benevolent Dictator for Life, -Guido van Rossum) can be consulted during the approval phase, and is -the final arbitrator of the draft's PEP-ability. +as Standards Track, Informational, or Process, give it status "Draft", +and create and check-in the initial draft of the PEP. The PEP editor +will not unreasonably deny a PEP. Reasons for denying PEP status +include duplication of effort, being technically unsound, not +providing proper motivation or addressing backwards compatibility, or +not in keeping with the Python philosophy. The BDFL (Benevolent +Dictator for Life, Guido van Rossum) can be consulted during the +approval phase, and is the final arbitrator of the draft's +PEP-ability. + +arbiter? If a pre-PEP is rejected, the author may elect to take the pre-PEP to the comp.lang.python newsgroup (a.k.a. python-list at python.org mailing @@ -91,22 +110,22 @@ CVS commit permissions, or can email new PEP versions to the PEP editor for committing. -Standards Track PEPs consists of two parts, a design document and a +Standards Track PEPs consist of two parts, a design document and a reference implementation. The PEP should be reviewed and accepted before a reference implementation is begun, unless a reference implementation will aid people in studying the PEP. Standards Track -PEPs must include an implementation -- in the form of code, patch, or -URL to same -- before it can be considered Final. +PEPs must include an implementation -- in the form of code, a patch, +or a URL to same -- before it can be considered Final. PEP authors are responsible for collecting community feedback on a PEP before submitting it for review. A PEP that has not been discussed on python-list at python.org and/or python-dev at python.org will not be accepted. However, wherever possible, long open-ended discussions on public mailing lists should be avoided. Strategies to keep the -discussions efficient include, setting up a separate SIG mailing list +discussions efficient include: setting up a separate SIG mailing list for the topic, having the PEP author accept private comments in the -early design phases, etc. PEP authors should use their discretion -here. +early design phases, setting up a wiki page, etc. PEP authors should +use their discretion here. Once the authors have completed a PEP, they must inform the PEP editor that it is ready for review. PEPs are reviewed by the BDFL and his @@ -144,13 +163,9 @@ obsolete. This is intended for Informational PEPs, where version 2 of an API can replace version 1. -PEP work flow is as follows:: +PEP work flow is as follows: - Draft -> Accepted -> Final -> Replaced - ^ - +----> Rejected - v - Deferred +.. image:: pep-0001-1.png Some Informational PEPs may also have a status of "Active" if they are never meant to be completed. E.g. PEP 1 (this PEP). @@ -250,7 +265,7 @@ * Discussions-To: Status: - Type: + Type: * Content-Type: * Requires: Created: @@ -286,8 +301,8 @@ on the python-list or python-dev email mailing lists. Note that email addresses in the Discussions-To header will not be obscured. -The Type header specifies the type of PEP: Informational or Standards -Track. +The Type header specifies the type of PEP: Standards Track, +Informational, or Process. The format of a PEP is specified with a Content-Type header. The acceptable values are "text/plain" for plaintext PEPs (see PEP 9 [3]_) @@ -302,7 +317,7 @@ Standards Track PEPs must have a Python-Version header which indicates the version of Python that the feature will be released with. -Informational PEPs do not need a Python-Version header. +Informational and Process PEPs do not need a Python-Version header. PEPs may have a Requires header, indicating the PEP numbers that this PEP depends on. From goodger at users.sourceforge.net Sat Aug 13 03:38:01 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sat, 13 Aug 2005 03:38:01 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0001-1.png,NONE,1.1 Message-ID: <20050813013801.3162F1E4005@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29206 Added Files: pep-0001-1.png Log Message: PEP workflow diagram --- NEW FILE: pep-0001-1.png --- (This appears to be a binary file; contents omitted.) From goodger at users.sourceforge.net Sat Aug 13 03:42:26 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sat, 13 Aug 2005 03:42:26 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0001.txt,1.46,1.47 Message-ID: <20050813014226.B9E181E4005@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29733 Modified Files: pep-0001.txt Log Message: fixed idiom Index: pep-0001.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0001.txt,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- pep-0001.txt 13 Aug 2005 01:37:32 -0000 1.46 +++ pep-0001.txt 13 Aug 2005 01:42:17 -0000 1.47 @@ -94,10 +94,7 @@ providing proper motivation or addressing backwards compatibility, or not in keeping with the Python philosophy. The BDFL (Benevolent Dictator for Life, Guido van Rossum) can be consulted during the -approval phase, and is the final arbitrator of the draft's -PEP-ability. - -arbiter? +approval phase, and is the final arbiter of the draft's PEP-ability. If a pre-PEP is rejected, the author may elect to take the pre-PEP to the comp.lang.python newsgroup (a.k.a. python-list at python.org mailing From goodger at users.sourceforge.net Sat Aug 13 03:47:37 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sat, 13 Aug 2005 03:47:37 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.12,1.13 Message-ID: <20050813014737.AF33F1E4005@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30138 Modified Files: pep-0347.txt Log Message: changed PEP type Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- pep-0347.txt 12 Aug 2005 23:15:14 -0000 1.12 +++ pep-0347.txt 13 Aug 2005 01:47:28 -0000 1.13 @@ -5,7 +5,7 @@ Author: Martin v. Lwis Discussions-To: Status: Draft -Type: Informational +Type: Process Content-Type: text/x-rst Created: 14-Jul-2004 Post-History: 14-Jul-2004 From rhettinger at users.sourceforge.net Sat Aug 13 04:29:03 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 04:29:03 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib sets.py,1.49,1.49.4.1 Message-ID: <20050813022903.55FE71E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3812/Lib Modified Files: Tag: release24-maint sets.py Log Message: Teach set modules to correctly compute s-=s and s^=s as the empty set. Index: sets.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/sets.py,v retrieving revision 1.49 retrieving revision 1.49.4.1 diff -u -d -r1.49 -r1.49.4.1 --- sets.py 19 Nov 2003 15:52:14 -0000 1.49 +++ sets.py 13 Aug 2005 02:28:53 -0000 1.49.4.1 @@ -480,6 +480,8 @@ value = True if not isinstance(other, BaseSet): other = Set(other) + if self is other: + self.clear() for elt in other: if elt in data: del data[elt] @@ -497,6 +499,8 @@ data = self._data if not isinstance(other, BaseSet): other = Set(other) + if self is other: + self.clear() for elt in ifilter(data.has_key, other): del data[elt] From rhettinger at users.sourceforge.net Sat Aug 13 04:29:03 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 04:29:03 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_set.py, 1.16.2.2, 1.16.2.3 test_sets.py, 1.31, 1.31.2.1 Message-ID: <20050813022903.583871E4007@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3812/Lib/test Modified Files: Tag: release24-maint test_set.py test_sets.py Log Message: Teach set modules to correctly compute s-=s and s^=s as the empty set. Index: test_set.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_set.py,v retrieving revision 1.16.2.2 retrieving revision 1.16.2.3 diff -u -d -r1.16.2.2 -r1.16.2.3 --- test_set.py 12 Aug 2005 23:47:50 -0000 1.16.2.2 +++ test_set.py 13 Aug 2005 02:28:53 -0000 1.16.2.3 @@ -382,6 +382,18 @@ else: self.assert_(c not in self.s) + def test_inplace_on_self(self): + t = self.s.copy() + t |= t + self.assertEqual(t, self.s) + t &= t + self.assertEqual(t, self.s) + t -= t + self.assertEqual(t, self.thetype()) + t = self.s.copy() + t ^= t + self.assertEqual(t, self.thetype()) + def test_weakref(self): s = self.thetype('gallahad') p = proxy(s) Index: test_sets.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_sets.py,v retrieving revision 1.31 retrieving revision 1.31.2.1 diff -u -d -r1.31 -r1.31.2.1 --- test_sets.py 7 Aug 2004 06:15:12 -0000 1.31 +++ test_sets.py 13 Aug 2005 02:28:53 -0000 1.31.2.1 @@ -243,6 +243,19 @@ self.assertRaises(TypeError, cmp, a, 12) self.assertRaises(TypeError, cmp, "abc", a) + def test_inplace_on_self(self): + t = self.set.copy() + t |= t + self.assertEqual(t, self.set) + t &= t + self.assertEqual(t, self.set) + t -= t + self.assertEqual(len(t), 0) + t = self.set.copy() + t ^= t + self.assertEqual(len(t), 0) + + #============================================================================== class TestUpdateOps(unittest.TestCase): From rhettinger at users.sourceforge.net Sat Aug 13 04:29:03 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 04:29:03 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.71, 1.1193.2.72 Message-ID: <20050813022903.9FB391E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3812/Misc Modified Files: Tag: release24-maint NEWS Log Message: Teach set modules to correctly compute s-=s and s^=s as the empty set. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.71 retrieving revision 1.1193.2.72 diff -u -d -r1.1193.2.71 -r1.1193.2.72 --- NEWS 12 Aug 2005 23:47:50 -0000 1.1193.2.71 +++ NEWS 13 Aug 2005 02:28:54 -0000 1.1193.2.72 @@ -17,6 +17,8 @@ __hash__() function. Also, changed set.__contains__() to have identical logic. +- The set() builtin can now properly compute s-=s as an empty set. + - SF bug #1238681: freed pointer is used in longobject.c:long_pow(). - SF bug #1185883: Python's small-object memory allocator took over @@ -58,6 +60,8 @@ Library ------- +- The sets module can now properly compute s-=s and s^=s as an empty set. + - Patch #827386: Support absolute source paths in msvccompiler.py. - Fix a problem in Tkinter introduced by SF patch #869468: delete bogus From rhettinger at users.sourceforge.net Sat Aug 13 04:29:03 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 04:29:03 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c, 1.31.2.2, 1.31.2.3 Message-ID: <20050813022903.A0B1A1E4007@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3812/Objects Modified Files: Tag: release24-maint setobject.c Log Message: Teach set modules to correctly compute s-=s and s^=s as the empty set. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.31.2.2 retrieving revision 1.31.2.3 diff -u -d -r1.31.2.2 -r1.31.2.3 --- setobject.c 12 Aug 2005 23:47:50 -0000 1.31.2.2 +++ setobject.c 13 Aug 2005 02:28:54 -0000 1.31.2.3 @@ -193,6 +193,16 @@ PyDoc_STRVAR(copy_doc, "Return a shallow copy of a set."); static PyObject * +set_clear(PySetObject *so) +{ + PyDict_Clear(so->data); + so->hash = -1; + Py_RETURN_NONE; +} + +PyDoc_STRVAR(clear_doc, "Remove all elements from this set."); + +static PyObject * set_union(PySetObject *so, PyObject *other) { PySetObject *result; @@ -379,6 +389,9 @@ set_difference_update(PySetObject *so, PyObject *other) { PyObject *item, *tgtdata, *it; + + if ((PyObject *)so == other) + return set_clear(so); it = PyObject_GetIter(other); if (it == NULL) @@ -758,16 +771,6 @@ return 0; } -static PyObject * -set_clear(PySetObject *so) -{ - PyDict_Clear(so->data); - so->hash = -1; - Py_RETURN_NONE; -} - -PyDoc_STRVAR(clear_doc, "Remove all elements from this set."); - static int set_tp_clear(PySetObject *so) { From rhettinger at users.sourceforge.net Sat Aug 13 04:30:07 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 04:30:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_sets.py,1.31,1.32 Message-ID: <20050813023007.B29A41E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3974/Lib/test Modified Files: test_sets.py Log Message: Teach the sets module to correctly compute s-=s and s^=s as the empty set. Index: test_sets.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_sets.py,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- test_sets.py 7 Aug 2004 06:15:12 -0000 1.31 +++ test_sets.py 13 Aug 2005 02:29:58 -0000 1.32 @@ -243,6 +243,19 @@ self.assertRaises(TypeError, cmp, a, 12) self.assertRaises(TypeError, cmp, "abc", a) + def test_inplace_on_self(self): + t = self.set.copy() + t |= t + self.assertEqual(t, self.set) + t &= t + self.assertEqual(t, self.set) + t -= t + self.assertEqual(len(t), 0) + t = self.set.copy() + t ^= t + self.assertEqual(len(t), 0) + + #============================================================================== class TestUpdateOps(unittest.TestCase): From rhettinger at users.sourceforge.net Sat Aug 13 04:30:07 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 04:30:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib sets.py,1.49,1.50 Message-ID: <20050813023007.012601E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3974/Lib Modified Files: sets.py Log Message: Teach the sets module to correctly compute s-=s and s^=s as the empty set. Index: sets.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/sets.py,v retrieving revision 1.49 retrieving revision 1.50 diff -u -d -r1.49 -r1.50 --- sets.py 19 Nov 2003 15:52:14 -0000 1.49 +++ sets.py 13 Aug 2005 02:29:58 -0000 1.50 @@ -480,6 +480,8 @@ value = True if not isinstance(other, BaseSet): other = Set(other) + if self is other: + self.clear() for elt in other: if elt in data: del data[elt] @@ -497,6 +499,8 @@ data = self._data if not isinstance(other, BaseSet): other = Set(other) + if self is other: + self.clear() for elt in ifilter(data.has_key, other): del data[elt] From pje at users.sourceforge.net Sat Aug 13 05:29:09 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sat, 13 Aug 2005 05:29:09 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects genobject.c,1.5,1.6 Message-ID: <20050813032909.CF8281E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12609/Objects Modified Files: genobject.c Log Message: Fix a too-aggressive assert (see SF#1257960). Previously, gen_iternext was never called during interpreter shutdown GC, so the f_back!=NULL assertion was correct. Now that generators get close()d during GC, the assertion was being triggered because the generator close() was being called as the top-level frame. However, nothing actually is broken by this; it's just that the condition was unexpected in previous Python versions. Index: genobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/genobject.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- genobject.c 2 Aug 2005 00:46:45 -0000 1.5 +++ genobject.c 13 Aug 2005 03:29:00 -0000 1.6 @@ -82,7 +82,7 @@ /* Don't keep the reference to f_back any longer than necessary. It * may keep a chain of frames alive or it could create a reference * cycle. */ - assert(f->f_back != NULL); + assert(f->f_back == tstate->frame); Py_CLEAR(f->f_back); /* If the generator just returned (as opposed to yielding), signal From rhettinger at users.sourceforge.net Sat Aug 13 10:28:14 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 10:28:14 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.47,1.48 Message-ID: <20050813082814.0BF021E4007@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19968 Modified Files: setobject.c Log Message: * Bring lookkey() and lookkey_string() closer to dict version. * Use set_next() for looping in issubset() and frozenset_hash(). * Re-order the presentation of cmp and hash functions. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.47 retrieving revision 1.48 diff -u -d -r1.47 -r1.48 --- setobject.c 12 Aug 2005 20:48:39 -0000 1.47 +++ setobject.c 13 Aug 2005 08:28:03 -0000 1.48 @@ -61,6 +61,7 @@ setentry *table = so->table; register setentry *entry; register int restore_error; + register int checked_error; register int cmp; PyObject *err_type, *err_value, *err_tb; PyObject *startkey; @@ -70,11 +71,13 @@ if (entry->key == NULL || entry->key == key) return entry; - restore_error = 0; + restore_error = checked_error = 0; if (entry->key == dummy) freeslot = entry; else { if (entry->hash == hash) { + /* error can't have been checked yet */ + checked_error = 1; if (_PyErr_OCCURRED()) { restore_error = 1; PyErr_Fetch(&err_type, &err_value, &err_tb); @@ -111,10 +114,13 @@ if (entry->key == key) break; if (entry->hash == hash && entry->key != dummy) { - if (_PyErr_OCCURRED()) { - restore_error = 1; - PyErr_Fetch(&err_type, &err_value, - &err_tb); + if (!checked_error) { + checked_error = 1; + if (_PyErr_OCCURRED()) { + restore_error = 1; + PyErr_Fetch(&err_type, &err_value, + &err_tb); + } } startkey = entry->key; cmp = PyObject_RichCompareBool(startkey, key, Py_EQ); @@ -174,44 +180,28 @@ entry = &table[i]; if (entry->key == NULL || entry->key == key) return entry; - if (so->fill != so->used) { - if (entry->key == dummy) - freeslot = entry; - else { - if (entry->hash == hash && _PyString_Eq(entry->key, key)) - return entry; - freeslot = NULL; - } - - /* In the loop, key == dummy is by far (factor of 100s) the - least likely outcome, so test for that last. */ - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { - i = (i << 2) + i + perturb + 1; - entry = &table[i & mask]; - if (entry->key == NULL) - return freeslot == NULL ? entry : freeslot; - if (entry->key == key - || (entry->hash == hash - && entry->key != dummy - && _PyString_Eq(entry->key, key))) - return entry; - if (entry->key == dummy && freeslot == NULL) - freeslot = entry; - } - } else { - /* Simplified loop when there are no dummy entries. */ + if (entry->key == dummy) + freeslot = entry; + else { if (entry->hash == hash && _PyString_Eq(entry->key, key)) return entry; - for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { - i = (i << 2) + i + perturb + 1; - entry = &table[i & mask]; - if (entry->key == NULL) - return entry; - if (entry->key == key - || (entry->hash == hash - && _PyString_Eq(entry->key, key))) - return entry; - } + freeslot = NULL; + } + + /* In the loop, key == dummy is by far (factor of 100s) the + least likely outcome, so test for that last. */ + for (perturb = hash; ; perturb >>= PERTURB_SHIFT) { + i = (i << 2) + i + perturb + 1; + entry = &table[i & mask]; + if (entry->key == NULL) + return freeslot == NULL ? entry : freeslot; + if (entry->key == key + || (entry->hash == hash + && entry->key != dummy + && _PyString_Eq(entry->key, key))) + return entry; + if (entry->key == dummy && freeslot == NULL) + freeslot = entry; } } @@ -1369,11 +1359,11 @@ static PyObject * set_issubset(PySetObject *so, PyObject *other) { - PyObject *tmp, *result; - register setentry *entry; - register int i; + setentry *entry; + int pos = 0; if (!PyAnySet_Check(other)) { + PyObject *tmp, *result; tmp = make_new_set(&PySet_Type, other); if (tmp == NULL) return NULL; @@ -1384,10 +1374,7 @@ if (set_len((PyObject *)so) > set_len(other)) Py_RETURN_FALSE; - entry = &so->table[0]; - for (i=so->used ; i ; entry++, i--) { - while (entry->key == NULL || entry->key==dummy) - entry++; + while (set_next(so, &pos, &entry)) { if (!set_contains_entry((PySetObject *)other, entry)) Py_RETURN_FALSE; } @@ -1414,51 +1401,6 @@ PyDoc_STRVAR(issuperset_doc, "Report whether this set contains another set."); -static long -set_nohash(PyObject *self) -{ - PyErr_SetString(PyExc_TypeError, "set objects are unhashable"); - return -1; -} - -static int -set_nocmp(PyObject *self) -{ - PyErr_SetString(PyExc_TypeError, "cannot compare sets using cmp()"); - return -1; -} - -static long -frozenset_hash(PyObject *self) -{ - PySetObject *so = (PySetObject *)self; - long h, hash = 1927868237L; - setentry *entry; - int i; - - if (so->hash != -1) - return so->hash; - - hash *= set_len(self) + 1; - entry = &so->table[0]; - for (i=so->used ; i ; entry++, i--) { - while (entry->key == NULL || entry->key==dummy) - entry++; - /* Work to increase the bit dispersion for closely spaced hash - values. The is important because some use cases have many - combinations of a small number of elements with nearby - hashes so that many distinct combinations collapse to only - a handful of distinct hash values. */ - h = entry->hash; - hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u; - } - hash = hash * 69069L + 907133923L; - if (hash == -1) - hash = 590923713L; - so->hash = hash; - return hash; -} - static PyObject * set_richcompare(PySetObject *v, PyObject *w, int op) { @@ -1502,6 +1444,48 @@ return Py_NotImplemented; } +static int +set_nocmp(PyObject *self) +{ + PyErr_SetString(PyExc_TypeError, "cannot compare sets using cmp()"); + return -1; +} + +static long +frozenset_hash(PyObject *self) +{ + PySetObject *so = (PySetObject *)self; + long h, hash = 1927868237L; + setentry *entry; + int pos = 0; + + if (so->hash != -1) + return so->hash; + + hash *= set_len(self) + 1; + while (set_next(so, &pos, &entry)) { + /* Work to increase the bit dispersion for closely spaced hash + values. The is important because some use cases have many + combinations of a small number of elements with nearby + hashes so that many distinct combinations collapse to only + a handful of distinct hash values. */ + h = entry->hash; + hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u; + } + hash = hash * 69069L + 907133923L; + if (hash == -1) + hash = 590923713L; + so->hash = hash; + return hash; +} + +static long +set_nohash(PyObject *self) +{ + PyErr_SetString(PyExc_TypeError, "set objects are unhashable"); + return -1; +} + static PyObject * set_repr(PySetObject *so) { From birkenfeld at users.sourceforge.net Sat Aug 13 11:06:33 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sat, 13 Aug 2005 11:06:33 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_doctest.py, 1.52, 1.52.2.1 Message-ID: <20050813090633.D6F371E4007@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26252/Lib/test Modified Files: Tag: release24-maint test_doctest.py Log Message: Complete backport of #1172785 fix. Index: test_doctest.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_doctest.py,v retrieving revision 1.52 retrieving revision 1.52.2.1 diff -u -d -r1.52 -r1.52.2.1 --- test_doctest.py 8 Nov 2004 22:07:36 -0000 1.52 +++ test_doctest.py 13 Aug 2005 09:06:24 -0000 1.52.2.1 @@ -1517,6 +1517,7 @@ ## 44 # # Yee ha! + >>> name = 'test.test_doctest.SampleNewStyleClass' >>> print doctest.testsource(test.test_doctest, name) @@ -1525,6 +1526,7 @@ ## 1 ## 2 ## 3 + >>> name = 'test.test_doctest.SampleClass.a_classmethod' >>> print doctest.testsource(test.test_doctest, name) @@ -1534,6 +1536,7 @@ print SampleClass(0).a_classmethod(10) # Expected: ## 12 + """ def test_debug(): r""" From birkenfeld at users.sourceforge.net Sat Aug 13 11:06:33 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sat, 13 Aug 2005 11:06:33 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib doctest.py, 1.120.2.2, 1.120.2.3 Message-ID: <20050813090633.E1B351E4009@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26252/Lib Modified Files: Tag: release24-maint doctest.py Log Message: Complete backport of #1172785 fix. Index: doctest.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/doctest.py,v retrieving revision 1.120.2.2 retrieving revision 1.120.2.3 diff -u -d -r1.120.2.2 -r1.120.2.3 --- doctest.py 26 Jun 2005 22:23:44 -0000 1.120.2.2 +++ doctest.py 13 Aug 2005 09:06:24 -0000 1.120.2.3 @@ -2472,6 +2472,7 @@ blah # # Ho hum + """ output = [] for piece in DocTestParser().parse(s): From rhettinger at users.sourceforge.net Sat Aug 13 11:28:58 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sat, 13 Aug 2005 11:28:58 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.48,1.49 Message-ID: <20050813092858.123931E4009@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29128 Modified Files: setobject.c Log Message: More function re-ordering (placing like functions together). Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.48 retrieving revision 1.49 diff -u -d -r1.48 -r1.49 --- setobject.c 13 Aug 2005 08:28:03 -0000 1.48 +++ setobject.c 13 Aug 2005 09:28:48 -0000 1.49 @@ -566,6 +566,57 @@ return key != NULL && key != dummy; } +static PyObject * +set_pop(PySetObject *so) +{ + PyObject *key; + register setentry *entry; + register int i = 0; + + assert (PyAnySet_Check(so)); + if (so->used == 0) { + PyErr_SetString(PyExc_KeyError, "pop from an empty set"); + return NULL; + } + + /* Set entry to "the first" unused or dummy set entry. We abuse + * the hash field of slot 0 to hold a search finger: + * If slot 0 has a value, use slot 0. + * Else slot 0 is being used to hold a search finger, + * and we use its hash value as the first index to look. + */ + entry = &so->table[0]; + if (entry->key == NULL || entry->key == dummy) { + i = (int)entry->hash; + /* The hash field may be a real hash value, or it may be a + * legit search finger, or it may be a once-legit search + * finger that's out of bounds now because it wrapped around + * or the table shrunk -- simply make sure it's in bounds now. + */ + if (i > so->mask || i < 1) + i = 1; /* skip slot 0 */ + while ((entry = &so->table[i])->key == NULL || entry->key==dummy) { + i++; + if (i > so->mask) + i = 1; + } + } + key = entry->key; + Py_INCREF(dummy); + entry->key = dummy; + so->used--; + so->table[0].hash = i + 1; /* next place to start */ + return key; +} + +PyDoc_STRVAR(pop_doc, "Remove and return an arbitrary set element."); + +static int +set_len(PyObject *so) +{ + return ((PySetObject *)so)->used; +} + /***** Set iterator type ***********************************************/ static PyTypeObject PySetIter_Type; /* Forward */ @@ -683,12 +734,6 @@ }; static int -set_len(PyObject *so) -{ - return ((PySetObject *)so)->used; -} - -static int set_update_internal(PySetObject *so, PyObject *other) { PyObject *key, *it; @@ -918,41 +963,6 @@ } } -static int -set_contains(PySetObject *so, PyObject *key) -{ - PyObject *tmpkey; - int rv; - - rv = set_contains_key(so, key); - if (rv == -1) { - if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) - return -1; - PyErr_Clear(); - tmpkey = make_new_set(&PyFrozenSet_Type, NULL); - if (tmpkey == NULL) - return -1; - set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - rv = set_contains(so, tmpkey); - set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); - Py_DECREF(tmpkey); - } - return rv; -} - -static PyObject * -set_direct_contains(PySetObject *so, PyObject *key) -{ - long result; - - result = set_contains(so, key); - if (result == -1) - return NULL; - return PyBool_FromLong(result); -} - -PyDoc_STRVAR(contains_doc, "x.__contains__(y) <==> y in x."); - static PyObject * set_copy(PySetObject *so) { @@ -1537,6 +1547,41 @@ \n\ This has no effect if the element is already present."); +static int +set_contains(PySetObject *so, PyObject *key) +{ + PyObject *tmpkey; + int rv; + + rv = set_contains_key(so, key); + if (rv == -1) { + if (!PyAnySet_Check(key) || !PyErr_ExceptionMatches(PyExc_TypeError)) + return -1; + PyErr_Clear(); + tmpkey = make_new_set(&PyFrozenSet_Type, NULL); + if (tmpkey == NULL) + return -1; + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); + rv = set_contains(so, tmpkey); + set_swap_bodies((PySetObject *)tmpkey, (PySetObject *)key); + Py_DECREF(tmpkey); + } + return rv; +} + +static PyObject * +set_direct_contains(PySetObject *so, PyObject *key) +{ + long result; + + result = set_contains(so, key); + if (result == -1) + return NULL; + return PyBool_FromLong(result); +} + +PyDoc_STRVAR(contains_doc, "x.__contains__(y) <==> y in x."); + static PyObject * set_remove(PySetObject *so, PyObject *key) { @@ -1597,51 +1642,6 @@ If the element is not a member, do nothing."); static PyObject * -set_pop(PySetObject *so) -{ - PyObject *key; - register setentry *entry; - register int i = 0; - - assert (PyAnySet_Check(so)); - if (so->used == 0) { - PyErr_SetString(PyExc_KeyError, "pop from an empty set"); - return NULL; - } - - /* Set entry to "the first" unused or dummy set entry. We abuse - * the hash field of slot 0 to hold a search finger: - * If slot 0 has a value, use slot 0. - * Else slot 0 is being used to hold a search finger, - * and we use its hash value as the first index to look. - */ - entry = &so->table[0]; - if (entry->key == NULL || entry->key == dummy) { - i = (int)entry->hash; - /* The hash field may be a real hash value, or it may be a - * legit search finger, or it may be a once-legit search - * finger that's out of bounds now because it wrapped around - * or the table shrunk -- simply make sure it's in bounds now. - */ - if (i > so->mask || i < 1) - i = 1; /* skip slot 0 */ - while ((entry = &so->table[i])->key == NULL || entry->key==dummy) { - i++; - if (i > so->mask) - i = 1; - } - } - key = entry->key; - Py_INCREF(dummy); - entry->key = dummy; - so->used--; - so->table[0].hash = i + 1; /* next place to start */ - return key; -} - -PyDoc_STRVAR(pop_doc, "Remove and return an arbitrary set element."); - -static PyObject * set_reduce(PySetObject *so) { PyObject *keys=NULL, *args=NULL, *result=NULL, *dict=NULL; From goodger at users.sourceforge.net Sat Aug 13 14:38:03 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sat, 13 Aug 2005 14:38:03 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0006.txt, 1.11, 1.12 pep-0000.txt, 1.340, 1.341 Message-ID: <20050813123803.9BA921E4007@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25234 Modified Files: pep-0006.txt pep-0000.txt Log Message: changed PEP 6 type to Process Index: pep-0006.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0006.txt,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- pep-0006.txt 19 Aug 2004 07:06:12 -0000 1.11 +++ pep-0006.txt 13 Aug 2005 12:37:53 -0000 1.12 @@ -3,7 +3,7 @@ Version: $Revision$ Author: aahz at pobox.com (Aahz), anthony at interlink.com.au (Anthony Baxter) Status: Active -Type: Informational +Type: Process Created: 15-Mar-2001 Post-History: 15-Mar-2001 18-Apr-2001 19-Aug-2004 @@ -55,6 +55,7 @@ Breaking any of these prohibitions requires a BDFL proclamation (and a prominent warning in the release notes). + Not-Quite-Prohibitions Where possible, bug fix releases should also: @@ -69,6 +70,7 @@ the standard library should not change behavior, or worse yet, APIs. + Applicability of Prohibitions The above prohibitions and not-quite-prohibitions apply both @@ -80,6 +82,7 @@ the community happy that a bug fix release is a painless and safe upgrade. + Helping the Bug Fix Releases Happen Here's a few pointers on helping the bug fix release process along. @@ -98,6 +101,7 @@ wait until 48 hours before a bug fix release is due, and then start asking for bug fixes to be included. + Version Numbers Starting with Python 2.0, all major releases are required to have @@ -111,10 +115,11 @@ the branch is named 'release2x-maint'. For example, the branch for the 2.3 maintenance releases is release23-maint + Procedure - The process for managing bugfix releases is modeled in part on the Tcl - system [1]. + The process for managing bugfix releases is modeled in part on the + Tcl system [1]. The Patch Czar is the counterpart to the BDFL for bugfix releases. However, the BDFL and designated appointees retain veto power over @@ -151,6 +156,7 @@ bugfix releases. If, however, someone qualified wishes to continue the work to maintain an older release, they should be encouraged. + Patch Czar History Anthony Baxter is the Patch Czar for 2.3.1 through 2.3.4. @@ -190,6 +196,7 @@ Anthony Baxter then took this PEP and revised it, based on lessons from the 2.3 release cycle. + References [1] http://www.tcl.tk/cgi-bin/tct/tip/28.html Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.340 retrieving revision 1.341 diff -u -d -r1.340 -r1.341 --- pep-0000.txt 13 Aug 2005 01:37:32 -0000 1.340 +++ pep-0000.txt 13 Aug 2005 12:37:53 -0000 1.341 @@ -35,7 +35,7 @@ I 3 Guidelines for Handling Bug Reports Hylton I 4 Deprecation of Standard Modules von Loewis I 5 Guidelines for Language Evolution Prescod - I 6 Bug Fix Releases Aahz + P 6 Bug Fix Releases Aahz I 7 Style Guide for C Code GvR I 8 Style Guide for Python Code GvR, Warsaw I 9 Sample Plaintext PEP Template Warsaw @@ -230,7 +230,7 @@ I 3 Guidelines for Handling Bug Reports Hylton I 4 Deprecation of Standard Modules von Loewis I 5 Guidelines for Language Evolution Prescod - I 6 Bug Fix Releases Aahz + P 6 Bug Fix Releases Aahz I 7 Style Guide for C Code GvR I 8 Style Guide for Python Code GvR, Warsaw I 9 Sample Plaintext PEP Template Warsaw From goodger at users.sourceforge.net Sat Aug 13 20:01:14 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sat, 13 Aug 2005 20:01:14 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0001.txt,1.47,1.48 Message-ID: <20050813180114.4A9BD1E4009@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23663 Modified Files: pep-0001.txt Log Message: Process PEPs may also be Active Index: pep-0001.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0001.txt,v retrieving revision 1.47 retrieving revision 1.48 diff -u -d -r1.47 -r1.48 --- pep-0001.txt 13 Aug 2005 01:42:17 -0000 1.47 +++ pep-0001.txt 13 Aug 2005 18:01:01 -0000 1.48 @@ -164,8 +164,8 @@ .. image:: pep-0001-1.png -Some Informational PEPs may also have a status of "Active" if they are -never meant to be completed. E.g. PEP 1 (this PEP). +Some Informational and Process PEPs may also have a status of "Active" +if they are never meant to be completed. E.g. PEP 1 (this PEP). What belongs in a successful PEP? From gregorykjohnson at users.sourceforge.net Sun Aug 14 00:41:45 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Sun, 14 Aug 2005 00:41:45 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox libmailbox.tex, 1.8, 1.9 mailbox.py, 1.7, 1.8 test_mailbox.py, 1.6, 1.7 Message-ID: <20050813224145.6EA9D1E4012@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10815 Modified Files: libmailbox.tex mailbox.py test_mailbox.py Log Message: * Regularize list_, get_, set_, add_, remove_, join_, and leave_ names: * Maildir and MH: keep list_folders(), change open_folder() to get_folder(), introduce add_folder, and keep remove_folder(). * Babyl: change list_labels() to get_labels(). * MaildirMessage, mboxMessage, and MMDFMessage: keep get_flags() and set_flags(), change add_flags() to add_flag(), and change remove_flags() to remove_flag(). * MHMessage: change list_sequences() to get_sequences(), introduce set_sequences(), change join_sequence() to add_sequence(), and change leave_sequence() to remove_sequence() * BabylMessage: change list_labels() to get_labels(), introduce set_labels(), and keep add_label() and remove_label() * At the suggestion of A.M. Kuchling: * Avoid os.mknod(), for MacOS compatibility. * Introduce create=True parameter for Mailbox constructors. * Prefer iteritems() to items() in Mailbox.update(). * Use fcntl=None to avoid checking globals(). * Use os.path.dirname() instead of os.path.split()[0]. * Use "':' in x" instead of "x.index(':') != -1". * Use os.path.getatime() instead of os.stat().st_atime. * Remove module-level open() function, which clutters the API. Its original motivation was to regularize Mailbox constructors while keep backward compatability, but all Mailbox classes have been renamed and regularized except Maildir, which is already extremely similar. * Introduce subclasses of Error: NoSuchMailboxError, NotEmptyError, ExternalClashError, FormatError. Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- libmailbox.tex 5 Aug 2005 16:34:45 -0000 1.8 +++ libmailbox.tex 13 Aug 2005 22:41:33 -0000 1.9 @@ -75,33 +75,7 @@ \class{Mailbox} itself is intended to define an interface and to be inherited from by format-specific subclasses but is not intended to be instantiated. -Instead, you may directly instantiate a subclass or use the module-level -\function{open()} function to do so. - -\begin{funcdesc}{open}{path\optional{, format\optional{, factory}}} -Instantiate and return an instance of the appropriate \class{Mailbox} subclass -for the mailbox at \var{path}. The mailbox is created if it does not already -exist. - -If \var{format} is specified, it should be one of "Maildir", "mbox", "MH", -"Babyl", or "MMDF" (case insensitive). If \var{format} is not specified, then -the format of the mailbox is automatically detected. Automatic detection -involves inspecting the mailbox at \var{path} if such a mailbox exists or if -no such mailbox exists inspecting \var{path} itself and assuming Maildir -format if \var{path} ends with the system's path separator (e.g., "/" or -"\textbackslash") or mbox format otherwise. - -Parameter \var{factory} is a callable object that accepts a file-like object -containing a raw message as its parameter and returns a message -representation. If \var{factory} is not specified, \class{Message} instances -are used to represent messages. - -For historical reasons, some subclasses of \class{Mailbox} take instantiation -arguments with different purposes, names, or default values. The -\function{open()} function is intended to present a convenient, uniform -interface for \class{Mailbox} instantiation while maintaining backward -compatibility. -\end{funcdesc} +Instead, directly instantiate a subclass. \class{Mailbox} instances have the following methods: @@ -256,11 +230,17 @@ \subsubsection{\class{Maildir}} \label{mailbox-maildir} -\begin{classdesc}{Maildir}{dirname\optional{, factory}} +\begin{classdesc}{Maildir}{dirname\optional{, factory=rfc822.Message\optional{, +create=True}}} A subclass of \class{Mailbox} for mailboxes in Maildir format. Parameter -\var{dirname} is the path to the mailbox. Parameter \var{factory} has the same -meaning as with the module-level \method{open()} function. For historical -reasons, \var{factory} defaults to \class{rfc822.Message}. +\var{factory} is a callable object that accepts a file-like object containing a +raw message as its parameter and returns a message representation. If +\var{factory} is \code{None}, \class{MaildirMessage} instances are used. +If \var{create} is \code{True}, the mailbox is created if it does not exist. + +It is for historical reasons that \var{factory} defaults to +\class{rfc822.Message} and that \var{dirname} is named as such rather than +\var{path}. \end{classdesc} Maildir is a directory-based mailbox format invented for the qmail MTA and now @@ -270,28 +250,35 @@ without data corruption, so file locking is unnecessary. Folders, as introduced by the Courier MTA, are supported. Each folder is -itself a Maildir mailbox and is represented as a \class{Maildir} instance. Any -subdirectory of the main Maildir directory is considered a folder if -\character{.} is the first character in its name. Folder names are represented -without the leading dot. For example, "Sent.2005.07" would be the name of a -folder implemented with a directory called ".Sent.2005.07" on the filesystem. +itself a Maildir mailbox. Any subdirectory of the main Maildir directory is +considered a folder if \character{.} is the first character in its name. Folder +names are represented without the leading dot. For example, "Sent" would be the +name of a folder implemented with a directory called ".Sent" on the filesystem. +Folders should not be nested, i.e., a Maildir mailbox that is itself a folder +should not contain other folders. Instead, logical nesting may be indicated +using \character{.} to delimit levels---for example, "Archived.2005.07". \class{Maildir} instances have all of the methods of \class{Mailbox} in addition to the following: \begin{methoddesc}{list_folders}{} -Return a list of the names of all folders. If there are no folders, the empty -list is returned. +Return a list of the names of all folders. \end{methoddesc} -\begin{methoddesc}{open_folder}{name} +\begin{methoddesc}{get_folder}{folder} Return a \class{Maildir} instance representing the folder whose name is -\var{name}. The folder will be created if it does not exist. +\var{folder}. A \exception{NoSuchMailboxError} exception is raised if the +folder does not exist. \end{methoddesc} -\begin{methoddesc}{remove_folder}{name} -Delete the folder whose name is \var{name}. If the folder contains any -messages, a \exception{mailbox.Error} exception will be raised and the folder +\begin{methoddesc}{add_folder}{folder} +Create a folder whose name is \var{folder} and return a \class{Maildir} +instance representing it. +\end{methoddesc} + +\begin{methoddesc}{remove_folder}{folder} +Delete the folder whose name is \var{folder}. If the folder contains any +messages, a \exception{NotEmptyError} exception will be raised and the folder will not be deleted. \end{methoddesc} @@ -301,13 +288,6 @@ should do this occassionally. \end{methoddesc} -\warning{Three \class{Maildir} methods---\method{add()}, -\method{__setitem__()}, and \method{update()}---generate unique file names -based upon the current process ID. When using multiple threads, undetected -clashes may occur and cause corruption of the mailbox unless threads are -coordinated to avoid using these methods to manipulate the same mailbox -simultaneously.} - Some \class{Mailbox} methods implemented by \class{Maildir} deserve special remarks: @@ -350,10 +330,12 @@ \subsubsection{\class{mbox}} \label{mailbox-mbox} -\begin{classdesc}{mbox}{path\optional{, factory}} -A subclass of \class{Mailbox} for mailboxes in mbox format. Parameters -\var{path} and \var{factory} has the same meaning as with the module-level -\method{open()} function. +\begin{classdesc}{mbox}{path\optional{, factory=None\optional{, create=True}}} +A subclass of \class{Mailbox} for mailboxes in mbox format. Parameter +\var{factory} is a callable object that accepts a file-like object containing a +raw message as its parameter and returns a message representation. If +\var{factory} is \code{None}, \class{mboxMessage} instances are used. If +\var{create} is \code{True}, the mailbox is created if it does not exist. \end{classdesc} The mbox format is the classic format for storing mail on \UNIX{} systems. All @@ -392,10 +374,12 @@ \subsubsection{\class{MH}} \label{mailbox-mh} -\begin{classdesc}{MH}{path\optional{, factory}} -A subclass of \class{Mailbox} for mailboxes in MH format. Parameters \var{path} -and \var{factory} has the same meaning as with the module-level \method{open()} -function. +\begin{classdesc}{MH}{path\optional{, factory=None\optional{, create=True}}} +A subclass of \class{Mailbox} for mailboxes in MH format. Parameter +\var{factory} is a callable object that accepts a file-like object containing a +raw message as its parameter and returns a message representation. If +\var{factory} is \code{None}, \class{MHMessage} instances are used. If +\var{create} is \code{True}, the mailbox is created if it does not exist. \end{classdesc} MH is a directory-based mailbox format invented for the MH Message Handling @@ -420,18 +404,23 @@ the following: \begin{methoddesc}{list_folders}{} -Return a list of the names of all folders. If there are no folders, the empty -list is returned. +Return a list of the names of all folders. \end{methoddesc} -\begin{methoddesc}{open_folder}{name} -Return an \class{MH} instance representing the folder whose name is \var{name}. -The folder will be created if it does not exist. +\begin{methoddesc}{get_folder}{folder} +Return an \class{MH} instance representing the folder whose name is +\var{folder}. A \exception{NoSuchMailboxError} exception is raised if the +folder does not exist. \end{methoddesc} -\begin{methoddesc}{remove_folder}{name} -Delete the folder whose name is \var{name}. If the folder contains any -messages, a \exception{mailbox.Error} exception will be raised and the folder +\begin{methoddesc}{add_folder}{folder} +Create a folder whose name is \var{folder} and return an \class{MH} instance +representing it. +\end{methoddesc} + +\begin{methoddesc}{remove_folder}{folder} +Delete the folder whose name is \var{folder}. If the folder contains any +messages, a \exception{NotEmptyError} exception will be raised and the folder will not be deleted. \end{methoddesc} @@ -474,12 +463,6 @@ \class{MH} instances do not keep any open files, so this method does nothing. \end{methoddesc} -\begin{classdesc}{MH}{path\optional{, factory}} -A subclass of \class{Mailbox} for mailboxes in MH format. Parameters \var{path} -and \var{factory} have the same meaning as with the module-level -\method{open()} function. -\end{classdesc} - \class{MH} instances have all of the methods of \class{Mailbox} in addition to the following: @@ -493,17 +476,19 @@ \seelink{http://www.nongnu.org/nmh/}{nmh - Message Handling System}{Home page of \program{nmh}, a modern version of the original \program{mh}.} \seelink{http://www.ics.uci.edu/\tilde{}mh/book/}{MH \& nmh: Email for Users \& -Programmers}{An open-source book on \program{mh} and \program{nmh}, with some +Programmers}{A GPL-licensed book on \program{mh} and \program{nmh}, with some information on the mailbox format.} \end{seealso} \subsubsection{\class{Babyl}} \label{mailbox-babyl} -\begin{classdesc}{Babyl}{path\optional{, factory}} -A subclass of \class{Mailbox} for mailboxes in Babyl format. Parameters -\var{path} and \var{factory} have the same meaning as with the module-level -\method{open()} function. +\begin{classdesc}{Babyl}{path\optional{, factory=None\optional{, create=True}}} +A subclass of \class{Mailbox} for mailboxes in Babyl format. Parameter +\var{factory} is a callable object that accepts a file-like object containing a +raw message as its parameter and returns a message representation. If +\var{factory} is \code{None}, \class{BabylMessage} instances are used. If +\var{create} is \code{True}, the mailbox is created if it does not exist. \end{classdesc} Babyl is a single-file mailbox format invented for the \program{Rmail} mail @@ -522,8 +507,8 @@ \class{Babyl} instances have all of the methods of \class{Mailbox} in addition to the following: -\begin{methoddesc}{list_labels}{} -Return a list of all user-defined labels in the mailbox. +\begin{methoddesc}{get_labels}{} +Return a list of the names of all user-defined labels used in the mailbox. \end{methoddesc} Some \class{Mailbox} methods implemented by \class{Babyl} deserve special @@ -546,10 +531,12 @@ \subsubsection{\class{MMDF}} \label{mailbox-mmdf} -\begin{classdesc}{MMDF}{path\optional{, factory}} -A subclass of \class{Mailbox} for mailboxes in MMDF format. Parameters -\var{path} and \var{factory} have the same meaning as with the module-level -\method{open()} function. +\begin{classdesc}{MMDF}{path\optional{, factory=None\optional{, create=True}}} +A subclass of \class{Mailbox} for mailboxes in MMDF format. Parameter +\var{factory} is a callable object that accepts a file-like object containing a +raw message as its parameter and returns a message representation. If +\var{factory} is \code{None}, \class{MMDFMessage} instances are used. If +\var{create} is \code{True}, the mailbox is created if it does not exist. \end{classdesc} MMDF is a single-file mailbox format invented for the Multichannel Memorandum @@ -671,30 +658,22 @@ \end{methoddesc} \begin{methoddesc}{set_flags}{flags} -Set the flags specified by \var{flags} and unset all others. Parameter -\var{flags} should be the concatenation in any order of zero or more -occurrences of each of \character{D}, \character{F}, \character{P}, -\character{R}, \character{S}, and \character{T}. The current "info" is -overwritten whether or not it contains experimental information instead of -flags. +Set the flags specified by \var{flags} and unset all others. \end{methoddesc} -\begin{methoddesc}{add_flags}{flags} -Set the flags specified by \var{flags} (if they are not set), and don't change -other flags. Parameter \var{flags} should be the concatenation in any order of -zero or more occurrences of each of \character{D}, \character{F}, -\character{P}, \character{R}, \character{S}, and \character{T}. The current -"info" is overwritten whether or not it contains experimental information -instead of flags. +\begin{methoddesc}{add_flag}{flag} +Set the flag(s) specified by \var{flag} without changing other flags. To add +more than one flag at a time, \var{flag} may be a string of more than one +character. The current "info" is overwritten whether or not it contains +experimental information rather than +flags. \end{methoddesc} -\begin{methoddesc}{remove_flags}{flags} -Unset the flags specified by \var{flags} (if they are set), and don't change -other flags. Parameter \var{flags} should be the concatenation in any order of -zero or more occurrences of each of \character{D}, \character{F}, -\character{P}, \character{R}, \character{S}, and \character{T}. If "info" -contains experimental information rather than flags, the current "info" is not -modified. +\begin{methoddesc}{remove_flag}{flag} +Unset the flag(s) specified by \var{flag} without changing other flags. To +remove more than one flag at a time, \var{flag} maybe a string of more than one +character. If "info" contains experimental information rather than flags, the +current "info" is not modified. \end{methoddesc} \begin{methoddesc}{get_info}{} @@ -804,18 +783,16 @@ \character{F}, and \character{A}. \end{methoddesc} -\begin{methoddesc}{add_flags}{flags} -Set the flags specified by \var{flags} (if they are not set), and don't change -other flags. Parameter \var{flags} should be the concatenation in any order of -zero or more occurrences of each of \character{R}, \character{O}, -\character{D}, \character{F}, and \character{A}. +\begin{methoddesc}{add_flag}{flag} +Set the flag(s) specified by \var{flag} without changing other flags. To add +more than one flag at a time, \var{flag} may be a string of more than one +character. \end{methoddesc} -\begin{methoddesc}{remove_flags}{flags} -Unset the flags specified by \var{flags} (if they are set), and don't change -other flags. Parameter \var{flags} should be the concatenation in any order of -zero or more occurrences of each of \character{R}, \character{O}, -\character{D}, \character{F}, and \character{A}. +\begin{methoddesc}{remove_flag}{flag} +Unset the flag(s) specified by \var{flag} without changing other flags. To +remove more than one flag at a time, \var{flag} maybe a string of more than one +character. \end{methoddesc} When an \class{mboxMessage} instance is created based upon a @@ -888,16 +865,20 @@ \class{MHMessage} instances offer the following methods: -\begin{methoddesc}{list_sequences}{} -Return a list of the names of sequences that include the message. +\begin{methoddesc}{get_sequences}{} +Return a list of the names of sequences that include this message. \end{methoddesc} -\begin{methoddesc}{join_sequence}{sequence} -Add \var{sequence} to the list of sequences that include the message. +\begin{methoddesc}{set_sequences}{sequences} +Set the list of sequences that include this message. \end{methoddesc} -\begin{methoddesc}{leave_sequence}{sequence} -Remove \var{sequence} from the list of sequences that include the message. +\begin{methoddesc}{add_sequence}{sequence} +Add \var{sequence} to the list of sequences that include this message. +\end{methoddesc} + +\begin{methoddesc}{remove_sequence}{sequence} +Remove \var{sequence} from the list of sequences that include this message. \end{methoddesc} When an \class{MHMessage} instance is created based upon a @@ -963,10 +944,14 @@ \class{BabylMessage} instances offer the following methods: -\begin{methoddesc}{list_labels}{} +\begin{methoddesc}{get_labels}{} Return a list of labels on the message. \end{methoddesc} +\begin{methoddesc}{set_labels}{labels} +Set the list of labels on the message to \var{labels}. +\end{methoddesc} + \begin{methoddesc}{add_label}{label} Add \var{label} to the list of labels on the message. \end{methoddesc} @@ -1088,18 +1073,16 @@ \character{F}, and \character{A}. \end{methoddesc} -\begin{methoddesc}{add_flags}{flags} -Set the flags specified by \var{flags} (if they are not set), and don't change -other flags. Parameter \var{flags} should be the concatenation in any order of -zero or more occurrences of each of \character{R}, \character{O}, -\character{D}, \character{F}, and \character{A}. +\begin{methoddesc}{add_flag}{flag} +Set the flag(s) specified by \var{flag} without changing other flags. To add +more than one flag at a time, \var{flag} may be a string of more than one +character. \end{methoddesc} -\begin{methoddesc}{remove_flags}{flags} -Unset the flags specified by \var{flags} (if they are set), and don't change -other flags. Parameter \var{flags} should be the concatenation in any order of -zero or more occurrences of each of \character{R}, \character{O}, -\character{D}, \character{F}, and \character{A}. +\begin{methoddesc}{remove_flag}{flag} +Unset the flag(s) specified by \var{flag} without changing other flags. To +remove more than one flag at a time, \var{flag} maybe a string of more than one +character. \end{methoddesc} When an \class{MMDFMessage} instance is created based upon a Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- mailbox.py 5 Aug 2005 16:34:45 -0000 1.7 +++ mailbox.py 13 Aug 2005 22:41:33 -0000 1.8 @@ -16,21 +16,17 @@ try: import fnctl except ImportError: - pass + fcntl = None -__all__ = [ 'open', 'Mailbox', 'Maildir', 'mbox', 'MH', 'Babyl', 'MMDF', +__all__ = [ 'Mailbox', 'Maildir', 'mbox', 'MH', 'Babyl', 'MMDF', 'Message', 'MaildirMessage', 'mboxMessage', 'MHMessage', 'BabylMessage', 'MMDFMessage' ] -def open(path, format=None, factory=None): - """Open a mailbox at the given path and return a Mailbox instance.""" - - class Mailbox: """A group of messages in a particular place.""" - def __init__(self, path, factory=None): + def __init__(self, path, factory=None, create=True): """Initialize a Mailbox instance.""" self._path = os.path.abspath(path) self._factory = factory @@ -154,7 +150,9 @@ def update(self, arg=None): """Change the messages that correspond to certain keys.""" - if hasattr(arg, 'items'): + if hasattr(arg, 'iteritems'): + source = arg.iteritems() + elif hasattr(arg, 'items'): source = arg.items() else: source = arg @@ -195,14 +193,17 @@ class Maildir(Mailbox): """A qmail-style Maildir mailbox.""" - def __init__(self, dirname, factory=rfc822.Message): + def __init__(self, dirname, factory=rfc822.Message, create=True): """Initialize a Maildir instance.""" - Mailbox.__init__(self, dirname, factory) + Mailbox.__init__(self, dirname, factory, create) if not os.path.exists(self._path): - os.mkdir(self._path, 0700) - os.mkdir(os.path.join(self._path, 'tmp'), 0700) - os.mkdir(os.path.join(self._path, 'new'), 0700) - os.mkdir(os.path.join(self._path, 'cur'), 0700) + if create: + os.mkdir(self._path, 0700) + os.mkdir(os.path.join(self._path, 'tmp'), 0700) + os.mkdir(os.path.join(self._path, 'new'), 0700) + os.mkdir(os.path.join(self._path, 'cur'), 0700) + else: + raise NoSuchMailboxError, self._path self._toc = {} def add(self, message): @@ -253,8 +254,8 @@ else: # temp's subdir and suffix were defaults from add(). dominant_subpath = old_subpath - subdir = os.path.split(dominant_subpath)[0] - if dominant_subpath.find(':') != -1: + subdir = os.path.dirname(dominant_subpath) + if ':' in dominant_subpath: suffix = ':' + dominant_subpath.split(':')[-1] else: suffix = '' @@ -273,7 +274,7 @@ f.close() subdir, name = os.path.split(subpath) msg.set_subdir(subdir) - if name.find(':') != -1: + if ':' in name: msg.set_info(name.split(':')[-1]) return msg @@ -327,27 +328,31 @@ result.append(entry[1:]) return result - def open_folder(self, name): - """Return a Maildir for the named folder, creating it if necessary.""" - path = os.path.join(self._path, '.' + name) - maildirfolder_path = os.path.join(path, 'maildirfolder') + def get_folder(self, folder): + """Return a Maildir instance for the named folder.""" + return Maildir(os.path.join(self._path, '.' + folder), create=False) + + def add_folder(self, folder): + """Create a folder and return a Maildir instance representing it.""" + path = os.path.join(self._path, '.' + folder) result = Maildir(path) + maildirfolder_path = os.path.join(path, 'maildirfolder') if not os.path.exists(maildirfolder_path): - os.mknod(maildirfolder_path, 0600 | stat.S_IFREG) + os.close(os.open(maildirfolder_path, os.O_CREAT | os.O_WRONLY)) return result - def remove_folder(self, name): + def remove_folder(self, folder): """Delete the named folder, which must be empty.""" - path = os.path.join(self._path, '.' + name) + path = os.path.join(self._path, '.' + folder) for entry in os.listdir(os.path.join(path, 'new')) + \ os.listdir(os.path.join(path, 'cur')): if len(entry) < 1 or entry[0] != '.': - raise Error, "Folder '%s' contains message" % name + raise NotEmptyError, "Folder '%s' contains message" % folder for entry in os.listdir(path): if entry != 'new' and entry != 'cur' and entry != 'tmp' and \ os.path.isdir(os.path.join(path, entry)): - raise Error, "Folder '%s' contains subdirectory '%s'" % \ - (name, entry) + raise NotEmptyError, "Folder '%s' contains subdirectory '%s'" \ + % (folder, entry) for root, dirs, files in os.walk(path, topdown=False): for entry in files: os.remove(os.path.join(root, entry)) @@ -360,7 +365,7 @@ now = time.time() for entry in os.listdir(os.path.join(self._path, 'tmp')): path = os.path.join(self._path, 'tmp', entry) - if now - os.stat(path).st_atime > 129600: # 60 * 60 * 36 + if now - os.path.getatime(path) > 129600: # 60 * 60 * 36 os.remove(path) _count = 1 # This is used to generate unique file names. @@ -385,7 +390,8 @@ else: raise else: - raise Error, "Name clash prevented file creation: '%s'" % path + raise ExternalClashError, \ + "Name clash prevented file creation: '%s'" % path def _refresh(self): """Update table of contents mapping.""" @@ -412,14 +418,17 @@ class _singlefileMailbox(Mailbox): """A single-file mailbox.""" - def __init__(self, path, factory=None): + def __init__(self, path, factory=None, create=True): """Initialize a single-file mailbox.""" - Mailbox.__init__(self, path, factory) + Mailbox.__init__(self, path, factory, create) try: f = file(self._path, 'r+') except IOError, e: if e.errno == errno.ENOENT: - f = file(self._path, 'w+') + if create: + f = file(self._path, 'w+') + else: + raise NoSuchMailboxError, self._path elif e.errno == errno.EACCES: f = file(self._path, 'r') else: @@ -544,7 +553,8 @@ def _assert_mtime(self): """Raise an exception if the file has been externally modified.""" if self._mtime != os.fstat(self._file.fileno()).st_mtime: - raise Error, 'External modifications detected: use refresh()' + raise ExternalClashError, \ + 'External modifications detected: use refresh()' def _set_mtime(self): """Store the current mtime.""" @@ -625,10 +635,10 @@ class mbox(_mboxMMDF): """A classic mbox mailbox.""" - def __init__(self, path, factory=None): + def __init__(self, path, factory=None, create=True): """Initialize an mbox mailbox.""" self._message_factory = mboxMessage - _mboxMMDF.__init__(self, path, factory) + _mboxMMDF.__init__(self, path, factory, create) def _pre_message_hook(self, f): """Called before writing each message to file f.""" @@ -657,10 +667,10 @@ class MMDF(_mboxMMDF): """An MMDF mailbox.""" - def __init__(self, path, factory=None): + def __init__(self, path, factory=None, create=True): """Initialize an MMDF mailbox.""" self._message_factory = MMDFMessage - _mboxMMDF.__init__(self, path, factory) + _mboxMMDF.__init__(self, path, factory, create) def _pre_message_hook(self, f): """Called before writing each message to file f.""" @@ -701,13 +711,16 @@ class MH(Mailbox): """An MH mailbox.""" - def __init__(self, path, factory=None): + def __init__(self, path, factory=None, create=True): """Initialize an MH instance.""" - Mailbox.__init__(self, path, factory) + Mailbox.__init__(self, path, factory, create) if not os.path.exists(self._path): - os.mkdir(self._path, 0700) - os.mknod(os.path.join(self._path, '.mh_sequences'), - 0600 | stat.S_IFREG) + if create: + os.mkdir(self._path, 0700) + os.close(os.open(os.path.join(self._path, '.mh_sequences'), + os.O_CREAT | os.O_WRONLY, 0600)) + else: + raise NoSuchMailboxError, self._path def add(self, message): """Add message and return assigned key.""" @@ -779,7 +792,7 @@ f.close() for name, key_list in self.get_sequences(): if key in key_list: - msg.join_sequence(name) + msg.add_sequence(name) return msg def get_string(self, key): @@ -829,27 +842,32 @@ return def list_folders(self): - """Return a list of folders in this mailbox.""" + """Return a list of folder names.""" result = [] for entry in os.listdir(self._path): if os.path.isdir(os.path.join(self._path, entry)): result.append(entry) return result - def open_folder(self, name): - """Return an MH instance for folder name, creating it if necessary.""" - return MH(os.path.join(self._path, name)) + def get_folder(self, folder): + """Return an MH instance for the named folder.""" + return MH(os.path.join(self._path, folder), create=False) - def remove_folder(self, name): - """Delete folder name.""" - path = os.path.join(self._path, name) + def add_folder(self, folder): + """Create a folder and return an MH instance representing it.""" + return Maildir(os.path.join(self._path, '.' + folder)) + + def remove_folder(self, folder): + """Delete the named folder, which must be empty.""" + path = os.path.join(self._path, folder) entries = os.listdir(path) if entries == ['.mh_sequences']: os.remove(os.path.join(path, '.mh_sequences')) elif entries == []: pass else: - raise Error, "Folder '%s' is not empty" % self._path + raise NotEmptyError, "Folder '%s' is not empty" % \ + self._path os.rmdir(path) def get_sequences(self): @@ -871,8 +889,8 @@ results[name] = [key for key in sorted(keys) \ if key in all_keys] except ValueError: - raise Error, "Invalid sequence specification: '%s'" % \ - line.rstrip() + raise FormatError, "Invalid sequence specification: " % \ + "'%s'" % line.rstrip() finally: f.close() return results @@ -942,7 +960,7 @@ def _dump_sequences(self, message, key): """Inspect a new MHMessage and update sequences appropriately.""" - pending_sequences = message.list_sequences() + pending_sequences = message.get_sequences() all_sequences = self.get_sequences() for name, key_list in all_sequences.iteritems(): if name in pending_sequences: @@ -1004,7 +1022,7 @@ """Return a file-like representation or raise a KeyError.""" return StringIO.StringIO(self.get_string(key)) - def list_labels(self): + def get_labels(self): """Return a list of user-defined labels in the mailbox.""" raise NotImplementedError, 'Method not yet implemented' @@ -1172,14 +1190,14 @@ """Set the given flags and unset all others.""" self._info = '2,' + ''.join(sorted(flags)) - def add_flags(self, flags): - """Set the given flags without changing others.""" - self.set_flags(''.join(set(self.get_flags()) | set(flags))) + def add_flag(self, flag): + """Set the given flag(s) without changing others.""" + self.set_flags(''.join(set(self.get_flags()) | set(flag))) - def remove_flags(self, flags): - """Unset the given string flags (if set) without changing others.""" + def remove_flag(self, flag): + """Unset the given string flag(s) without changing others.""" if self.get_flags() != '': - self.set_flags(''.join(set(self.get_flags()) - set(flags))) + self.set_flags(''.join(set(self.get_flags()) - set(flag))) def get_info(self): """Get the message's "info" as a string.""" @@ -1200,23 +1218,23 @@ elif isinstance(message, _mboxMMDFMessage): flags = set(self.get_flags()) if 'S' in flags: - message.add_flags('R') + message.add_flag('R') if self.get_subdir() == 'cur': - message.add_flags('O') + message.add_flag('O') if 'T' in flags: - message.add_flags('D') + message.add_flag('D') if 'F' in flags: - message.add_flags('F') + message.add_flag('F') if 'R' in flags: - message.add_flags('A') + message.add_flag('A') elif isinstance(message, MHMessage): flags = set(self.get_flags()) if 'S' not in flags: - message.join_sequence('unseen') + message.add_sequence('unseen') if 'R' in flags: - message.join_sequence('replied') + message.add_sequence('replied') if 'F' in flags: - message.join_sequence('flagged') + message.add_sequence('flagged') elif isinstance(message, BabylMessage): flags = set(self.get_flags()) if 'S' not in flags: @@ -1287,14 +1305,14 @@ except KeyError: self.add_header('X-Status', xstatus_flags) - def add_flags(self, flags): - """Set the given flags without changing others.""" - self.set_flags(''.join(set(self.get_flags()) | set(flags))) + def add_flag(self, flag): + """Set the given flag(s) without changing others.""" + self.set_flags(''.join(set(self.get_flags()) | set(flag))) - def remove_flags(self, flags): - """Unset the given string flags (if set) without changing others.""" + def remove_flag(self, flag): + """Unset the given string flag(s) without changing others.""" if 'Status' in self or 'X-Status' in self: - self.set_flags(''.join(set(self.get_flags()) - set(flags))) + self.set_flags(''.join(set(self.get_flags()) - set(flag))) def _explain_to(self, message): """Copy mbox- or MMDF-specific state to message insofar as possible.""" @@ -1303,24 +1321,24 @@ if 'O' in flags: message.set_subdir('cur') if 'F' in flags: - message.add_flags('F') + message.add_flag('F') if 'A' in flags: - message.add_flags('R') + message.add_flag('R') if 'R' in flags: - message.add_flags('S') + message.add_flag('S') if 'D' in flags: - message.add_flags('T') + message.add_flag('T') elif isinstance(message, _mboxMMDFMessage): message.set_flags(self.get_flags()) message.set_from(self.get_from()) elif isinstance(message, MHMessage): flags = set(self.get_flags()) if 'R' not in flags: - message.join_sequence('unseen') + message.add_sequence('unseen') if 'A' in flags: - message.join_sequence('replied') + message.add_sequence('replied') if 'F' in flags: - message.join_sequence('flagged') + message.add_sequence('flagged') elif isinstance(message, BabylMessage): flags = set(self.get_flags()) if 'R' not in flags: @@ -1347,11 +1365,15 @@ self._sequences = [] Message.__init__(self, message) - def list_sequences(self): + def get_sequences(self): """Return a list of sequences that include the message.""" return self._sequences[:] - def join_sequence(self, sequence): + def set_sequences(self, sequences): + """Set the list of sequences that include the message.""" + self._sequences = list(sequences) + + def add_sequence(self, sequence): """Add sequence to list of sequences including the message.""" if isinstance(sequence, str): if not sequence in self._sequences: @@ -1359,7 +1381,7 @@ else: raise TypeError, "sequence must be a string" - def leave_sequence(self, sequence): + def remove_sequence(self, sequence): """Remove sequence from the list of sequences including the message.""" try: self._sequences.remove(sequence) @@ -1369,31 +1391,31 @@ def _explain_to(self, message): """Copy MH-specific state to message insofar as possible.""" if isinstance(message, MaildirMessage): - sequences = set(self.list_sequences()) + sequences = set(self.get_sequences()) if 'unseen' in sequences: message.set_subdir('cur') else: message.set_subdir('cur') - message.add_flags('S') + message.add_flag('S') if 'flagged' in sequences: - message.add_flags('F') + message.add_flag('F') if 'replied' in sequences: - message.add_flags('R') + message.add_flag('R') elif isinstance(message, _mboxMMDFMessage): - sequences = set(self.list_sequences()) + sequences = set(self.get_sequences()) if 'unseen' not in sequences: - message.add_flags('RO') + message.add_flag('RO') else: - message.add_flags('O') + message.add_flag('O') if 'flagged' in sequences: - message.add_flags('F') + message.add_flag('F') if 'replied' in sequences: - message.add_flags('A') + message.add_flag('A') elif isinstance(message, MHMessage): - for sequence in self.list_sequences(): - message.join_sequence(sequence) + for sequence in self.get_sequences(): + message.add_sequence(sequence) elif isinstance(message, BabylMessage): - sequences = set(self.list_sequences()) + sequences = set(self.get_sequences()) if 'unseen' in sequences: message.add_label('unseen') if 'replied' in sequences: @@ -1413,10 +1435,14 @@ self._visible = Message() Message.__init__(self, message) - def list_labels(self): + def get_labels(self): """Return a list of labels on the message.""" return self._labels[:] + def set_labels(self, labels): + """Set the list of labels on the message.""" + self._labels = list(labels) + def add_label(self, label): """Add label to list of labels on the message.""" if isinstance(label, str): @@ -1454,37 +1480,37 @@ def _explain_to(self, message): """Copy Babyl-specific state to message insofar as possible.""" if isinstance(message, MaildirMessage): - labels = set(self.list_labels()) + labels = set(self.get_labels()) if 'unseen' in labels: message.set_subdir('cur') else: message.set_subdir('cur') - message.add_flags('S') + message.add_flag('S') if 'forwarded' in labels or 'resent' in labels: - message.add_flags('P') + message.add_flag('P') if 'answered' in labels: - message.add_flags('R') + message.add_flag('R') if 'deleted' in labels: - message.add_flags('T') + message.add_flag('T') elif isinstance(message, _mboxMMDFMessage): - labels = set(self.list_labels()) + labels = set(self.get_labels()) if 'unseen' not in labels: - message.add_flags('RO') + message.add_flag('RO') else: - message.add_flags('O') + message.add_flag('O') if 'deleted' in labels: - message.add_flags('D') + message.add_flag('D') if 'answered' in labels: - message.add_flags('A') + message.add_flag('A') elif isinstance(message, MHMessage): - labels = set(self.list_labels()) + labels = set(self.get_labels()) if 'unseen' in labels: - message.join_sequence('unseen') + message.add_sequence('unseen') if 'answered' in labels: - message.join_sequence('replied') + message.add_sequence('replied') elif isinstance(message, BabylMessage): message.set_visible(self.get_visible()) - for label in self.list_labels(): + for label in self.get_labels(): message.add_label(label) elif isinstance(message, Message): pass @@ -1588,21 +1614,18 @@ return _ProxyFile._read(self, size, read_method) -class Error(Exception): - """Raised for module-specific errors.""" - - def _lock_file(f, path, system=True, dot=True): """Lock file f using lockf, flock, and dot locking.""" lockf_done = flock_done = dotlock_done = False try: - if system and 'fcntl' in globals(): + if system and fcntl: try: fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB) lockf_done = True except IOError, e: if e.errno == errno.EAGAIN: - raise Error, "lockf: lock unavailable: %s" % path + raise ExternalClashError, \ + "lockf: lock unavailable: %s" % path else: raise try: @@ -1610,7 +1633,8 @@ flock_done = True except IOError, e: if e.errno == errno.EWOULDBLOCK: - raise Error, "flock: lock unavailable: %s" % path + raise ExternalClashError, \ + "flock: lock unavailable: %s" % path else: raise if dot: @@ -1637,7 +1661,7 @@ os.remove(tmp) except: pass - raise Error, 'dot lock unavailable: %s' % path + raise ExternalClashError, 'dot lock unavailable: %s' % path else: raise except: @@ -1651,7 +1675,7 @@ def _unlock_file(f, path, system=True, dot=True): """Unlock file f using lockf, flock, and dot locking.""" - if system and 'fcntl' in globals(): + if system and fcntl: fcntl.lockf(f, fcntl.LOCK_UN) fcntl.flock(f, fcntl.LOCK_UN) if dot and os.path.exists(path + '.lock'): @@ -1660,3 +1684,18 @@ def _create_carefully(path): """Create a file if it doesn't exist and open for reading and writing.""" return os.fdopen(os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR), 'r+') + +class Error(Exception): + """Raised for module-specific errors.""" + +class NoSuchMailboxError(Error): + """The specified mailbox does not exist and won't be created.""" + +class NotEmptyError(Error): + """The specified mailbox is not empty and deletion was requested.""" + +class ExternalClashError(Error): + """Another process caused an action to fail.""" + +class FormatError(Error): + """A file appears to have an invalid format.""" Index: test_mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- test_mailbox.py 5 Aug 2005 16:34:45 -0000 1.6 +++ test_mailbox.py 13 Aug 2005 22:41:33 -0000 1.7 @@ -487,32 +487,33 @@ def test_list_folders(self): # List folders - self._box.open_folder('one') - self._box.open_folder('two') - self._box.open_folder('three') + self._box.add_folder('one') + self._box.add_folder('two') + self._box.add_folder('three') self.assert_(len(self._box.list_folders()) == 3) self.assert_(set(self._box.list_folders()) == set(('one', 'two', 'three'))) - def test_open_folder(self): + def test_get_folder(self): # Open folders - folder0 = self._box.open_folder('foo.bar') + self._box.add_folder('foo.bar') + folder0 = self._box.get_folder('foo.bar') folder0.add(self._template % 'bar') self.assert_(os.path.isdir(os.path.join(self._path, '.foo.bar'))) - folder1 = self._box.open_folder('foo.bar') + folder1 = self._box.get_folder('foo.bar') self.assert_(folder1.get_string(folder1.keys()[0]) == \ self._template % 'bar') - def test_remove_folder(self): + def test_add_and_remove_folders(self): # Delete folders - self._box.open_folder('one') - self._box.open_folder('two') + self._box.add_folder('one') + self._box.add_folder('two') self.assert_(len(self._box.list_folders()) == 2) self.assert_(set(self._box.list_folders()) == set(('one', 'two'))) self._box.remove_folder('one') self.assert_(len(self._box.list_folders()) == 1) self.assert_(set(self._box.list_folders()) == set(('two',))) - self._box.open_folder('three') + self._box.add_folder('three') self.assert_(len(self._box.list_folders()) == 2) self.assert_(set(self._box.list_folders()) == set(('two', 'three'))) self._box.remove_folder('three') @@ -775,7 +776,7 @@ self._check_sample(msg) def test_flags(self): - # Use get_flags(), set_flags(), add_flags(), remove_flags() + # Use get_flags(), set_flags(), add_flag(), remove_flag() msg = mailbox.MaildirMessage(_sample_message) self.assert_(msg.get_flags() == '') self.assert_(msg.get_subdir() == 'new') @@ -784,9 +785,9 @@ self.assert_(msg.get_flags() == 'F') msg.set_flags('SDTP') self.assert_(msg.get_flags() == 'DPST') - msg.add_flags('FT') + msg.add_flag('FT') self.assert_(msg.get_flags() == 'DFPST') - msg.remove_flags('TDRP') + msg.remove_flag('TDRP') self.assert_(msg.get_flags() == 'FS') self.assert_(msg.get_subdir() == 'new') self._check_sample(msg) @@ -810,10 +811,10 @@ msg.set_info('1,') self.assert_(msg.get_flags() == '') self.assert_(msg.get_info() == '1,') - msg.remove_flags('RPT') + msg.remove_flag('RPT') self.assert_(msg.get_flags() == '') self.assert_(msg.get_info() == '1,') - msg.add_flags('D') + msg.add_flag('D') self.assert_(msg.get_flags() == 'D') self.assert_(msg.get_info() == '2,D') self._check_sample(msg) @@ -845,16 +846,16 @@ self._check_from(msg, 'blah at temp') def test_flags(self): - # Use get_flags(), set_flags(), add_flags(), remove_flags() + # Use get_flags(), set_flags(), add_flag(), remove_flag() msg = mailbox.mboxMessage(_sample_message) self.assert_(msg.get_flags() == '') msg.set_flags('F') self.assert_(msg.get_flags() == 'F') msg.set_flags('XODR') self.assert_(msg.get_flags() == 'RODX') - msg.add_flags('FA') + msg.add_flag('FA') self.assert_(msg.get_flags() == 'RODFAX') - msg.remove_flags('FDXA') + msg.remove_flag('FDXA') self.assert_(msg.get_flags() == 'RO') self._check_sample(msg) @@ -879,21 +880,27 @@ self.assert_(msg._sequences == []) def test_sequences(self): - # List, join, and leave sequences + # Get, set, join, and leave sequences msg = mailbox.MHMessage(_sample_message) - self.assert_(msg.list_sequences() == []) - msg.join_sequence('unseen') - self.assert_(msg.list_sequences() == ['unseen']) - msg.join_sequence('flagged') - self.assert_(msg.list_sequences() == ['unseen', 'flagged']) - msg.join_sequence('flagged') - self.assert_(msg.list_sequences() == ['unseen', 'flagged']) - msg.leave_sequence('unseen') - self.assert_(msg.list_sequences() == ['flagged']) - msg.join_sequence('foobar') - self.assert_(msg.list_sequences() == ['flagged', 'foobar']) - msg.leave_sequence('replied') - self.assert_(msg.list_sequences() == ['flagged', 'foobar']) + self.assert_(msg.get_sequences() == []) + msg.set_sequences(['foobar']) + self.assert_(msg.get_sequences() == ['foobar']) + msg.set_sequences([]) + self.assert_(msg.get_sequences() == []) + msg.add_sequence('unseen') + self.assert_(msg.get_sequences() == ['unseen']) + msg.add_sequence('flagged') + self.assert_(msg.get_sequences() == ['unseen', 'flagged']) + msg.add_sequence('flagged') + self.assert_(msg.get_sequences() == ['unseen', 'flagged']) + msg.remove_sequence('unseen') + self.assert_(msg.get_sequences() == ['flagged']) + msg.add_sequence('foobar') + self.assert_(msg.get_sequences() == ['flagged', 'foobar']) + msg.remove_sequence('replied') + self.assert_(msg.get_sequences() == ['flagged', 'foobar']) + msg.set_sequences(['foobar', 'replied']) + self.assert_(msg.get_sequences() == ['foobar', 'replied']) class TestBabylMessage(TestMessage): @@ -904,21 +911,27 @@ self.assert_(msg._labels == []) def test_labels(self): - # List, add, and remove labels + # Get, set, join, and leave labels msg = mailbox.BabylMessage(_sample_message) - self.assert_(msg.list_labels() == []) + self.assert_(msg.get_labels() == []) + msg.set_labels(['foobar']) + self.assert_(msg.get_labels() == ['foobar']) + msg.set_labels([]) + self.assert_(msg.get_labels() == []) msg.add_label('filed') - self.assert_(msg.list_labels() == ['filed']) + self.assert_(msg.get_labels() == ['filed']) msg.add_label('resent') - self.assert_(msg.list_labels() == ['filed', 'resent']) + self.assert_(msg.get_labels() == ['filed', 'resent']) msg.add_label('resent') - self.assert_(msg.list_labels() == ['filed', 'resent']) + self.assert_(msg.get_labels() == ['filed', 'resent']) msg.remove_label('filed') - self.assert_(msg.list_labels() == ['resent']) + self.assert_(msg.get_labels() == ['resent']) msg.add_label('foobar') - self.assert_(msg.list_labels() == ['resent', 'foobar']) + self.assert_(msg.get_labels() == ['resent', 'foobar']) msg.remove_label('unseen') - self.assert_(msg.list_labels() == ['resent', 'foobar']) + self.assert_(msg.get_labels() == ['resent', 'foobar']) + msg.set_labels(['foobar', 'answered']) + self.assert_(msg.get_labels() == ['foobar', 'answered']) def test_visible(self): # Get, set, and update visible headers @@ -1007,7 +1020,7 @@ ('T', ['unseen']), ('DFPRST', ['replied', 'flagged'])) for setting, result in pairs: msg_maildir.set_flags(setting) - self.assert_(mailbox.MHMessage(msg_maildir).list_sequences() == \ + self.assert_(mailbox.MHMessage(msg_maildir).get_sequences() == \ result) def test_maildir_to_babyl(self): @@ -1019,7 +1032,7 @@ ('DFPRST', ['deleted', 'answered', 'forwarded'])) for setting, result in pairs: msg_maildir.set_flags(setting) - self.assert_(mailbox.BabylMessage(msg_maildir).list_labels() == \ + self.assert_(mailbox.BabylMessage(msg_maildir).get_labels() == \ result) def test_mboxmmdf_to_maildir(self): @@ -1057,7 +1070,7 @@ ('RODFA', ['replied', 'flagged'])) for setting, result in pairs: msg_mboxMMDF.set_flags(setting) - self.assert_(mailbox.MHMessage(msg_mboxMMDF).list_sequences() \ + self.assert_(mailbox.MHMessage(msg_mboxMMDF).get_sequences() \ == result) def test_mboxmmdf_to_babyl(self): @@ -1070,20 +1083,20 @@ ('RODFA', ['deleted', 'answered'])) for setting, result in pairs: msg.set_flags(setting) - self.assert_(mailbox.BabylMessage(msg).list_labels() == result) + self.assert_(mailbox.BabylMessage(msg).get_labels() == result) def test_mh_to_maildir(self): # Convert MHMessage to MaildirMessage pairs = (('unseen', ''), ('replied', 'RS'), ('flagged', 'FS')) for setting, result in pairs: msg = mailbox.MHMessage(_sample_message) - msg.join_sequence(setting) + msg.add_sequence(setting) self.assert_(mailbox.MaildirMessage(msg).get_flags() == result) self.assert_(mailbox.MaildirMessage(msg).get_subdir() == 'cur') msg = mailbox.MHMessage(_sample_message) - msg.join_sequence('unseen') - msg.join_sequence('replied') - msg.join_sequence('flagged') + msg.add_sequence('unseen') + msg.add_sequence('replied') + msg.add_sequence('flagged') self.assert_(mailbox.MaildirMessage(msg).get_flags() == 'FR') self.assert_(mailbox.MaildirMessage(msg).get_subdir() == 'cur') @@ -1092,23 +1105,23 @@ pairs = (('unseen', 'O'), ('replied', 'ROA'), ('flagged', 'ROF')) for setting, result in pairs: msg = mailbox.MHMessage(_sample_message) - msg.join_sequence(setting) + msg.add_sequence(setting) for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage): self.assert_(class_(msg).get_flags() == result) msg = mailbox.MHMessage(_sample_message) - msg.join_sequence('unseen') - msg.join_sequence('replied') - msg.join_sequence('flagged') + msg.add_sequence('unseen') + msg.add_sequence('replied') + msg.add_sequence('flagged') for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage): self.assert_(class_(msg).get_flags() == 'OFA') def test_mh_to_mh(self): # Convert MHMessage to MHMessage msg = mailbox.MHMessage(_sample_message) - msg.join_sequence('unseen') - msg.join_sequence('replied') - msg.join_sequence('flagged') - self.assert_(mailbox.MHMessage(msg).list_sequences() == \ + msg.add_sequence('unseen') + msg.add_sequence('replied') + msg.add_sequence('flagged') + self.assert_(mailbox.MHMessage(msg).get_sequences() == \ ['unseen', 'replied', 'flagged']) def test_mh_to_babyl(self): @@ -1117,13 +1130,13 @@ ('flagged', [])) for setting, result in pairs: msg = mailbox.MHMessage(_sample_message) - msg.join_sequence(setting) - self.assert_(mailbox.BabylMessage(msg).list_labels() == result) + msg.add_sequence(setting) + self.assert_(mailbox.BabylMessage(msg).get_labels() == result) msg = mailbox.MHMessage(_sample_message) - msg.join_sequence('unseen') - msg.join_sequence('replied') - msg.join_sequence('flagged') - self.assert_(mailbox.BabylMessage(msg).list_labels() == \ + msg.add_sequence('unseen') + msg.add_sequence('replied') + msg.add_sequence('flagged') + self.assert_(mailbox.BabylMessage(msg).get_labels() == \ ['unseen', 'answered']) def test_babyl_to_maildir(self): @@ -1168,12 +1181,12 @@ for setting, result in pairs: msg = mailbox.BabylMessage(_sample_message) msg.add_label(setting) - self.assert_(mailbox.MHMessage(msg).list_sequences() == result) + self.assert_(mailbox.MHMessage(msg).get_sequences() == result) msg = mailbox.BabylMessage(_sample_message) for label in ('unseen', 'deleted', 'filed', 'answered', 'forwarded', 'edited', 'resent'): msg.add_label(label) - self.assert_(mailbox.MHMessage(msg).list_sequences() == \ + self.assert_(mailbox.MHMessage(msg).get_sequences() == \ ['unseen', 'replied']) def test_babyl_to_babyl(self): @@ -1184,9 +1197,9 @@ 'edited', 'resent'): msg.add_label(label) msg2 = mailbox.BabylMessage(msg) - self.assert_(msg2.list_labels() == ['unseen', 'deleted', 'filed', - 'answered', 'forwarded', 'edited', - 'resent']) + self.assert_(msg2.get_labels() == ['unseen', 'deleted', 'filed', + 'answered', 'forwarded', 'edited', + 'resent']) self.assert_(msg.get_visible().keys() == msg2.get_visible().keys()) for key in msg.get_visible().keys(): self.assert_(msg.get_visible()[key] == msg2.get_visible()[key]) From pje at users.sourceforge.net Sun Aug 14 01:04:18 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 01:04:18 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command egg_info.py, 1.11, 1.12 Message-ID: <20050813230418.DC5101E4013@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14936/setuptools/command Modified Files: egg_info.py Log Message: Added docs for main EntryPoint APIs, and cleaned up the API itself a bit. Also fixed a few bugs. Index: egg_info.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/egg_info.py,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- egg_info.py 6 Aug 2005 21:17:50 -0000 1.11 +++ egg_info.py 13 Aug 2005 23:04:08 -0000 1.12 @@ -219,7 +219,7 @@ data = [] for section, contents in ep.items(): if not isinstance(contents,basestring): - contents = EntryPoint.parse_list(section, contents) + contents = EntryPoint.parse_group(section, contents) contents = '\n'.join(map(str,contents.values())) data.append('[%s]\n%s\n\n' % (section,contents)) data = ''.join(data) From pje at users.sourceforge.net Sun Aug 14 01:04:19 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 01:04:19 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools api_tests.txt, 1.5, 1.6 pkg_resources.py, 1.64, 1.65 pkg_resources.txt, 1.4, 1.5 Message-ID: <20050813230419.CC68B1E4014@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14936 Modified Files: api_tests.txt pkg_resources.py pkg_resources.txt Log Message: Added docs for main EntryPoint APIs, and cleaned up the API itself a bit. Also fixed a few bugs. Index: api_tests.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/api_tests.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- api_tests.txt 6 Aug 2005 20:54:01 -0000 1.5 +++ api_tests.txt 13 Aug 2005 23:04:08 -0000 1.6 @@ -138,7 +138,7 @@ ['http://example.com/something'] >>> dist in ws True - >>> Distribution('foo') in ws + >>> Distribution('foo',version="") in ws False And you can iterate over its distributions:: Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.64 retrieving revision 1.65 diff -u -d -r1.64 -r1.65 --- pkg_resources.py 11 Aug 2005 00:37:37 -0000 1.64 +++ pkg_resources.py 13 Aug 2005 23:04:08 -0000 1.65 @@ -1598,7 +1598,7 @@ class EntryPoint(object): - """Object representing an importable location""" + """Object representing an advertised importable object""" def __init__(self, name, module_name, attrs=(), extras=(), dist=None): if not MODULE(module_name): @@ -1680,35 +1680,37 @@ #@classmethod - def parse_list(cls, section, contents, dist=None): - if not MODULE(section): - raise ValueError("Invalid section name", section) + def parse_group(cls, group, lines, dist=None): + """Parse an entry point group""" + if not MODULE(group): + raise ValueError("Invalid group name", group) this = {} - for line in yield_lines(contents): + for line in yield_lines(lines): ep = cls.parse(line, dist) if ep.name in this: - raise ValueError("Duplicate entry point",section,ep.name) + raise ValueError("Duplicate entry point", group, ep.name) this[ep.name]=ep return this - parse_list = classmethod(parse_list) + parse_group = classmethod(parse_group) #@classmethod def parse_map(cls, data, dist=None): + """Parse a map of entry point groups""" if isinstance(data,dict): data = data.items() else: data = split_sections(data) maps = {} - for section, contents in data: - if section is None: - if not contents: + for group, lines in data: + if group is None: + if not lines: continue - raise ValueError("Entry points must be listed in sections") - section = section.strip() - if section in maps: - raise ValueError("Duplicate section name", section) - maps[section] = cls.parse_list(section, contents, dist) + raise ValueError("Entry points must be listed in groups") + group = group.strip() + if group in maps: + raise ValueError("Duplicate group name", group) + maps[group] = cls.parse_group(group, lines, dist) return maps parse_map = classmethod(parse_map) @@ -1718,8 +1720,6 @@ - - class Distribution(object): """Wrap an actual or potential sys.path entry w/metadata""" def __init__(self, @@ -1862,7 +1862,9 @@ return str(self) def __str__(self): - version = getattr(self,'version',None) or "[unknown version]" + try: version = getattr(self,'version',None) + except ValueError: version = None + version = version or "[unknown version]" return "%s %s" % (self.project_name,version) def __getattr__(self,attr): @@ -1882,8 +1884,6 @@ return Requirement.parse('%s==%s' % (self.project_name, self.version)) - - def load_entry_point(self, group, name): """Return the `name` entry point of `group` or raise ImportError""" ep = self.get_entry_info(group,name) Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- pkg_resources.txt 7 Aug 2005 20:54:10 -0000 1.4 +++ pkg_resources.txt 13 Aug 2005 23:04:08 -0000 1.5 @@ -46,11 +46,12 @@ API Reference ------------- + 'require', 'run_script', Namespace Package Support ========================= -XXX +declare_namespace, fixup_namespace_packages, register_namespace_handler ``WorkingSet`` Objects @@ -65,24 +66,188 @@ XXX -``EntryPoint`` Objects -====================== - -XXX - - ``Requirement`` Objects ======================= XXX Syntax, parse_requirments, Requirement.parse, etc. + + +Entry Points +============ + +Entry points are a simple way for distributions to "advertise" Python objects +(such as functions or classes) for use by other distributions. Extensible +applications and frameworks can search for entry points with a particular name +or group, either from a specific distribution or from all active distributions +on sys.path, and then inspect or load the advertised objects at will. + +Entry points belong to "groups" which are named with a dotted name similar to +a Python package or module name. For example, the ``setuptools`` package uses +an entry point named ``distutils.commands`` in order to find commands defined +by distutils extensions. ``setuptools`` treats the names of entry points +defined in that group as the acceptable commands for a setup script. + +In a similar way, other packages can define their own entry point groups, +either using dynamic names within the group (like ``distutils.commands``), or +possibly using predefined names within the group. For example, a blogging +framework that offers various pre- or post-publishing hooks might define an +entry point group and look for entry points named "pre_process" and +"post_process" within that group. + +To advertise an entry point, a project needs to use ``setuptools`` and provide +an ``entry_points`` argument to ``setup()`` in its setup script, so that the +entry points will be included in the distribution's metadata. For more +details, see the ``setuptools`` documentation. (XXX link here to setuptools) + +Each project distribution can advertise at most one entry point of a given +name within the same entry point group. For example, a distutils extension +could advertise two different ``distutils.commands`` entry points, as long as +they had different names. However, there is nothing that prevents *different* +projects from advertising entry points of the same name in the same group. In +some cases, this is a desirable thing, since the application or framework that +uses the entry points may be calling them as hooks, or in some other way +combining them. It is up to the application or framework to decide what to do +if multiple distributions advertise an entry point; some possibilities include +using both entry points, displaying an error message, using the first one found +in sys.path order, etc. + + +Convenience API +--------------- + +In the following functions, the `dist` argument can be a ``Distribution`` +instance, a ``Requirement`` instance, or a string specifying a requirement +(i.e. project name, version, etc.). If the argument is a string or +``Requirement``, the specified distribution is located (and added to sys.path +if not already present). An error will be raised if a matching distribution is +not available. + +The `group` argument should be a string containing a dotted identifier, +identifying an entry point group. If you are defining an entry point group, +you should include some portion of your package's name in the group name so as +to avoid collision with other packages' entry point groups. + +``load_entry_point(dist, group, name)`` + Load the named entry point from the specified distribution, or raise + ``ImportError``. + +``get_entry_info(dist, group, name)`` + Return an ``EntryPoint`` object for the given `group` and `name` from + the specified distribution. Returns ``None`` if the distribution has not + advertised a matching entry point. + +``get_entry_map(dist, group=None) + Return the distribution's entry point map for `group`, or the full entry + map for the distribution. This function always returns a dictionary, + even if the distribution advertises no entry points. If `group` is given, + the dictionary maps entry point names to the corresponding ``EntryPoint`` + object. If `group` is None, the dictionary maps group names to + dictionaries that then map entry point names to the corresponding + ``EntryPoint`` instance in that group. + +``iter_entry_points(group, name=None)`` + Yield entry point objects from `group` matching `name` + + If `name` is None, yields all entry points in `group` from all + distributions in the working set on sys.path, otherwise only ones matching + both `group` and `name` are yielded. Entry points are yielded from + the active distributions in the order that the distributions appear on + sys.path. (Within entry points for a particular distribution, however, + there is no particular ordering.) + + +Creating and Parsing +-------------------- + +``EntryPoint(name, module_name, attrs=(), extras=(), dist=None)`` + Create an ``EntryPoint`` instance. `name` is the entry point name. The + `module_name` is the (dotted) name of the module containing the advertised + object. `attrs` is an optional tuple of names to look up from the + module to obtain the advertised object. For example, an `attrs` of + ``("foo","bar")`` and a `module_name` of ``"baz"`` would mean that the + advertised object could be obtained by the following code:: + + import baz + advertised_object = baz.foo.bar + + The `extras` are an optional tuple of "extra feature" names that the + distribution needs in order to provide this entry point. When the + entry point is loaded, these extra features are looked up in the `dist` + argument to find out what other distributions may need to be activated + on sys.path; see the ``load()`` method for more details. The `extras` + argument is only meaningful if `dist` is specified. `dist` must be + a ``Distribution`` instance. + +``EntryPoint.parse(src, dist=None)`` (classmethod) + Parse a single entry point from string `src` + + Entry point syntax follows the form:: + + name = some.module:some.attr [extra1,extra2] + + The entry name and module name are required, but the ``:attrs`` and + ``[extras]`` parts are optional, as is the whitespace shown between + some of the items. The `dist` argument is passed through to the + ``EntryPoint()`` constructor, along with the other values parsed from + `src`. + +``EntryPoint.parse_group(group, lines, dist=None)`` (classmethod) + Parse `lines` (a string or sequence of lines) to create a dictionary + mapping entry point names to ``EntryPoint`` objects. ``ValueError`` is + raised if entry point names are duplicated, if `group` is not a valid + entry point group name, or if there are any syntax errors. (Note: the + `group` parameter is used only for validation and to create more + informative error messages.) If `dist` is provided, it will be used to + set the ``dist`` attribute of the created ``EntryPoint`` objects. + +``EntryPoint.parse_map(data, dist=None)`` (classmethod) + Parse `data` into a dictionary mapping group names to dictionaries mapping + entry point names to ``EntryPoint`` objects. If `data` is a dictionary, + then the keys are used as group names and the values are passed to + ``parse_group()`` as the `lines` argument. If `data` is a string or + sequence of lines, it is first split into .ini-style sections (using + the ``split_sections()`` utility function) and the section names are used + as group names. In either case, the `dist` argument is passed through to + ``parse_group()`` so that the entry points will be linked to the specified + distribution. + + +``EntryPoint`` Objects +---------------------- + +For simple introspection, ``EntryPoint`` objects have attributes that +correspond exactly to the constructor argument names: ``name``, +``module_name``, ``attrs``, ``extras``, and ``dist`` are all available. In +addition, the following methods are provided: + +``load(require=True, env=None, installer=None)`` + Load the entry point, returning the advertised Python object, or raise + ``ImportError`` if it cannot be obtained. If `require` is a true value, + then ``require(env, installer)`` is called before attempting the import. + +``require(env=None, installer=None)`` + Ensure that any "extras" needed by the entry point are available on + sys.path. ``UnknownExtra`` is raised if the ``EntryPoint`` has ``extras``, + but no ``dist``, or if the named extras are not defined by the + distribution. If `env` is supplied, it must be an ``Environment``, and it + will be used to search for needed distributions if they are not already + present on sys.path. If `installer` is supplied, it must be a callable + taking a ``Requirement`` instance and returning a matching importable + ``Distribution`` instance or None. + + ``Distribution`` Objects ======================== Factories: get_provider, get_distribution, find_distributions; see also WorkingSet and Environment APIs. +register_finder +register_loader_type +'load_entry_point', 'get_entry_map', 'get_entry_info' + ``ResourceManager`` API ======================= @@ -459,6 +624,21 @@ set. +PEP 302 Utilities +----------------- + +``get_importer(path_item)`` + Retrieve a PEP 302 "importer" for the given path item (which need not + actually be on ``sys.path``). This routine simulates the PEP 302 protocol + for obtaining an "importer" object. It first checks for an importer for + the path item in ``sys.path_importer_cache``, and if not found it calls + each of the ``sys.path_hooks`` and caches the result if a good importer is + found. If no importer is found, this routine returns an ``ImpWrapper`` + instance that wraps the builtin import machinery as a PEP 302-compliant + "importer" object. This ``ImpWrapper`` is *not* cached; instead a new + instance is returned each time. + + File/Path Utilities ------------------- From pje at users.sourceforge.net Sun Aug 14 01:04:19 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 01:04:19 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/tests test_resources.py, 1.21, 1.22 Message-ID: <20050813230419.C912B1E4013@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/tests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14936/setuptools/tests Modified Files: test_resources.py Log Message: Added docs for main EntryPoint APIs, and cleaned up the API itself a bit. Also fixed a few bugs. Index: test_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/tests/test_resources.py,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- test_resources.py 7 Aug 2005 01:03:36 -0000 1.21 +++ test_resources.py 13 Aug 2005 23:04:08 -0000 1.22 @@ -269,9 +269,9 @@ """ def testParseList(self): - self.checkSubMap(EntryPoint.parse_list("xyz", self.submap_str)) - self.assertRaises(ValueError, EntryPoint.parse_list, "x a", "foo=bar") - self.assertRaises(ValueError, EntryPoint.parse_list, "x", + self.checkSubMap(EntryPoint.parse_group("xyz", self.submap_str)) + self.assertRaises(ValueError, EntryPoint.parse_group, "x a", "foo=bar") + self.assertRaises(ValueError, EntryPoint.parse_group, "x", ["foo=baz", "foo=bar"]) def testParseMap(self): @@ -397,7 +397,7 @@ """ ) ), - [(None,["x"]), ("y",["z","a"]), ("b",["c"]), ("d",[]), ("q",["v"])] + [(None,["x"]), ("Y",["z","a"]), ("b",["c"]), ("d",[]), ("q",["v"])] ) self.assertRaises(ValueError,list,pkg_resources.split_sections("[foo")) From pje at users.sourceforge.net Sun Aug 14 02:37:38 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 02:37:38 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.txt, 1.5, 1.6 Message-ID: <20050814003738.E81821E4018@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv419 Modified Files: pkg_resources.txt Log Message: Document "Requirement" objects. Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- pkg_resources.txt 13 Aug 2005 23:04:08 -0000 1.5 +++ pkg_resources.txt 14 Aug 2005 00:37:28 -0000 1.6 @@ -69,9 +69,96 @@ ``Requirement`` Objects ======================= -XXX Syntax, parse_requirments, Requirement.parse, etc. +``Requirement`` objects express what versions of a project are suitable for +some purpose. These objects (or their string form) are used by various +``pkg_resources`` APIs in order to find distributions that a script or +distribution needs. + +Requirements Parsing +-------------------- + +``parse_requirements(s)`` + Yield ``Requirement`` objects for a string or list of lines. Each + requirement must start on a new line. See below for syntax. +``Requirement.parse(s)`` + Create a ``Requirement`` object from a string or list of lines. A + ``ValueError`` is raised if the string or lines do not contain a valid + requirement specifier. The syntax of a requirement specifier can be + defined in EBNF as follows:: + + requirement ::= project_name versionspec? extras? + versionspec ::= comparison version (',' comparison version)* + comparison ::= '<' | '<=' | '!=' | '==' | '>=' | '>' + extras ::= '[' extralist? ']' + extralist ::= identifier (',' identifier)* + project_name ::= identifier + identifier ::= [-A-Za-z0-9_]+ + version ::= [-A-Za-z0-9_.]+ + + Tokens can be separated by whitespace, and a requirement can be continued + over multiple lines using a backslash (``\\``). Line-end comments (using + ``#``) are also allowed. + + Some examples of valid requirement specifiers:: + + FooProject >= 1.2 + Fizzy [foo, bar] + PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1 + SomethingWhoseVersionIDontCareAbout + + The project name is the only required portion of a requirement string, and + if it's the only thing supplied, the requirement will accept any version + of that project. + + The "extras" in a requirement are used to request optional features of a + project, that may require additional project distributions in order to + function. For example, if the hypothetical "Report-O-Rama" project offered + optional PDF support, it might require an additional library in order to + provide that support. Thus, a project needing Report-O-Rama's PDF features + could use a requirement of ``Report-O-Rama[PDF]`` to request installation + or activation of both Report-O-Rama and any libraries it needs in order to + provide PDF support. For example, you could use:: + + easy_install.py Report-O-Rama[PDF] + + To install the necessary packages using the EasyInstall program, or call + ``pkg_resources.require('Report-O-Rama[PDF]')`` to add the necessary + distributions to sys.path at runtime. + + +``Requirement`` Methods and Attributes +-------------------------------------- + +``__contains__(dist_or_version)`` + Return true if `dist_or_version` fits the criteria for this requirement. + If `dist_or_version` is a ``Distribution`` object, its project name must + match the requirement's project name, and its version must meet the + requirement's version criteria. If `dist_or_version` is a string, it is + parsed using the ``parse_version()`` utility function. Otherwise, it is + assumed to be an already-parsed version. + +``__eq__(other_requirement)`` + A requirement compares equal to another requirement if they have + case-insensitively equal project names, version specifiers, and "extras". + (The order that extras and version specifiers are in is also ignored.) + Equal requirements also have equal hashes, so that requirements can be + used in sets or as dictionary keys. + +``__str__()`` + The string form of a ``Requirement`` is a string that, if passed to + ``Requirement.parse()``, would return an equal ``Requirement`` object. + +``project_name`` + The name of the required project + +``key`` + An all-lowercase version of the ``project_name``, useful for comparison + or indexing. + +``extras`` + A tuple of names of "extras" that this requirement calls for. Entry Points From pje at users.sourceforge.net Sun Aug 14 03:45:48 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 03:45:48 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools package_index.py, 1.17, 1.18 Message-ID: <20050814014548.7DFF31E4018@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9985/setuptools Modified Files: package_index.py Log Message: Document the "Environment" class, and simplify its API. Index: package_index.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/package_index.py,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- package_index.py 11 Aug 2005 00:37:37 -0000 1.17 +++ package_index.py 14 Aug 2005 01:45:38 -0000 1.18 @@ -264,7 +264,7 @@ def obtain(self, requirement, installer=None): self.find_packages(requirement) - for dist in self.get(requirement.key, ()): + for dist in self[requirement.key]: if dist in requirement: return dist self.debug("%s does not match %s", requirement, dist) @@ -344,7 +344,7 @@ self.info("Searching for %s", requirement) def find(req): - for dist in self.get(req.key, ()): + for dist in self[req.key]: if dist in req and (dist.precedence<=SOURCE_DIST or not source): self.info("Best match: %s", dist) return self.download(dist.location, tmpdir) From pje at users.sourceforge.net Sun Aug 14 03:45:48 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 03:45:48 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/tests test_resources.py, 1.22, 1.23 Message-ID: <20050814014548.994281E4019@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/tests In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9985/setuptools/tests Modified Files: test_resources.py Log Message: Document the "Environment" class, and simplify its API. Index: test_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/tests/test_resources.py,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- test_resources.py 13 Aug 2005 23:04:08 -0000 1.22 +++ test_resources.py 14 Aug 2005 01:45:38 -0000 1.23 @@ -25,19 +25,19 @@ # empty path should produce no distributions ad = Environment([], python=None) self.assertEqual(list(ad), []) - self.assertEqual(len(ad),0) - self.assertEqual(ad.get('FooPkg'),None) - self.failIf('FooPkg' in ad) + self.assertEqual(ad['FooPkg'],[]) + ad.add(Distribution.from_filename("FooPkg-1.3_1.egg")) ad.add(Distribution.from_filename("FooPkg-1.4-py2.4-win32.egg")) ad.add(Distribution.from_filename("FooPkg-1.2-py2.4.egg")) # Name is in there now - self.failUnless('FooPkg' in ad) + self.failUnless(ad['FooPkg']) # But only 1 package self.assertEqual(list(ad), ['foopkg']) - self.assertEqual(len(ad),1) + + # Distributions sort by version self.assertEqual( @@ -46,7 +46,7 @@ # Removing a distribution leaves sequence alone ad.remove(ad['FooPkg'][1]) self.assertEqual( - [dist.version for dist in ad.get('FooPkg')], ['1.4','1.2'] + [dist.version for dist in ad['FooPkg']], ['1.4','1.2'] ) # And inserting adds them in order ad.add(Distribution.from_filename("FooPkg-1.9.egg")) From pje at users.sourceforge.net Sun Aug 14 03:45:49 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 03:45:49 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.65, 1.66 pkg_resources.txt, 1.6, 1.7 setuptools.txt, 1.30, 1.31 Message-ID: <20050814014549.6CF981E4018@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9985 Modified Files: pkg_resources.py pkg_resources.txt setuptools.txt Log Message: Document the "Environment" class, and simplify its API. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.65 retrieving revision 1.66 diff -u -d -r1.65 -r1.66 --- pkg_resources.py 13 Aug 2005 23:04:08 -0000 1.65 +++ pkg_resources.py 14 Aug 2005 01:45:37 -0000 1.66 @@ -234,7 +234,7 @@ def load_entry_point(dist, group, name): """Return `name` entry point of `group` for `dist` or raise ImportError""" return get_distribution(dist).load_entry_point(group, name) - + def get_entry_map(dist, group=None): """Return the entry point map for `group`, or the full entry map""" return get_distribution(dist).get_entry_map(group) @@ -537,8 +537,8 @@ def __init__(self,search_path=None,platform=get_platform(),python=PY_MAJOR): """Snapshot distributions available on a search path - Any distributions found on `search_path` are added to the distribution - map. `search_path` should be a sequence of ``sys.path`` items. If not + Any distributions found on `search_path` are added to the environment. + `search_path` should be a sequence of ``sys.path`` items. If not supplied, ``sys.path`` is used. `platform` is an optional string specifying the name of the platform @@ -558,31 +558,24 @@ self.scan(search_path) def can_add(self, dist): - """Is distribution `dist` acceptable for this collection?""" + """Is distribution `dist` acceptable for this environment? + + The distribution must match the platform and python version + requirements specified when this environment was created, or False + is returned. + """ return (self.python is None or dist.py_version is None or dist.py_version==self.python) \ and compatible_platforms(dist.platform,self.platform) - def __iter__(self): - """Iterate over distribution keys""" - return iter(self._distmap.keys()) - - def __contains__(self,name): - """Has a distribution named `name` ever been added to this map?""" - return name.lower() in self._distmap - - - def get(self,key,default=None): - """Return ``self[key]`` if `key` in self, otherwise return `default`""" - if key in self: - return self[key] - else: - return default + def remove(self, dist): + """Remove `dist` from the environment""" + self._distmap[dist.key].remove(dist) def scan(self, search_path=None): - """Scan `search_path` for distributions usable on `platform` + """Scan `search_path` for distributions usable in this environment - Any distributions found are added to the distribution map. + Any distributions found are added to the environment. `search_path` should be a sequence of ``sys.path`` items. If not supplied, ``sys.path`` is used. Only distributions conforming to the platform/python version defined at initialization are added. @@ -594,66 +587,73 @@ for dist in find_distributions(item): self.add(dist) - def __getitem__(self,key): - """Return a newest-to-oldest list of distributions for the given key - - The returned list may be modified in-place, e.g. for narrowing down - usable distributions. + def __getitem__(self,project_name): + """Return a newest-to-oldest list of distributions for `project_name` """ try: - return self._cache[key] + return self._cache[project_name] except KeyError: - key = key.lower() - if key not in self._distmap: - raise + project_name = project_name.lower() + if project_name not in self._distmap: + return [] - if key not in self._cache: - dists = self._cache[key] = self._distmap[key] + if project_name not in self._cache: + dists = self._cache[project_name] = self._distmap[project_name] _sort_dists(dists) - return self._cache[key] + return self._cache[project_name] def add(self,dist): - """Add `dist` to the distribution map, only if it's suitable""" + """Add `dist` if we ``can_add()`` it and it isn't already added""" if self.can_add(dist): - self._distmap.setdefault(dist.key,[]).append(dist) - if dist.key in self._cache: - _sort_dists(self._cache[dist.key]) + dists = self._distmap.setdefault(dist.key,[]) + if dist not in dists: + dists.append(dist) + if dist.key in self._cache: + _sort_dists(self._cache[dist.key]) - def remove(self,dist): - """Remove `dist` from the distribution map""" - self._distmap[dist.key].remove(dist) def best_match(self, req, working_set, installer=None): """Find distribution best matching `req` and usable on `working_set` - If a distribution that's already active in `working_set` is unsuitable, - a VersionConflict is raised. If one or more suitable distributions are - already active, the leftmost distribution (i.e., the one first in - the search path) is returned. Otherwise, the available distribution - with the highest version number is returned. If nothing is available, - returns ``obtain(req,installer)`` or ``None`` if no distribution can - be obtained. + This calls the ``find(req)`` method of the `working_set` to see if a + suitable distribution is already active. (This may raise + ``VersionConflict`` if an unsuitable version of the project is already + active in the specified `working_set`.) If a suitable distribution + isn't active, this method returns the newest distribution in the + environment that meets the ``Requirement`` in `req`. If no suitable + distribution is found, and `installer` is supplied, then the result of + calling the environment's ``obtain(req, installer)`` method will be + returned. """ dist = working_set.find(req) if dist is not None: return dist - - for dist in self.get(req.key, ()): + for dist in self[req.key]: if dist in req: return dist - return self.obtain(req, installer) # try and download/install def obtain(self, requirement, installer=None): - """Obtain a distro that matches requirement (e.g. via download)""" + """Obtain a distribution matching `requirement` (e.g. via download) + + Obtain a distro that matches requirement (e.g. via download). In the + base ``Environment`` class, this routine just returns + ``installer(requirement)``, unless `installer` is None, in which case + None is returned instead. This method is a hook that allows subclasses + to attempt other ways of obtaining a distribution before falling back + to the `installer` argument.""" if installer is not None: return installer(requirement) - def __len__(self): return len(self._distmap) + def __iter__(self): + """Yield the unique project names of the available distributions""" + for key in self._distmap.keys(): + if self[key]: yield key AvailableDistributions = Environment # XXX backward compatibility + class ResourceManager: """Manage resource extraction and packages""" extraction_path = None @@ -744,7 +744,7 @@ is based on the ``PYTHON_EGG_CACHE`` environment variable, with various platform-specific fallbacks. See that routine's documentation for more details.) - + Resources are extracted to subdirectories of this path based upon information given by the ``IResourceProvider``. You may set this to a temporary directory, but then you must call ``cleanup_resources()`` to @@ -1369,7 +1369,7 @@ ) else: # scan for .egg and .egg-info in directory - for entry in os.listdir(path_item): + for entry in os.listdir(path_item): lower = entry.lower() if lower.endswith('.egg-info'): fullpath = os.path.join(path_item, entry) @@ -1637,7 +1637,7 @@ raise UnknownExtra("Can't require() without a distribution", self) map(working_set.add, working_set.resolve(self.dist.requires(self.extras),env,installer)) - + #@classmethod def parse(cls, src, dist=None): """Parse a single entry point from string `src` Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- pkg_resources.txt 14 Aug 2005 00:37:28 -0000 1.6 +++ pkg_resources.txt 14 Aug 2005 01:45:37 -0000 1.7 @@ -58,12 +58,91 @@ ====================== Listeners +working_set ``Environment`` Objects ======================= -XXX +An "environment" is a collection of ``Distribution`` objects, usually ones +that are present and potentially importable on the current platform. +``Environment`` objects are used by ``pkg_resources`` to index available +distributions during dependency resolution. + +``Environment(search_path=None, platform=get_platform(), python=PY_MAJOR)`` + Create an environment snapshot by scanning `search_path` for distributions + compatible with `platform` and `python`. `search_path` should be a + sequence of strings such as might be used on ``sys.path``. If a + `search_path` isn't supplied, ``sys.path`` is used. + + `platform` is an optional string specifying the name of the platform + that platform-specific distributions must be compatible with. If + unspecified, it defaults to the current platform. `python` is an + optional string naming the desired version of Python (e.g. ``'2.4'``); + it defaults to the currently-running version. + + You may explicitly set `platform` (and/or `python`) to ``None`` if you + wish to include *all* distributions, not just those compatible with the + running platform or Python version. + + Note that `search_path` is scanned immediately for distributions, and the + resulting ``Environment`` is a snapshot of the found distributions. It + is not automatically updated if the system's state changes due to e.g. + installation or removal of distributions. + +``__getitem__(project_name)`` + Returns a list of distributions for the given project name, ordered + from newest to oldest version. (And highest to lowest format precedence + for distributions that contain the same version of the project.) If there + are no distributions for the project, returns an empty list. + +``__iter__()`` + Yield the unique project names of the distributions in this environment. + The yielded names are always in lower case. + +``add(dist)`` + Add `dist` to the environment if it matches the platform and python version + specified at creation time, and only if the distribution hasn't already + been added. (i.e., adding the same distribution more than once is a no-op.) + +``remove(dist)`` + Remove `dist` from the environment. + +``can_add(dist)`` + Is distribution `dist` acceptable for this environment? If it's not + compatible with the platform and python version specified at creation of + the environment, False is returned. + +``best_match(req, working_set, installer=None)`` + Find distribution best matching `req` and usable on `working_set` + + This calls the ``find(req)`` method of the `working_set` to see if a + suitable distribution is already active. (This may raise + ``VersionConflict`` if an unsuitable version of the project is already + active in the specified `working_set`.) If a suitable distribution isn't + active, this method returns the newest distribution in the environment + that meets the ``Requirement`` in `req`. If no suitable distribution is + found, and `installer` is supplied, then the result of calling + the environment's ``obtain(req, installer)`` method will be returned. + +``obtain(requirement, installer=None)`` + Obtain a distro that matches requirement (e.g. via download). In the + base ``Environment`` class, this routine just returns + ``installer(requirement)``, unless `installer` is None, in which case + None is returned instead. This method is a hook that allows subclasses + to attempt other ways of obtaining a distribution before falling back + to the `installer` argument. + +``scan(search_path=None)`` + Scan `search_path` for distributions usable on `platform` + + Any distributions found are added to the environment. `search_path` should + be a sequence of strings such as might be used on ``sys.path``. If not + supplied, ``sys.path`` is used. Only distributions conforming to + the platform/python version defined at initialization are added. This + method is a shortcut for using the ``find_distributions()`` function to + find the distributions from each item in `search_path`, and then calling + ``add()`` to add each one to the environment. ``Requirement`` Objects @@ -75,18 +154,21 @@ distribution needs. -Requirements Parsing +Requirements Parsing -------------------- ``parse_requirements(s)`` - Yield ``Requirement`` objects for a string or list of lines. Each + Yield ``Requirement`` objects for a string or iterable of lines. Each requirement must start on a new line. See below for syntax. ``Requirement.parse(s)`` - Create a ``Requirement`` object from a string or list of lines. A + Create a ``Requirement`` object from a string or iterable of lines. A ``ValueError`` is raised if the string or lines do not contain a valid - requirement specifier. The syntax of a requirement specifier can be - defined in EBNF as follows:: + requirement specifier, or if they contain more than one specifier. (To + parse multiple specifiers from a string or iterable of strings, use + ``parse_requirements()`` instead.) + + The syntax of a requirement specifier can be defined in EBNF as follows:: requirement ::= project_name versionspec? extras? versionspec ::= comparison version (',' comparison version)* @@ -100,7 +182,7 @@ Tokens can be separated by whitespace, and a requirement can be continued over multiple lines using a backslash (``\\``). Line-end comments (using ``#``) are also allowed. - + Some examples of valid requirement specifiers:: FooProject >= 1.2 @@ -258,7 +340,7 @@ import baz advertised_object = baz.foo.bar - + The `extras` are an optional tuple of "extra feature" names that the distribution needs in order to provide this entry point. When the entry point is loaded, these extra features are looked up in the `dist` @@ -266,7 +348,7 @@ on sys.path; see the ``load()`` method for more details. The `extras` argument is only meaningful if `dist` is specified. `dist` must be a ``Distribution`` instance. - + ``EntryPoint.parse(src, dist=None)`` (classmethod) Parse a single entry point from string `src` @@ -324,6 +406,10 @@ taking a ``Requirement`` instance and returning a matching importable ``Distribution`` instance or None. +``__str__()`` + The string form of an ``EntryPoint`` is a string that could be passed to + ``EntryPoint.parse()`` to yield an equivalent ``EntryPoint``. + ``Distribution`` Objects ======================== Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- setuptools.txt 7 Aug 2005 01:03:35 -0000 1.30 +++ setuptools.txt 14 Aug 2005 01:45:37 -0000 1.31 @@ -1852,7 +1852,11 @@ that tells it to only yield distributions whose location is the passed-in path. (It defaults to False, so that the default behavior is unchanged.) - * ``AvailableDistributions`` is now called ``Environment`` + * ``AvailableDistributions`` is now called ``Environment``, and the + ``get()``, ``__len__()``, and ``__contains__()`` methods were removed, + because they weren't particularly useful. ``__getitem__()`` no longer + raises ``KeyError``; it just returns an empty list if there are no + distributions for the named project. * The ``resolve()`` method of ``Environment`` is now a method of ``WorkingSet`` instead, and the ``best_match()`` method now uses a working From pje at users.sourceforge.net Sun Aug 14 08:03:32 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 08:03:32 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.66, 1.67 Message-ID: <20050814060332.66ED31E4019@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11496 Modified Files: pkg_resources.py Log Message: Make "run_script" a method of WorkingSet objects, thereby removing a global coupling. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.66 retrieving revision 1.67 diff -u -d -r1.66 -r1.67 --- pkg_resources.py 14 Aug 2005 01:45:37 -0000 1.66 +++ pkg_resources.py 14 Aug 2005 06:03:20 -0000 1.67 @@ -398,13 +398,13 @@ elif name in entries: yield entries[name] - - - - - - - + def run_script(self, requires, script_name): + """Locate distribution for `requires` and run `script_name` script""" + ns = sys._getframe(1).f_globals + name = ns['__name__'] + ns.clear() + ns['__name__'] = name + self.require(requires)[0].run_script(script_name, ns) @@ -2147,6 +2147,8 @@ require = working_set.require iter_entry_points = working_set.iter_entry_points add_activation_listener = working_set.subscribe +run_script = working_set.run_script +run_main = run_script # backward compatibility # Activate all distributions already on sys.path, and ensure that # all distributions added to the working set in the future (e.g. by @@ -2169,5 +2171,3 @@ - - From pje at users.sourceforge.net Sun Aug 14 08:08:47 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 08:08:47 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.txt, 1.7, 1.8 Message-ID: <20050814060847.D31BA1E4019@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12011 Modified Files: pkg_resources.txt Log Message: Documentation for namespace packages, working sets, and supporting custom PEP 302 importers. Once the "Distribution" class is documented, this will be a complete API reference for pkg_resources. Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- pkg_resources.txt 14 Aug 2005 01:45:37 -0000 1.7 +++ pkg_resources.txt 14 Aug 2005 06:08:37 -0000 1.8 @@ -46,19 +46,231 @@ API Reference ------------- - 'require', 'run_script', - Namespace Package Support ========================= -declare_namespace, fixup_namespace_packages, register_namespace_handler +A namespace package is a package that only contains other packages and modules, +with no direct contents of its own. Such packages can be split across +multiple, separately-packaged distributions. Normally, you do not need to use +the namespace package APIs directly; instead you should supply the +``namespace_packages`` argument to ``setup()`` in your project's ``setup.py``. +See the `setuptools documentation on namespace packages`_ for more information. + +However, if for some reason you need to manipulate namespace packages or +directly alter ``sys.path`` at runtime, you may find these APIs useful: + +``declare_namespace(name)`` + Declare that the dotted package name `name` is a "namespace package" whose + contained packages and modules may be spread across multiple distributions. + The named package's ``__path__`` will be extended to include the + corresponding package in all distributions on ``sys.path`` that contain a + package of that name. (More precisely, if an importer's + ``find_module(name)`` returns a loader, then it will also be searched for + the package's contents.) Whenever a Distribution's ``to_install()`` method + is invoked, it checks for the presence of namespace packages and updates + their ``__path__`` contents accordingly. + +``fixup_namespace_packages(path_item)`` + Declare that `path_item` is a newly added item on ``sys.path`` that may + need to be used to update existing namespace packages. Ordinarily, this is + called for you when an egg is automatically added to ``sys.path``, but if + your application modifies ``sys.path`` to include locations that may + contain portions of a namespace package, you will need to call this + function to ensure they are added to the existing namespace packages. + +Although by default ``pkg_resources`` only supports namespace packages for +filesystem and zip importers, you can extend its support to other "importers" +compatible with PEP 302 using the ``register_namespace_handler()`` function. +See the section below on `Supporting Custom Importers`_ for details. + +.. _setuptools documentation on namespace packages: http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages ``WorkingSet`` Objects ====================== -Listeners -working_set +The ``WorkingSet`` class provides access to a collection of "active" +distributions. In general, there is only one meaningful ``WorkingSet`` +instance: the one that represents the distributions that are currently active +on ``sys.path``. This global instance is available under the name +``working_set`` in the ``pkg_resources`` module. However, specialized +tools may wish to manipulate working sets that don't correspond to +``sys.path``, and therefore may wish to create other ``WorkingSet`` instances. + +It's important to note that the global ``working_set`` object is initialized +from ``sys.path`` when ``pkg_resources`` is first imported, but is only updated +if you do all future ``sys.path`` manipulation via ``pkg_resources`` APIs. If +you manually modify ``sys.path``, you must invoke the appropriate methods on +the ``working_set`` instance to keep it in sync. Unfortunately, Python does +not provide any way to detect arbitrary changes to a list object like +``sys.path``, so ``pkg_resources`` cannot automatically update the +``working_set`` based on changes to ``sys.path``. + +``WorkingSet(entries=None)`` + Create a ``WorkingSet`` from an iterable of path entries. If `entries` + is not supplied, it defaults to the value of ``sys.path`` at the time + the constructor is called. + + Note that you will not normally construct ``WorkingSet`` instances + yourbut instead you will implicitly or explicitly use the global + ``working_set`` instance. For the most part, the ``pkg_resources`` API + is designed so that the ``working_set`` is used by default, such that you + don't have to explicitly refer to it most of the time. + + +Basic ``WorkingSet`` Methods +---------------------------- + +The following methods of ``WorkingSet`` objects are also available as module- +level functions in ``pkg_resources`` that apply to the default ``working_set`` +instance. Thus, you can use e.g. ``pkg_resources.require()`` as an +abbreviation for ``pkg_resources.working_set.require()``: + + +``require(*requirements)`` + Ensure that distributions matching `requirements` are activated + + `requirements` must be a string or a (possibly-nested) sequence + thereof, specifying the distributions and versions required. The + return value is a sequence of the distributions that needed to be + activated to fulfill the requirements; all relevant distributions are + included, even if they were already activated in this working set. + + For the syntax of requirement specifiers, see the section below on + `Requirements Parsing`_. + + Note: in general, it should not be necessary for you to call this method + directly. It's intended more for use in quick-and-dirty scripting and + interactive interpreter hacking than for production use. If you're creating + an actual library or application, it's strongly recommended that you create + a "setup.py" script using ``setuptools``, and declare all your requirements + there. That way, tools like EasyInstall can automatically detect what + requirements your package has, and deal with them accordingly. + +``run_script(requires, script_name)`` + Locate distribution specified by `requires` and run its `script_name` + script. `requires` must be a string containing a requirement specifier. + (See `Requirements Parsing`_ below for the syntax.) + + The script, if found, will be executed in *the caller's globals*. That's + because this method is intended to be called from wrapper scripts that + act as a proxy for the "real" scripts in a distribution. A wrapper script + usually doesn't need to do anything but invoke this function with the + correct arguments. + + If you need more control over the script execution environment, you + probably want to use the ``run_script()`` method of a ``Distribution`` + object's `Metadata API`_ instead. + +``iter_entry_points(group, name=None)`` + Yield entry point objects from `group` matching `name` + + If `name` is None, yields all entry points in `group` from all + distributions in the working set, otherwise only ones matching both + `group` and `name` are yielded. Entry points are yielded from the active + distributions in the order that the distributions appear in the working + set. (For the global ``working_set``, this should be the same as the order + that they are listed in ``sys.path``.) Note that within the entry points + advertised by an individual distribution, there is no particular ordering. + + Please see the section below on `Entry Points`_ for more information. + + +``WorkingSet`` Methods and Attributes +------------------------------------- + +These methods are used to query or manipulate the contents of a specific +working set, so they must be explicitly invoked on a particular ``WorkingSet`` +instance: + +``add_entry(entry)`` + Add a path item to the ``entries``, finding any distributions on it. You + should use this when you add additional items to ``sys.path`` and you want + the global ``working_set`` to reflect the change. This method is also + called by the ``WorkingSet()`` constructor during initialization. + + This method uses ``find_distributions(entry,False)`` to find distributions + corresponding to the path entry, and then ``add()`` them. `entry` is + always appended to the ``entries`` attribute, even if it is already + present, however. (This is because ``sys.path`` can contain the same value + more than once, and the ``entries`` attribute should be able to reflect + this.) + +``__contains__(dist)`` + True if `dist` is active in this ``WorkingSet``. Note that only one + distribution for a given project can be active in a given ``WorkingSet``. + +``__iter__()`` + Yield distributions for non-duplicate projects in the working set. + The yield order is the order in which the items' path entries were + added to the working set. + +``find(req)`` + Find a distribution matching `req` (a ``Requirement`` instance). + If there is an active distribution for the requested project, this + returns it, as long as it meets the version requirement specified by + `req`. But, if there is an active distribution for the project and it + does *not* meet the `req` requirement, ``VersionConflict`` is raised. + If there is no active distribution for the requested project, ``None`` + is returned. + +``resolve(requirements, env=None, installer=None)`` + List all distributions needed to (recursively) meet `requirements` + + `requirements` must be a sequence of ``Requirement`` objects. `env`, + if supplied, should be an ``Environment`` instance. If + not supplied, an ``Environment`` is created from the working set's + ``entries``. `installer`, if supplied, will be invoked with each + requirement that cannot be met by an already-installed distribution; it + should return a ``Distribution`` or ``None``. (See the ``obtain()`` method + of `Environment Objects`_, below, for more information on the `installer` + argument.) + +``add(dist, entry=None)`` + Add `dist` to working set, associated with `entry` + + If `entry` is unspecified, it defaults to ``dist.location``. On exit from + this routine, `entry` is added to the end of the working set's ``.entries`` + (if it wasn't already present). + + `dist` is only added to the working set if it's for a project that + doesn't already have a distribution active in the set. If it's + successfully added, any callbacks registered with the ``subscribe()`` + method will be called. (See `Receiving Change Notifications`_, below.) + + Note: ``add()`` is automatically called for you by the ``require()`` + method, so you don't normally need to use this method directly. + +``entries`` + This attribute represents a "shadow" ``sys.path``, primarily useful for + debugging. If you are experiencing import problems, you should check + the global ``working_set`` object's ``entries`` against ``sys.path``, to + ensure that they match. If they do not, then some part of your program + is manipulating ``sys.path`` without updating the ``working_set`` + accordingly. IMPORTANT NOTE: do not directly manipulate this attribute! + Setting it equal to ``sys.path`` will not fix your problem, any more than + putting black tape over an "engine warning" light will fix your car! If + this attribute is out of sync with ``sys.path``, it's merely an *indicator* + of the problem, not the cause of it. + + +Receiving Change Notifications +------------------------------ + +Extensible applications and frameworks may need to receive notification when +a new distribution (such as a plug-in component) has been added to a working +set. This is what the ``subscribe()`` method and ``add_activation_listener()`` +function are for. + +``subscribe(callback)`` + Invoke ``callback(distribution)`` once for each active distribution that is + in the set now, or gets added later. Because the callback is invoked for + already-active distributions, you do not need to loop over the working set + yourself to deal with the existing items; just register the callback and + be prepared for the fact that it will be called immediately by this method. + +``pkg_resources.add_activation_listener()`` is an alternate spelling of +``pkg_resources.working_set.subscribe()``. ``Environment`` Objects @@ -317,7 +529,7 @@ ``EntryPoint`` instance in that group. ``iter_entry_points(group, name=None)`` - Yield entry point objects from `group` matching `name` + Yield entry point objects from `group` matching `name`. If `name` is None, yields all entry points in `group` from all distributions in the working set on sys.path, otherwise only ones matching @@ -326,6 +538,9 @@ sys.path. (Within entry points for a particular distribution, however, there is no particular ordering.) + (This API is actually a method of the global ``working_set`` object; see + the section above on `Basic WorkingSet Methods`_ for more information.) + Creating and Parsing -------------------- @@ -411,16 +626,37 @@ ``EntryPoint.parse()`` to yield an equivalent ``EntryPoint``. + ``Distribution`` Objects ======================== -Factories: get_provider, get_distribution, find_distributions; see also +Factories: see also WorkingSet and Environment APIs. register_finder register_loader_type 'load_entry_point', 'get_entry_map', 'get_entry_info' +Getting or Creating Distributions +--------------------------------- + +``find_distributions(path_item, only=False)`` + Yield distributions accessible via `path_item`. If `only` is true, yield + only distributions whose ``location`` is equal to `path_item`. In other + words, if `only` is true, this yields any distributions that would be + importable if `path_item` were on ``sys.path``. If `only` is false, this + also yields distributions that are "in" or "under" `path_item`, but would + not be importable unless their locations were also added to ``sys.path``. + +``get_distribution(dist_spec)`` + Return a ``Distribution`` object for a given ``Requirement`` or string. + If `dist_spec` is already a ``Distribution`` instance, it is returned. + If it is a ``Requirement`` object or a string that can be parsed into one, + it is used to locate and activate a matching distribution, which is then + returned. + + + ``ResourceManager`` API ======================= @@ -525,14 +761,16 @@ details.) Resources are extracted to subdirectories of this path based upon - information given by the ``IResourceProvider``. You may set this to a + information given by the resource provider. You may set this to a temporary directory, but then you must call ``cleanup_resources()`` to delete the extracted files when done. There is no guarantee that - ``cleanup_resources()`` will be able to remove all extracted files. + ``cleanup_resources()`` will be able to remove all extracted files. (On + Windows, for example, you can't unlink .pyd or .dll files that are still + in use.) - (Note: you may not change the extraction path for a given resource + Note that you may not change the extraction path for a given resource manager once resources have been extracted, unless you first call - ``cleanup_resources()``.) + ``cleanup_resources()``. ``cleanup_resources(force=False)`` Delete all extracted resource files and directories, returning a list @@ -550,7 +788,7 @@ If you are implementing an ``IResourceProvider`` and/or ``IMetadataProvider`` for a new distribution archive format, you may need to use the following -``ResourceManager`` methods to co-ordinate extraction of resources to the +``IResourceManager`` methods to co-ordinate extraction of resources to the filesystem. If you're not implementing an archive format, however, you have no need to use these methods. Unlike the other methods listed above, they are *not* available as top-level functions tied to the global ``ResourceManager``; @@ -592,12 +830,11 @@ resource paths. The metadata API is provided by objects implementing the ``IMetadataProvider`` -interface. ``Distribution`` objects created with a ``metadata`` setting -implement this interface, as do objects returned by the ``get_provider()`` -function: +or ``IResourceProvider`` interfaces. ``Distribution`` objects implement this +interface, as do objects returned by the ``get_provider()`` function: ``get_provider(package_or_requirement)`` - If a package name is supplied, return an ``IMetadataProvider`` for the + If a package name is supplied, return an ``IResourceProvider`` for the package. If a ``Requirement`` is supplied, resolve it by returning a ``Distribution`` from the current working set (searching the current ``Environment`` if necessary and adding the newly found ``Distribution`` @@ -606,12 +843,15 @@ Note also that if you supply a package name, and the package is not part of a pluggable distribution (i.e., it has no metadata), then you will still - get an ``IMetadataProvider`` object, but it will just be an empty one that - answers ``False`` when asked if any given metadata resource file or - directory exists. + get an ``IResourceProvider`` object, but it will return ``False`` when + asked if any metadata files or directories exist. -The methods provided by ``IMetadataProvider`` (and ``Distribution`` objects -with a ``metadata`` attribute set) are: + +``IMetadataProvider`` Methods +----------------------------- + +The methods provided by objects (such as ``Distribution`` instances) that +implement the ``IMetadataProvider`` or ``IResourceProvider`` interfaces are: ``has_metadata(name)`` Does the named metadata resource exist? @@ -668,6 +908,150 @@ was requested from. +Supporting Custom Importers +=========================== + +By default, ``pkg_resources`` supports normal filesystem imports, and +``zipimport`` importers. If you wish to use the ``pkg_resources`` features +with other (PEP 302-compatible) importers or module loaders, you may need to +register various handlers and support functions using these APIs: + +``register_finder(importer_type, distribution_finder)`` + Register `distribution_finder` to find distributions in ``sys.path`` items. + `importer_type` is the type or class of a PEP 302 "Importer" (``sys.path`` + item handler), and `distribution_finder` is a callable that, when passed a + path item, the importer instance, and an `only` flag, yields + ``Distribution`` instances found under that path item. (The `only` flag, + if true, means the finder should yield only ``Distribution`` objects whose + ``location`` is equal to the path item provided.) + + See the source of the ``pkg_resources.find_on_path`` function for an + example finder function. + +``register_loader_type(loader_type, provider_factory)`` + Register `provider_factory` to make ``IResourceProvider`` objects for + `loader_type`. `loader_type` is the type or class of a PEP 302 + ``module.__loader__``, and `provider_factory` is a function that, when + passed a module object, returns an `IResourceProvider`_ for that module, + allowing it to be used with the `ResourceManager API`_. + +``register_namespace_handler(importer_type, namespace_handler)`` + Register `namespace_handler` to declare namespace packages for the given + `importer_type`. `importer_type` is the type or class of a PEP 302 + "importer" (sys.path item handler), and `namespace_handler` is a callable + with a signature like this:: + + def namespace_handler(importer, path_entry, moduleName, module): + # return a path_entry to use for child packages + + Namespace handlers are only called if the relevant importer object has + already agreed that it can handle the relevant path item. The handler + should only return a subpath if the module ``__path__`` does not already + contain an equivalent subpath. Otherwise, it should return None. + + For an example namespace handler, see the source of the + ``pkg_resources.file_ns_handler`` function, which is used for both zipfile + importing and regular importing. + + +IResourceProvider +----------------- + +``IResourceProvider`` is an abstract class that documents what methods are +required of objects returned by a `provider_factory` registered with +``register_loader_type()``. ``IResourceProvider`` is a subclass of +``IMetadataProvider``, so objects that implement this interface must also +implement all of the `IMetadataProvider Methods`_ as well as the methods +shown here. The `manager` argument to the methods below must be an object +that supports the full `ResourceManager API`_ documented above. + +``get_resource_filename(manager, resource_name)`` + Return a true filesystem path for `resource_name`, co-ordinating the + extraction with `manager`, if the resource must be unpacked to the + filesystem. + +``get_resource_stream(manager, resource_name)`` + Return a readable file-like object for `resource_name`. + +``get_resource_string(manager, resource_name)`` + Return a string containing the contents of `resource_name`. + +``has_resource(resource_name)`` + Does the package contain the named resource? + +``resource_isdir(resource_name)`` + Is the named resource a directory? Return a false value if the resource + does not exist or is not a directory. + +``resource_listdir(resource_name)`` + Return a list of the contents of the resource directory, ala + ``os.listdir()``. Requesting the contents of a non-existent directory may + raise an exception. + +Note, by the way, that your provider classes need not (and should not) subclass +``IResourceProvider`` or ``IMetadataProvider``! These classes exist solely +for documentation purposes and do not provide any useful implementation code. +You may instead wish to subclass one of the `built-in resource providers`_. + + +Built-in Resource Providers +--------------------------- + +``pkg_resources`` includes several provider classes, whose inheritance +tree looks like this:: + + NullProvider + EggProvider + DefaultProvider + PathMetadata + ZipProvider + EggMetadata + EmptyProvider + + +``NullProvider`` + This provider class is just an abstract base that provides for common + provider behaviors (such as running scripts), given a definition for just + a few abstract methods. + +``EggProvider`` + This provider class adds in some egg-specific features that are common + to zipped and unzipped eggs. + +``DefaultProvider`` + This provider class is used for unpacked eggs and "plain old Python" + filesystem modules. + +``ZipProvider`` + This provider class is used for all zipped modules, whether they are eggs + or not. + +``EmptyProvider`` + This provider class always returns answers consistent with a provider that + has no metadata or resources. ``Distribution`` objects created without + a ``metadata`` argument use an instance of this provider class instead. + Since all ``EmptyProvider`` instances are equivalent, there is no need + to have more than one instance. ``pkg_resources`` therefore creates a + global instance of this class under the name ``empty_provider``, and you + may use it if you have need of an ``EmptyProvider`` instance. + +``PathMetadata(path, egg_info)`` + Create an ``IResourceProvider`` for a filesystem-based distribution, where + `path` is the filesystem location of the importable modules, and `egg_info` + is the filesystem location of the distribution's metadata directory. + `egg_info` should usually be the ``EGG-INFO`` subdirectory of `path` for an + "unpacked egg", and a ``ProjectName.egg-info`` subdirectory of `path` for + a "development egg". However, other uses are possible for custom purposes. + +``EggMetadata(zipimporter)`` + Create an ``IResourceProvider`` for a zipfile-based distribution. The + `zipimporter` should be a ``zipimport.zipimporter`` instance, and may + represent a "basket" (a zipfile containing multiple ".egg" subdirectories) + a specific egg *within* a basket, or a zipfile egg (where the zipfile + itself is a ".egg"). It can also be a combination, such as a zipfile egg + that also contains other eggs. + + Utility Functions ================= From pje at users.sourceforge.net Sun Aug 14 19:30:26 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 19:30:26 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.67, 1.68 pkg_resources.txt, 1.8, 1.9 Message-ID: <20050814173026.55E7B1E401F@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18452 Modified Files: pkg_resources.py pkg_resources.txt Log Message: Document "Distribution" objects. Now the API reference is complete, and I just need to write the Overview and Developer's Guide sections so that most people won't have to actually *read* the API reference. :) Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.67 retrieving revision 1.68 diff -u -d -r1.67 -r1.68 --- pkg_resources.py 14 Aug 2005 06:03:20 -0000 1.67 +++ pkg_resources.py 14 Aug 2005 17:30:15 -0000 1.68 @@ -1881,9 +1881,9 @@ from_filename = classmethod(from_filename) def as_requirement(self): + """Return a ``Requirement`` that matches this distribution exactly""" return Requirement.parse('%s==%s' % (self.project_name, self.version)) - def load_entry_point(self, group, name): """Return the `name` entry point of `group` or raise ImportError""" ep = self.get_entry_info(group,name) Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- pkg_resources.txt 14 Aug 2005 06:08:37 -0000 1.8 +++ pkg_resources.txt 14 Aug 2005 17:30:15 -0000 1.9 @@ -626,20 +626,25 @@ ``EntryPoint.parse()`` to yield an equivalent ``EntryPoint``. - ``Distribution`` Objects ======================== -Factories: see also -WorkingSet and Environment APIs. +``Distribution`` objects represent collections of Python code that may or may +not be importable, and may or may not have metadata and resources associated +with them. Their metadata may include information such as what other projects +the distribution depends on, what entry points the distribution advertises, and +so on. -register_finder -register_loader_type -'load_entry_point', 'get_entry_map', 'get_entry_info' Getting or Creating Distributions --------------------------------- +Most commonly, you'll obtain ``Distribution`` objects from a ``WorkingSet`` or +an ``Environment``. (See the sections above on `WorkingSet Objects`_ and +`Environment Objects`_, which are containers for active distributions and +available distributions, respectively.) You can also obtain ``Distribution`` +objects from one of these high-level APIs: + ``find_distributions(path_item, only=False)`` Yield distributions accessible via `path_item`. If `only` is true, yield only distributions whose ``location`` is equal to `path_item`. In other @@ -655,7 +660,191 @@ it is used to locate and activate a matching distribution, which is then returned. +However, if you're creating specialized tools for working with distributions, +or creating a new distribution format, you may also need to create +``Distribution`` objects directly, using one of the three constructors below. + +These constructors all take an optional `metadata` argument, which is used to +access any resources or metadata associated with the distribution. `metadata` +must be an object that implements the ``IResourceProvider`` interface, or None. +If it is None, an ``EmptyProvider`` is used instead. ``Distribution`` objects +implement both the `IResourceProvider`_ and `IMetadataProvider Methods`_ by +delegating them to the `metadata` object. + +``Distribution.from_location(location, basename, metadata=None)`` (classmethod) + Create a distribution for `location`, which must be a string such as a + URL, filename, or other string that might be used on ``sys.path``. + `basename` is a string naming the distribution, like ``Foo-1.2-py2.4.egg``. + If `basename` ends with ``.egg``, then the project's name, version, python + version and platform are extracted from the filename and used to set those + properties of the created distribution. + +``Distribution.from_filename(filename, metadata=None)`` (classmethod) + Create a distribution by parsing a local filename. This is a shorter way + of saying ``Distribution.from_location(normalize_path(filename), + os.path.basename(filename), metadata)``. In other words, it creates a + distribution whose location is the normalize form of the filename, parsing + name and version information from the base portion of the filename. + +``Distribution(location,metadata,project_name,version,py_version,platform,precedence)`` + Create a distribution by setting its properties. All arguments are + optional and default to None, except for `py_version` (which defaults to + the current Python version) and `precedence` (which defaults to + ``EGG_DIST``; for more details see ``precedence`` under `Distribution + Attributes`_ below). Note that it's usually easier to use the + ``from_filename()`` or ``from_location()`` constructors than to specify + all these arguments individually. + + +``Distribution`` Attributes +--------------------------- + +location + A string indicating the distribution's location. For an importable + distribution, this is the string that would be added to ``sys.path`` to + make it actively importable. For non-importable distributions, this is + simply a filename, URL, or other way of locating the distribution. + +project_name + A string, naming the project that this distribution is for. Project names + are defined by a project's setup script, and they are used to identify + projects on PyPI. When a ``Distribution`` is constructed, the + `project_name` argument is passed through the ``safe_name()`` utility + function to filter out any unacceptable characters. + +key + ``dist.key`` is short for ``dist.project_name.lower()``. It's used for + case-insensitive comparison and indexing of distributions by project name. + +version + A string denoting what release of the project this distribution contains. + When a ``Distribution`` is constructed, the `version` argument is passed + through the ``safe_version()`` utility function to filter out any + unacceptable characters. If no `version` is specified at construction + time, then attempting to access this attribute later will cause the + ``Distribution`` to try to discover its version by reading its ``PKG-INFO`` + metadata file. If ``PKG-INFO`` is unavailable or can't be parsed, + ``ValueError`` is raised. + +parsed_version + The ``parsed_version`` is a tuple representing a "parsed" form of the + distribution's ``version``. ``dist.parsed_version`` is a shortcut for + calling ``parse_version(dist.version)``. It is used to compare or sort + distributions by version. (See the `Parsing Utilities`_ section below for + more information on the ``parse_version()`` function.) Note that accessing + ``parsed_version`` may result in a ``ValueError`` if the ``Distribution`` + was constructed without a `version` and without `metadata` capable of + supplying the missing version info. + +py_version + The major/minor Python version the distribution supports, as a string. + For example, "2.3" or "2.4". The default is the current version of Python. + +platform + A string representing the platform the distribution is intended for, or + ``None`` if the distribution is "pure Python" and therefore cross-platform. + See `Platform Utilities`_ below for more information on platform strings. + +precedence + A distribution's ``precedence`` is used to determine the relative order of + two distributions that have the same ``project_name`` and + ``parsed_version``. The default precedence is ``pkg_resources.EGG_DIST``, + which is the highest (i.e. most preferred) precedence. The full list + of predefined precedences, from most preferred to least preferred, is: + ``EGG_DIST``, ``BINARY_DIST``, ``SOURCE_DIST``, and ``CHECKOUT_DIST``. + Normally, precedences other than ``EGG_DIST`` are used only by the + ``setuptools.package_index`` module, when sorting distributions found in a + package index to determine their suitability for installation. + + +``Distribution`` Methods +------------------------ + +``activate(path=None)`` + Ensure distribution is importable on `path`. If `path` is None, + ``sys.path`` is used instead. This ensures that the distribution's + ``location`` is in the `path` list, and it also performs any necessary + namespace package fixups or declarations. (That is, if the distribution + contains namespace packages, this method ensures that they are declared, + and that the distribution's contents for those namespace packages are + merged with the contents provided by any other active distributions. See + the section above on `Namespace Package Support`_ for more information.) + + ``pkg_resources`` adds a notification callback to the global ``working_set`` + that ensures this method is called whenever a distribution is added to it. + Therefore, you should not normally need to explicitly call this method. + (Note that this means that namespace packages on ``sys.path`` are always + imported as soon as ``pkg_resources`` is, which is another reason why + namespace packages should not contain any code or import statements.) + +``as_requirement()`` + Return a ``Requirement`` instance that matches this distribution's project + name and version. + +``requires(extras=())`` + List the ``Requirement`` objects that specify this distribution's + dependencies. If `extras` is specified, it should be a sequence of names + of "extras" defined by the distribution, and the list returned will then + include any dependencies needed to support the named "extras". + +``egg_name()`` + Return what this distribution's standard filename should be, not including + the ".egg" extension. For example, a distribution for project "Foo" + version 1.2 that runs on Python 2.3 for Windows would have an ``egg_name()`` + of ``Foo-1.2-py2.3-win32``. Any dashes in the name or version are + converted to underscores. (``Distribution.from_location()`` will convert + them back when parsing a ".egg" file name.) + +``__cmp__(other)``, ``__hash__()`` + Distribution objects are hashed and compared on the basis of their parsed + version and precedence, followed by their key (lowercase project name), + location, Python version, and platform. + +The following methods are used to access ``EntryPoint`` objects advertised +by the distribution. See the section above on `Entry Points`_ for more +detailed information about these operations: + +``get_entry_info(group, name)`` + Return the ``EntryPoint`` object for `group` and `name`, or None if no + such point is advertised by this distribution. + +``get_entry_map(group=None)`` + Return the entry point map for `group`. If `group` is None, return + a dictionary mapping group names to entry point maps for all groups. + (An entry point map is a dictionary of entry point names to ``EntryPoint`` + objects.) + +``load_entry_point(group, name)`` + Short for ``get_entry_info(group, name).load()``. Returns the object + advertised by the named entry point, or raises ``ImportError`` if + the entry point isn't advertised by this distribution, or there is some + other import problem. + +In addition to the above methods, ``Distribution`` objects also implement all +of the `IResourceProvider`_ and `IMetadataProvider Methods`_ (which are +documented in later sections): + +* ``has_metadata(name)`` +* ``metadata_isdir(name)`` +* ``metadata_listdir(name)`` +* ``get_metadata(name)`` +* ``get_metadata_lines(name)`` +* ``run_script(script_name, namespace)`` +* ``get_resource_filename(manager, resource_name)`` +* ``get_resource_stream(manager, resource_name)`` +* ``get_resource_string(manager, resource_name)`` +* ``has_resource(resource_name)`` +* ``resource_isdir(resource_name)`` +* ``resource_listdir(resource_name)`` + +If the distribution was created with a `metadata` argument, these resource and +metadata access methods are all delegated to that `metadata` provider. +Otherwise, they are delegated to an ``EmptyProvider``, so that the distribution +will appear to have no resources or metadata. This delegation approach is used +so that supporting custom importers or new distribution formats can be done +simply by creating an appropriate `IResourceProvider`_ implementation; see the +section below on `Supporting Custom Importers`_ for more details. ``ResourceManager`` API @@ -1212,4 +1401,3 @@ reflect the platform's case-sensitivity, so there is always the possibility of two apparently-different paths being equal on such platforms. - From pje at users.sourceforge.net Sun Aug 14 19:48:17 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 19:48:17 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.txt, 1.9, 1.10 Message-ID: <20050814174817.23E6C1E4020@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21566 Modified Files: pkg_resources.txt Log Message: Fix some reST formatting problems and other issues discovered during a quick review. Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- pkg_resources.txt 14 Aug 2005 17:30:15 -0000 1.9 +++ pkg_resources.txt 14 Aug 2005 17:48:07 -0000 1.10 @@ -18,13 +18,15 @@ Overview -------- -XXX +XXX TBD ----------------- Developer's Guide ----------------- +This section isn't written yet. Currently planned topics include:: + Accessing Resources Finding and Activating Package Distributions get_provider() @@ -519,7 +521,7 @@ the specified distribution. Returns ``None`` if the distribution has not advertised a matching entry point. -``get_entry_map(dist, group=None) +``get_entry_map(dist, group=None)`` Return the distribution's entry point map for `group`, or the full entry map for the distribution. This function always returns a dictionary, even if the distribution advertises no entry points. If `group` is given, @@ -876,7 +878,10 @@ importable (i.e., be in a distribution or directory on ``sys.path``), and the `resource_name` argument is interpreted relative to the named package. (Note that if a module name is used, then the resource name is relative to the -package immediately containing the named module.) +package immediately containing the named module. Also, you should not use use +a namespace package name, because a namespace package can be spread across +multiple distributions, and is therefore ambiguous as to which distribution +should be searched for the resource.) If it is a ``Requirement``, then the requirement is automatically resolved (searching the current ``Environment`` if necessary) and a matching @@ -888,7 +893,7 @@ distribution. Note that resource names must be ``/``-separated paths and cannot be absolute -(i.e. no leading ``/``) or contain relative names like ``..``. Do *not* use +(i.e. no leading ``/``) or contain relative names like ``".."``. Do *not* use ``os.path`` routines to manipulate resource paths, as they are *not* filesystem paths. @@ -1186,8 +1191,8 @@ Built-in Resource Providers --------------------------- -``pkg_resources`` includes several provider classes, whose inheritance -tree looks like this:: +``pkg_resources`` includes several provider classes that are automatically used +where appropriate. Their inheritance tree looks like this:: NullProvider EggProvider From pje at users.sourceforge.net Sun Aug 14 22:16:38 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 22:16:38 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools dist.py, 1.19, 1.20 Message-ID: <20050814201638.DAA5D1E4022@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16098/setuptools Modified Files: dist.py Log Message: Allow distributing an empty namespace package. Index: dist.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/dist.py,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- dist.py 6 Aug 2005 19:29:49 -0000 1.19 +++ dist.py 14 Aug 2005 20:16:28 -0000 1.20 @@ -54,7 +54,7 @@ for nsp in value: for name in dist.iter_distribution_names(): - if name.startswith(nsp+'.'): break + if name==nsp or name.startswith(nsp+'.'): break else: raise DistutilsSetupError( "Distribution contains no modules or packages for " + From pje at users.sourceforge.net Sun Aug 14 22:19:06 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 22:19:06 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools dist.py, 1.20, 1.21 Message-ID: <20050814201906.1FA451E4022@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16344/setuptools Modified Files: dist.py Log Message: On second thought, don't. :( Walter Doerwald's situation isn't really compatible with namespace packages, even if I do manage to hack up a way to make it work. Index: dist.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/dist.py,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- dist.py 14 Aug 2005 20:16:28 -0000 1.20 +++ dist.py 14 Aug 2005 20:18:56 -0000 1.21 @@ -54,7 +54,7 @@ for nsp in value: for name in dist.iter_distribution_names(): - if name==nsp or name.startswith(nsp+'.'): break + if name.startswith(nsp+'.'): break else: raise DistutilsSetupError( "Distribution contains no modules or packages for " + From pje at users.sourceforge.net Sun Aug 14 22:46:59 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 22:46:59 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command easy_install.py, 1.21, 1.22 Message-ID: <20050814204659.331EA1E4022@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21106/setuptools/command Modified Files: easy_install.py Log Message: Fix a bug introduced by removing the Environment.get() method. Index: easy_install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/easy_install.py,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- easy_install.py 11 Aug 2005 00:37:37 -0000 1.21 +++ easy_install.py 14 Aug 2005 20:46:49 -0000 1.22 @@ -822,7 +822,7 @@ if self.pth_file is None: return - for d in self.pth_file.get(dist.key,()): # drop old entries + for d in self.pth_file[dist.key]: # drop old entries if self.multi_version or d.location != dist.location: log.info("Removing %s from easy-install.pth file", d) self.pth_file.remove(d) From pje at users.sourceforge.net Sun Aug 14 23:01:43 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 23:01:43 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.68, 1.69 Message-ID: <20050814210143.668261E4024@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22976 Modified Files: pkg_resources.py Log Message: Add experimental support for merging non-empty namespace packages. This lets you have one distribution containing a non-empty __init__.py for the package, as long as you call 'declare_namespace()' from that __init__.py and all other __init__.py files for the namespace package, and do *not* declare it as a namespace package in setup() (so that it won't be automatically imported if it's on sys.path, the way empty namespace packages are.) Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.68 retrieving revision 1.69 diff -u -d -r1.68 -r1.69 --- pkg_resources.py 14 Aug 2005 17:30:15 -0000 1.68 +++ pkg_resources.py 14 Aug 2005 21:01:33 -0000 1.69 @@ -13,7 +13,7 @@ method. """ -import sys, os, zipimport, time, re, imp +import sys, os, zipimport, time, re, imp, new from sets import ImmutableSet @@ -1412,7 +1412,6 @@ """ _namespace_handlers[importer_type] = namespace_handler - def _handle_ns(packageName, path_item): """Ensure that named package includes a subpath of path_item (if needed)""" importer = get_importer(path_item) @@ -1421,18 +1420,19 @@ loader = importer.find_module(packageName) if loader is None: return None - - module = sys.modules.get(packageName) or loader.load_module(packageName) - if not hasattr(module,'__path__'): + module = sys.modules.get(packageName) + if module is None: + module = sys.modules[packageName] = new.module(packageName) + module.__path__ = [] + elif not hasattr(module,'__path__'): raise TypeError("Not a package:", packageName) - handler = _find_adapter(_namespace_handlers, importer) subpath = handler(importer,path_item,packageName,module) if subpath is not None: module.__path__.append(subpath) + loader.load_module(packageName) return subpath - def declare_namespace(packageName): """Declare that package 'packageName' is a namespace package""" @@ -1451,16 +1451,16 @@ except AttributeError: raise TypeError("Not a package:", parent) - for path_item in path: - # Ensure all the parent's path items are reflected in the child, - # if they apply - _handle_ns(packageName, path_item) - # Track what packages are namespaces, so when new path items are added, # they can be updated _namespace_packages.setdefault(parent,[]).append(packageName) _namespace_packages.setdefault(packageName,[]) + for path_item in path: + # Ensure all the parent's path items are reflected in the child, + # if they apply + _handle_ns(packageName, path_item) + finally: imp.release_lock() @@ -1478,9 +1478,9 @@ """Compute an ns-package subpath for a filesystem or zipfile importer""" subpath = os.path.join(path_item, packageName.split('.')[-1]) - normalized = os.path.normpath(os.path.normcase(subpath)) + normalized = normalize_path(subpath) for item in module.__path__: - if os.path.normpath(os.path.normcase(item))==normalized: + if normalize_path(item)==normalized: break else: # Only return the path if it's not already there From pje at users.sourceforge.net Sun Aug 14 23:14:56 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 23:14:56 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools dist.py, 1.21, 1.22 Message-ID: <20050814211456.D7DCD1E4271@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25594/setuptools Modified Files: dist.py Log Message: Minor refactoring of code that checks a distribution's contents. Index: dist.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/dist.py,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- dist.py 14 Aug 2005 20:18:56 -0000 1.21 +++ dist.py 14 Aug 2005 21:14:46 -0000 1.22 @@ -53,9 +53,7 @@ assert_string_list(dist,attr,value) for nsp in value: - for name in dist.iter_distribution_names(): - if name.startswith(nsp+'.'): break - else: + if not dist.has_contents_for(nsp): raise DistutilsSetupError( "Distribution contains no modules or packages for " + "namespace package %r" % nsp @@ -80,6 +78,8 @@ "%r must be a boolean value (got %r)" % (attr,value) ) + + def check_install_requires(dist, attr, value): """Verify that install_requires is a valid requirements list""" try: @@ -436,17 +436,17 @@ pfx = package+'.' - for p in self.packages or (): + for p in self.iter_distribution_names(): if p==package or p.startswith(pfx): return True - for p in self.py_modules or (): - if p==package or p.startswith(pfx): - return True - for p in self.ext_modules or (): - if p.name==package or p.name.startswith(pfx): - return True + + + + + + def _exclude_misc(self,name,value): From pje at users.sourceforge.net Sun Aug 14 23:17:54 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 14 Aug 2005 23:17:54 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command bdist_egg.py, 1.27, 1.28 Message-ID: <20050814211754.EF44E1E4024@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25708/setuptools/command Modified Files: bdist_egg.py Log Message: Auto-generate namespace __init__.py files for packages without them. This is a workaround for packages like 'll-color', which are distributed without 'll/__init__.py', to avoid overwriting ll-core's copy of ll/__init__.py. This allows existing packages that use this sort of kludging to be treated as a crude namespace package, as long as the "real" __init__.py also calls declare_namespace(). Index: bdist_egg.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/bdist_egg.py,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- bdist_egg.py 12 Jul 2005 23:43:21 -0000 1.27 +++ bdist_egg.py 14 Aug 2005 21:17:45 -0000 1.28 @@ -26,8 +26,8 @@ ])) f.close() - - +# stub __init__.py for packages distributed without one +NS_PKG_STUB = '__import__("pkg_resources").declare_namespace(__name__)' @@ -186,7 +186,7 @@ write_stub(os.path.basename(ext_name), pyfile) to_compile.append(pyfile) ext_outputs[p] = ext_name.replace(os.sep,'/') - + to_compile.extend(self.make_init_files()) if to_compile: cmd.byte_compile(to_compile) @@ -260,30 +260,30 @@ log.warn("zip_safe flag not set; analyzing archive contents...") return analyze_egg(self.bdist_dir, self.stubs) + def make_init_files(self): + """Create missing package __init__ files""" + init_files = [] + for base,dirs,files in walk_egg(self.bdist_dir): + if base==self.bdist_dir: + # don't put an __init__ in the root + continue + for name in files: + if name.endswith('.py'): + if '__init__.py' not in files: + pkg = base[len(self.bdist_dir)+1:].replace(os.sep,'.') + if self.distribution.has_contents_for(pkg): + log.warn("Creating missing __init__.py for %s",pkg) + filename = os.path.join(base,'__init__.py') + if not self.dry_run: + f = open(filename,'w'); f.write(NS_PKG_STUB) + f.close() + init_files.append(filename) + break + else: + # not a package, don't traverse to subdirectories + dirs[:] = [] - - - - - - - - - - - - - - - - - - - - - - - + return init_files def walk_egg(egg_dir): """Walk an unpacked egg's contents, skipping the metadata directory""" From loewis at users.sourceforge.net Sun Aug 14 23:42:44 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 14 Aug 2005 23:42:44 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules posixmodule.c, 2.338, 2.339 Message-ID: <20050814214244.C16CC1E4022@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30605/Modules Modified Files: posixmodule.c Log Message: Correct definition of ST_GEN_IDX. Index: posixmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/posixmodule.c,v retrieving revision 2.338 retrieving revision 2.339 diff -u -d -r2.338 -r2.339 --- posixmodule.c 9 Aug 2005 15:00:59 -0000 2.338 +++ posixmodule.c 14 Aug 2005 21:42:34 -0000 2.339 @@ -740,9 +740,9 @@ #endif #ifdef HAVE_STRUCT_STAT_ST_GEN -#define ST_GEN_IDX (ST_RDEV_IDX+1) +#define ST_GEN_IDX (ST_FLAGS_IDX+1) #else -#define ST_GEN_IDX ST_RDEV_IDX +#define ST_GEN_IDX ST_FLAGS_IDX #endif #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME From bcannon at users.sourceforge.net Mon Aug 15 06:28:39 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon, 15 Aug 2005 06:28:39 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0348.txt,1.7,1.8 Message-ID: <20050815042839.52CF11E4272@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31789 Modified Files: pep-0348.txt Log Message: Big changes: - Remove proposal of removing WindowsError - Change bare 'except' proposal to recommend their removal Minor changes: - Flesh out arguments for TerminatingException - Reorganize discussion of hierarchy difference compared to 2.4 - Strip out unneeded Rejected Idea sections based on other discussions in the PEP Index: pep-0348.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0348.txt,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- pep-0348.txt 9 Aug 2005 04:26:28 -0000 1.7 +++ pep-0348.txt 15 Aug 2005 04:28:28 -0000 1.8 @@ -13,25 +13,34 @@ Abstract ======== -Python, as 0of version 2.4, has 38 exceptions (including warnings) in -the built-in namespace in a rather shallow hierarchy. This list of -classes has grown over the years without a chance to learn from +Python, as of version 2.4, has 38 exceptions (including warnings) in +the built-in namespace in a rather shallow hierarchy. These +classes have come about over the years without a chance to learn from experience. This PEP proposes doing a reorganization of the hierarchy for Python 3.0 when backwards-compatibility is not as much of an -issue. Along with this reorganization, adding a requirement that all +issue. + +Along with this reorganization, adding a requirement that all objects passed to a ``raise`` statement must inherit from a specific -superclass is proposed. Lastly, bare ``except`` clauses will catch -only exceptions inheriting from Exception. +superclass is proposed. This is to have guarantees about the basic +interface of exceptions and to further enhance the natural hierarchy +of exceptions. +Lastly, bare ``except`` clauses will be removed. While they had their +usefulness when exceptions could be any object, with the above +proposal +of a required superclass for exceptions bare ``except`` clauses lose +their purpose. -Rationale -========= + +Rationale For Wanting Change +============================ Exceptions are a critical part of Python. While exceptions are traditionally used to signal errors in a program, they have also grown to be used for flow control for things such as iterators. -While their importance is great, there is lack of structure to them. +While their importance is great, there is a lack of structure to them. This stems from the fact that any object can be raised as an exception. Because of this you have no guarantee in terms of what kind of object will be raised, destroying any possible hierarchy @@ -40,26 +49,23 @@ But exceptions do have a hierarchy, showing the severity of the exception. The hierarchy also groups related exceptions together to simplify catching them in ``except`` clauses. To allow peopele to -be able to rely on this hierarchy, a common superclasse that all +be able to rely on this hierarchy, a common superclass that all raise objects must inherit from is being proposed. It also allows guarantees about the interface to raised objects to be made (see PEP 344 [#PEP344]_). A discussion about all of this has occurred before on python-dev [#Summary2004-08-01]_. -But allowing a guarantee about the hierarchy is not the only place -where exceptions can stand improvement. Bare ``except`` clauses are -often used in an inappropriate manner. Since they catch *all* raised -objects, they can catch exceptions that should have been allowed to -propagate to the top level of the execution stack, leading to the -interpreter terminating execution. Once again, this has been -discussed on python-dev [#python-dev3]_. +With the requirement of a common superclass for all exceptions, bare +``except`` clauses are impacted. Currently used as a catch-all for +raised exceptions, its usefulness is terminally weakened. Now, the +same functionality is possible by catching the required superclass. +Once again, this has been discussed on python-dev [#python-dev3]_. -To fix this over-reaching of bare ``except`` clauses, it is being -proposed that only objects inheriting from Exception be caught by -bare ``except`` clauses. This will allow the exception hierarchy -to be organized in such a way that bare ``except`` clauses can be -more useful by allowing exceptions that should not normally be caught -to lead to the termination of the interpreter. +Finally, slight changes to the exception hierarchy will make it much +more reasonable in terms of structure. By minor rearranging +exceptions +that should not typically be caught can be allowed to propagate to the +top of the execution stack, terminating the interpreter as intended. Philosophy of Reorganization @@ -104,9 +110,6 @@ .. parsed-literal:: +-- BaseException (new; broader inheritance for subclasses) - +-- TerminatingException (new; stricter inheritance for subclasses) - +-- KeyboardInterrupt - +-- SystemExit +-- Exception +-- GeneratorExit (defined in PEP 342 [#PEP342]_) +-- StandardError @@ -142,12 +145,17 @@ +-- StopIteration +-- SystemError +-- Warning - +-- PendingDeprecationWarning +-- DeprecationWarning +-- FutureWarning - +-- SyntaxWarning + +-- PendingDeprecationWarning +-- RuntimeWarning + +-- SyntaxWarning +-- UserWarning + + -- WindowsError + +-- TerminatingException (new; stricter inheritance for + subclasses) + +-- KeyboardInterrupt + +-- SystemExit Differences Compared to Python 2.4 @@ -157,49 +165,111 @@ inheritance changes. Inheritance changes result in either broader or more restrictive inheritance. "Broader" is when a class has an inheritance tree like ``cls, A`` and then becomes ``cls, B, A``. -"Stricter is the reverse. - +"Stricter" is the reverse. -New Exceptions --------------- BaseException -''''''''''''' +------------- -The superclass that all exceptions must inherit from. +The superclass that all exceptions must inherit from. It's name was +chosen to reflect that it is at the base of the exception hierarchy +while being an exception itself. "Raisable" was considered as a name, +it was passed on because its name did not properly reflect the fact +that it is an exception itself. + +Direct inheritance of BaseException is not expected, and will +be discouraged for the general case. Most user-defined +exceptions should inherit from Exception instead. This allows +catching Exception to continue to work in the common case of catching +all exceptions that should be caught. Direct inheritance of +BaseException should only be done in cases where an entirely new +category of exception is desired. + +But, for cases where all +exceptions should be caught blindly, ``except BaseException`` will +work. TerminatingException -'''''''''''''''''''' +-------------------- -Superclass for exceptions that are meant to the termination of the -interpreter. It does not inherit from Exception so that -subclasses are not caught by bare ``except`` clauses. +Superclass for exceptions that are meant to symbolize the termination +of +the interpreter. It does not inherit from Exception so that the +common +``except Exception`` statement does not catch the exceptions. This +for ``try`` statements that want to catch all exceptions that are +signals of errors and handle them separately from exceptions that +signify that the interpreter should be terminated:: -Naming based on the idea that the interpreter is trying to terminate when these -exceptions are raised. An earlier proposal suggested "TerminalException" but -avoidance of any confusion with an actual terminal along with "terminal" being -more fatalistic than "terminating" led to the current name choice. + try: + ... + # Catch all exceptions that are expected to be caught + except Exception: + ... + # Catch exceptions expected to terminate the interpreter + except TerminatingException: + ... +Compare this to:: -Removed Exceptions ------------------- + try: + ... + except Exception: + ... + except (KeyboardInterrupt, SystemExit): + ... -WindowsError -'''''''''''' +While more explicit, it is not necessarily obvious why the two +exceptions are being caught directly. By providing a common +superclass with a name that explicitly states the exceptions' typical +usage the reasoning behind the catch becomes more apparent. -Too OS-specific to be kept in the built-in exception hierarchy. +Comparing it to an even more general ``except`` clause:: + try: + ... + except Exception: + ... + except BaseException: + ... + +While this will perform the same action and catch all exceptions, +guaranteed, it is once again not obvious why Exception and +BaseException are being caught separately and not just +BaseException based purely on the code. + +TerminatingException will also help with transitioning from Python +2.x to 3.0 . With TerminatingException being a new exception, when +it is used the new inheritance for KeyboardInterrupt and SystemExit +becomes more obvious. + +It has been argued that TerminatingException should not be added +because it goes against Flat Is Better Than Nested (FIBTN). +While this new exception will not make the hierarchy as flat is it +could be, the overall depth of the tree is not changed; Exception has +a much deeper inheritance tree below it. + +It has also been argued that since KeyboardInterrupt and SystemExit +are not caught together that often in 2.4, there might not be much of +a need for TerminatingException. But with their new position in the +hierarchy catching them separately from other exceptions should +become more prevalent. + +Naming is based on the idea that the interpreter is trying to +terminate when KeyboardInterrupt and SystemExit +are raised. An earlier proposal suggested +"TerminalException" but +avoidance of any confusion with an actual terminal along with +"terminal" being +more fatalistic than "terminating" led to the current name choice. -Change of Position in the Exception Hierarchy ---------------------------------------------- NotImplementedError -''''''''''''''''''' +------------------- Inherits from Exception instead of from RuntimeError. - Originally inheriting from RuntimeError, NotImplementedError does not have any direct relation to the exception meant for use in user code as a quick-and-dirty exception. Thus it now directly inherits from @@ -228,27 +298,54 @@ inheritance check applied. -Bare ``except`` Clauses Catching ``Exception`` Only -=================================================== +Removal of Bare ``except`` Clauses +================================== -While Python does have its "explicit is better than implicit" tenant, -it is not necessary if there is a reasonable default behavior. -Changing the behavior of a bare ``except`` clause makes its existance -quite reasonable. +Bare ``except`` clauses serve the purpose of catching all exceptions +in Python 2.x . This is needed thanks to the fact that in 2.x any +exception can be raised as an exception. But if this PEP is accepted +this will no longer be the case because of a required superclass for +all raised objects. +This goes against a part of the Zen of Python; +One Way To Do It (OWTDI) [#zen]_. By having bare ``except`` clauses +keep their semantic meaning, there would be two ways of doing the +same things. It also goes against Exlpicit Is Better Than Implicit +(EIBTI) by implicitly doing something that can easily be covered by +a more explicit statement. -In Python 2.4, a bare ``except`` clause will catch any and all -exceptions. Typically, though, this is not what is truly desired. -More often than not one wants to catch all error exceptions that do -not signify a "bad" interpreter state. In the new exception hierarchy -this is condition is embodied by Exception. Thus bare ``except`` -clauses will catch only exceptions inheriting from Exception. +It has also been proposed that bare ``except`` clauses be changed to +semantically be equivalent to ``except Exception``. This has been +proposed since this is what most bare ``except`` clauses are meant to +do. This would make ``except`` clauses have a more reasonable +default behavior. + +But this line of reasoning has some issues. First is that it also +goes against the Zen of Python; both OWTDI and EIBTI by providing +an implicit alternative to ``except Exception``. Secondly, +backwards-compatibility becomes more difficult. While removal will +break code, it can mechanically be changed to have the same semantic +meaning as it currently has by finding all occurances of ``except:`` +and replacing them with ``except BaseException:``. But going with +this semantic change makes compatibility more subtle. Was a bare +``except`` clause meant to catch all exceptions, or actually meant +to catch all reasonable exceptions (i.e., everything but +TerminatingException)? Every case will need to be carefully +examined, and could easily be incorrectly examined, leading to subtle +bugs. + +The shorter typing afforded by bare ``except`` statements also does +not justify its existence. "Exception", the typical exception that\ +will be caught, is only nine characters. Add in the needed space to +separate "Exception" from "except" you get only 10 more characters to +type. While this might be a nuisance in quick-and-dirty scripts, the +impact is minimal. Implementation -------------- -In the compiler, when a bare ``except`` clause is reached, the code -for ``except Exception`` will be emitted. +Changing Grammar/Grammar is all that is needed to remove bare +``except`` clauses. Transition Plan @@ -280,15 +377,6 @@ in the implementation of the bytecode. -Removed Exceptions -'''''''''''''''''' - -Exceptions scheduled for removal will be transitioned much like the -old names of renamed exceptions. Upon instantiation a -PendingDeprecationWarning will be raised stating the the exception is -due for removal in Python 3.0. - - Required Superclass for ``raise`` --------------------------------- @@ -299,36 +387,49 @@ Removal of Bare ``except`` Clauses ---------------------------------- -A RuntimeWarning will be raised for all bare ``except`` clauses that -catch an exception that does not inherit from Exception. - +A PendingDeprecationWarning will be raised when a bare ``except`` +clause is found in code. One release before they are removed the +warning will be changed to DeprecationWarning. -Rejected Ideas -============== +Doing ``from __future__ import exceptions`` will cause bare +``except`` clauses to be considered syntax errors. -Multiple threads on python-dev discussing this PEP have lead to -various ideas being rejected [#python-dev-thread1]_, -[#python-dev-thread2]_, [#python-dev-thread3]_. +Roadmap +------- -KeyboardInterrupt inheriting from ControlFlowException ------------------------------------------------------- +Python 2.x is the first version that contains changes. Python 3.0 +will be when transition will be complete. Version 3.0-1 represents +one version before 3.0 is released, 3.0-2 two versions before, etc. -KeyboardInterrupt has been a contentious point within this hierarchy. -Some view the exception more as control flow being caused by the user. -But with its asynchronous cause (the user is able to trigger the -exception at any point in code) its proper place is inheriting from -CriticalError. +* 2.x + - Add BaseException, TerminatingException + - Have KeyboardInterrupt and SystemExit inherit from both + Exception and TerminatingException + - Introduce ``from __future__ import exceptions`` + - Provide a script that mechanically changes all bare ``except`` + clauses to catch BaseException in a .py file + - PendingDeprecationWarning for bare ``except`` clauses + - PendingDeprecationWarning for all objects raised that do not + inherit from BaseException + - PendingDeprecationWarning raised when KeyboardInterrupt or + SystemExit are caught because of their inheritance of Exception +* 3.0-1 + - Turn all introduced PendingDeprecationWarnings into + DeprecationWarning +* 3.0 + - Remove DeprecationWarnings + - Have KeyboardInterrupt and SystemExit only inherit from + TerminatingException + - Remove ``exceptions`` __future__ import support -Other Names for BaseException and Exception -------------------------------------------- +Rejected Ideas +============== -Alternative names for BaseException and Exception have been -Raisable/Exception and Exception/StandardError. The former -alternatives were rejected because "Raisable" does not reflect its -exception nature well enough. The latter alternatives were rejected -because they do not reflect current use. +Multiple threads on python-dev discussing this PEP have lead to +various ideas being rejected [#python-dev-thread1]_, +[#python-dev-thread2]_, [#python-dev-thread3]_. DeprecationWarning Inheriting From PendingDeprecationWarning @@ -381,23 +482,14 @@ It has been suggested that ControlFlowException should inherit from Exception. This idea has been rejected based on the thinking that -control flow exceptions typically should not be caught by bare -``except`` clauses, whereas Exception subclasses should be. - - -Removal of Bare ``except`` Clauses ----------------------------------- - -The suggestion has been made to remove bare ``except`` clauses -altogether, in the name of "explicit is better than implicit". But -Guido has said this is too weak of an argument since other areas of -Python have default behavior [#python-dev3]_. - +control flow exceptions typically do not all need to be caught by a +single ``except`` clause. Rename NameError to NamespaceError ---------------------------------- -NameError is considered more succinct and leaves open no possible mistyping of +NameError is considered more succinct and leaves open no possible +mistyping of the capitalization of "Namespace" [#python-dev5]_. @@ -407,7 +499,8 @@ The thinking was that RuntimeError was in no way an obvious name for an exception meant to be used when a situation did not call for the creation of a new exception. The renaming was rejected on the basis -that the exception is already used throughout the interpreter [#python-dev6]_. +that the exception is already used throughout the interpreter +[#python-dev6]_. Rejection of SimpleError was founded on the thought that people should be free to use whatever exception they choose and not have one so blatently suggested [#python-dev7]_. @@ -425,26 +518,39 @@ Have EOFError Subclass IOError ------------------------------ -The original thought was that sine EOFError deals directly with I/O, it should -subclass IOError. But since EOFError is used more as a signal that an event -has occurred (the exhaustion of an I/O port), it should not subclass such a -specific error exception. +The original thought was that since EOFError deals directly with I/O, +it should +subclass IOError. But since EOFError is used more as a signal that an +event +has occurred (the exhaustion of an I/O port), it should not subclass +such a specific error exception. Have MemoryError and SystemError Have a Common Superclass --------------------------------------------------------- -Both classes deal with the interpreter, so why not have them have a common -superclass? Because one of them means that the interpreter is in a state that -it should not recover from while the other does not. +Both classes deal with the interpreter, so why not have them have a +common +superclass? Because one of them means that the interpreter is in a +state that it should not recover from while the other does not. Common Superclass for PendingDeprecationWarning and DeprecationWarning ---------------------------------------------------------------------- -Grouping the deprecation warning exceptions together makes intuitive sense. -But this sensical idea does not extend well when one considers how rarely -either warning is used, let along at the same time. +Grouping the deprecation warning exceptions together makes intuitive +sense. +But this sensical idea does not extend well when one considers how +rarely either warning is used, let along at the same time. + + +Removing WindowsError +--------------------- + +Originally proposed based on the idea that having such a +platform-specific exception should not be in the built-in namespace. +It turns out, though, enough code exists that uses the exception to +warrant it staying. Acknowledgements @@ -503,6 +609,9 @@ .. [#python-dev7] python-dev email (Exception Reorg PEP checked in) http://mail.python.org/pipermail/python-dev/2005-August/055175.html +.. [#zen] PEP 20 (The Zen of Python) + http://www.python.org/peps/pep-0020.html + Copyright ========= From emanuelkso_3w9w at yahoo.com Mon Aug 15 17:22:09 2005 From: emanuelkso_3w9w at yahoo.com (emanuelkso_3w9w@yahoo.com) Date: Mon, 15 Aug 2005 12:22:09 -0300 Subject: [Python-checkins] mala direta dividida por atividade Message-ID: <20050815152638.9F92022F5C@internet06.internett.com.br> Lista de emails - Mala Direta emails, e-mails,listas de email Lista de emails - Mala Direta emails, e-mails,listas de email Programas gratis, dicas de divulga??o pela internet: http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm e-mails e-mail free marketing Programas gratis, dicas de divulga??o pela internet mala direta dividida por atividade Lista de emails - Mala Direta emails, e-mails,listas de email Divulga??o de sites via mala direta: Visite qualquer um dos 3 links abaixo http://www.segmails.vze.com ou http://www.vendemails.cjb.net ou http://geocities.yahoo.com.br/webneggocios/listagemnova.htm E-mails cadastros cadastro de emails e-mail email lista listas de para Mala Direta Programas gratis, dicas de divulga??o pela internet Lista de emails - Mala Direta emails, e-mails,listas de email enviar email publicidade From bwarsaw at users.sourceforge.net Mon Aug 15 19:33:07 2005 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Mon, 15 Aug 2005 19:33:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_trace.py, 1.13, 1.13.4.1 Message-ID: <20050815173307.4AE561E4028@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20452/Lib/test Modified Files: Tag: release24-maint test_trace.py Log Message: Fix for SF bug # 900092, hotshot.stats.load assertion failure. This patch restores the tracing of a 'return' event for exceptions that cause a function to exit. Also, update the unit test. I will port to Python 2.5. Index: test_trace.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_trace.py,v retrieving revision 1.13 retrieving revision 1.13.4.1 diff -u -d -r1.13 -r1.13.4.1 --- test_trace.py 22 Mar 2004 19:30:39 -0000 1.13 +++ test_trace.py 15 Aug 2005 17:32:56 -0000 1.13.4.1 @@ -97,6 +97,7 @@ (-3, 'call'), (-2, 'line'), (-2, 'exception'), + (-2, 'return'), (2, 'exception'), (3, 'line'), (4, 'line'), From bwarsaw at users.sourceforge.net Mon Aug 15 19:33:07 2005 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Mon, 15 Aug 2005 19:33:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python ceval.c,2.419,2.419.2.1 Message-ID: <20050815173307.5A56C1E402A@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20452/Python Modified Files: Tag: release24-maint ceval.c Log Message: Fix for SF bug # 900092, hotshot.stats.load assertion failure. This patch restores the tracing of a 'return' event for exceptions that cause a function to exit. Also, update the unit test. I will port to Python 2.5. Index: ceval.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v retrieving revision 2.419 retrieving revision 2.419.2.1 diff -u -d -r2.419 -r2.419.2.1 --- ceval.c 23 Nov 2004 18:06:08 -0000 2.419 +++ ceval.c 15 Aug 2005 17:32:56 -0000 2.419.2.1 @@ -2462,14 +2462,20 @@ fast_yield: if (tstate->use_tracing) { - if (tstate->c_tracefunc - && (why == WHY_RETURN || why == WHY_YIELD)) { - if (call_trace(tstate->c_tracefunc, - tstate->c_traceobj, f, - PyTrace_RETURN, retval)) { - Py_XDECREF(retval); - retval = NULL; - why = WHY_EXCEPTION; + if (tstate->c_tracefunc) { + if (why == WHY_RETURN || why == WHY_YIELD) { + if (call_trace(tstate->c_tracefunc, + tstate->c_traceobj, f, + PyTrace_RETURN, retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + else if (why == WHY_EXCEPTION) { + call_trace_protected(tstate->c_tracefunc, + tstate->c_traceobj, f, + PyTrace_RETURN); } } if (tstate->c_profilefunc) { From bwarsaw at users.sourceforge.net Mon Aug 15 19:35:53 2005 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Mon, 15 Aug 2005 19:35:53 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.72, 1.1193.2.73 Message-ID: <20050815173553.8B9921E4028@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21152 Modified Files: Tag: release24-maint NEWS Log Message: Add news about SF bug # 900092 fix. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.72 retrieving revision 1.1193.2.73 diff -u -d -r1.1193.2.72 -r1.1193.2.73 --- NEWS 13 Aug 2005 02:28:54 -0000 1.1193.2.72 +++ NEWS 15 Aug 2005 17:35:43 -0000 1.1193.2.73 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- SF bug #900092: When tracing (e.g. for hotshot), restore 'return' events for + exceptions that cause a function to exit. + - SF bug #1257731: set.discard() and set.remove() did not correctly handle keys that both inherited from set and defined their own __hash__() function. Also, changed set.__contains__() to have From bwarsaw at users.sourceforge.net Mon Aug 15 20:14:28 2005 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Mon, 15 Aug 2005 20:14:28 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_trace.py, 1.13, 1.14 Message-ID: <20050815181428.82EC01E4028@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28928/Lib/test Modified Files: test_trace.py Log Message: Port from the Python 2.4 branch, patches for SF bug # 900092, hotshot.stats.load. Index: test_trace.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_trace.py,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- test_trace.py 22 Mar 2004 19:30:39 -0000 1.13 +++ test_trace.py 15 Aug 2005 18:14:18 -0000 1.14 @@ -97,6 +97,7 @@ (-3, 'call'), (-2, 'line'), (-2, 'exception'), + (-2, 'return'), (2, 'exception'), (3, 'line'), (4, 'line'), From bwarsaw at users.sourceforge.net Mon Aug 15 20:14:28 2005 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Mon, 15 Aug 2005 20:14:28 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1333,1.1334 Message-ID: <20050815181428.E630A1E4028@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28928/Misc Modified Files: NEWS Log Message: Port from the Python 2.4 branch, patches for SF bug # 900092, hotshot.stats.load. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1333 retrieving revision 1.1334 diff -u -d -r1.1333 -r1.1334 --- NEWS 12 Aug 2005 17:34:57 -0000 1.1333 +++ NEWS 15 Aug 2005 18:14:18 -0000 1.1334 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- SF bug #900092: When tracing (e.g. for hotshot), restore 'return' events for + exceptions that cause a function to exit. + - The implementation of set() and frozenset() was revised to use its own internal data structure. Memory consumption is reduced by 1/3 and there are modest speed-ups as well. The API is unchanged. From bwarsaw at users.sourceforge.net Mon Aug 15 20:14:30 2005 From: bwarsaw at users.sourceforge.net (bwarsaw@users.sourceforge.net) Date: Mon, 15 Aug 2005 20:14:30 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python ceval.c,2.425,2.426 Message-ID: <20050815181430.181431E402F@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28928/Python Modified Files: ceval.c Log Message: Port from the Python 2.4 branch, patches for SF bug # 900092, hotshot.stats.load. Index: ceval.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/ceval.c,v retrieving revision 2.425 retrieving revision 2.426 diff -u -d -r2.425 -r2.426 --- ceval.c 2 Aug 2005 00:46:45 -0000 2.425 +++ ceval.c 15 Aug 2005 18:14:19 -0000 2.426 @@ -2480,14 +2480,20 @@ fast_yield: if (tstate->use_tracing) { - if (tstate->c_tracefunc - && (why == WHY_RETURN || why == WHY_YIELD)) { - if (call_trace(tstate->c_tracefunc, - tstate->c_traceobj, f, - PyTrace_RETURN, retval)) { - Py_XDECREF(retval); - retval = NULL; - why = WHY_EXCEPTION; + if (tstate->c_tracefunc) { + if (why == WHY_RETURN || why == WHY_YIELD) { + if (call_trace(tstate->c_tracefunc, + tstate->c_traceobj, f, + PyTrace_RETURN, retval)) { + Py_XDECREF(retval); + retval = NULL; + why = WHY_EXCEPTION; + } + } + else if (why == WHY_EXCEPTION) { + call_trace_protected(tstate->c_tracefunc, + tstate->c_traceobj, f, + PyTrace_RETURN); } } if (tstate->c_profilefunc) { From rhettinger at users.sourceforge.net Tue Aug 16 05:48:01 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 05:48:01 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1334,1.1335 Message-ID: <20050816034801.BB0F71E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31184/Misc Modified Files: NEWS Log Message: Add a C API for sets and frozensets. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1334 retrieving revision 1.1335 diff -u -d -r1.1334 -r1.1335 --- NEWS 15 Aug 2005 18:14:18 -0000 1.1334 +++ NEWS 16 Aug 2005 03:47:51 -0000 1.1335 @@ -439,6 +439,8 @@ C API ----- +- Added a C API for set and frozenset objects. + - Removed PyRange_New(). From rhettinger at users.sourceforge.net Tue Aug 16 05:48:01 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 05:48:01 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/api concrete.tex,1.61,1.62 Message-ID: <20050816034801.EC6B41E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/api In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31184/Doc/api Modified Files: concrete.tex Log Message: Add a C API for sets and frozensets. Index: concrete.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/api/concrete.tex,v retrieving revision 1.61 retrieving revision 1.62 diff -u -d -r1.61 -r1.62 --- concrete.tex 18 Jun 2005 17:54:13 -0000 1.61 +++ concrete.tex 16 Aug 2005 03:47:51 -0000 1.62 @@ -2897,3 +2897,128 @@ tuple suitable for passing to \code{datetime.date.fromtimestamp()}. \versionadded{2.4} \end{cfuncdesc} + + +\subsection{Set Objects \label{setObjects}} +\sectionauthor{Raymond D. Hettinger}{python at rcn.com} + +\obindex{set} +\obindex{frozenset} +\versionadded{2.5} + +This section details the public API for \class{set} and \class{frozenset} +objects. Any functionality not listed below is best accessed using the +abstract object API (including +\cfunction{PyObject_CallMethod()}, \cfunction{PyObject_RichCompareBool()}, +\cfunction{PyObject_Hash()}, \cfunction{PyObject_Repr()}, +\cfunction{PyObject_IsTrue()}, \cfunction{PyObject_Print()}, and +\cfunction{PyObject_GetIter()}). + +\begin{ctypedesc}{PySetObject} + This subtype of \ctype{PyObject} is used to hold the internal data for + both \class{set} and \class{frozenset} objects. It is like a + \ctype{PyDictObject} in that it is a fixed size for small sets + (much like tuple storage) and will point to a separate, variable sized + block of memory for medium and large sized sets (much like list storage). + None of the fields of this structure should be considered public and + are subject to change. All access should be done through the + documented API. + +\end{ctypedesc} + +\begin{cvardesc}{PyTypeObject}{PySet_Type} + This is an instance of \ctype{PyTypeObject} representing the Python + \class{set} type. +\end{cvardesc} + +\begin{cvardesc}{PyTypeObject}{PyFrozenSet_Type} + This is an instance of \ctype{PyTypeObject} representing the Python + \class{frozenset} type. +\end{cvardesc} + + +The following type check macros work on pointers to any Python object. +Likewise, the constructor functions work with any iterable Python object. + +\begin{cfuncdesc}{int}{PyAnySet_Check}{PyObject *p} + Returns true if \var{p} is a \class{set} object, a \class{frozenset} + object, or an instance of a subtype. +\end{cfuncdesc} + +\begin{cfuncdesc}{int}{PyAnySet_CheckExact}{PyObject *p} + Returns true if \var{p} is a \class{set} object or a \class{frozenset} + object but not an instance of a subtype. +\end{cfuncdesc} + +\begin{cfuncdesc}{int}{PyFrozenSet_CheckExact}{PyObject *p} + Returns true if \var{p} is a \class{frozenset} object + but not an instance of a subtype. +\end{cfuncdesc} + +\begin{cfuncdesc}{PyObject*}{PySet_New}{PyObject *iterable} + Returns a new \class{set} containing objects returned by the + \var{iterable}. The \var{iterable} may be \NULL{} to create a + new empty set. Returns the new set on success or \NULL{} on + failure. +\end{cfuncdesc} + +\begin{cfuncdesc}{PyObject*}{PyFrozenSet_New}{PyObject *iterable} + Returns a new \class{frozenset} containing objects returned by the + \var{iterable}. The \var{iterable} may be \NULL{} to create a + new empty frozenset. Returns the new set on success or \NULL{} on + failure. +\end{cfuncdesc} + + +The following functions and macros are available for instances of +\class{set} or \class{frozenset} or instances of their subtypes. + +\begin{cfuncdesc}{int}{PySet_Size}{PyObject *anyset} + Returns the length of a \class{set} or \class{frozenset} object. + Equivalent to \samp{len(\var{anyset})}. Raises a + \exception{PyExc_SystemError} if the argument is not a \class{set}, + \class{frozenset}, or an instance of a subtype. + \bifuncindex{len} +\end{cfuncdesc} + +\begin{cfuncdesc}{int}{PySet_GET_SIZE}{PyObject *anyset} + Macro form of \cfunction{PySet_Size()} without error checking. +\end{cfuncdesc} + +\begin{cfuncdesc}{int}{PySet_Contains}{PyObject *anyset, PyObject *key} + Returns 1 if found, 0 if not found, and -1 if an error is + encountered. Unlike the Python \method{__contains__()} method, this + function does not automatically convert unhashable sets into temporary + frozensets. Raises a \exception{TypeError} if the key is unhashable. +\end{cfuncdesc} + +\begin{cfuncdesc}{int}{PySet_Discard}{PyObject *anyset, PyObject *key} + Returns 1 if found and removed, 0 if not found (no action taken), + and -1 if an error is encountered. Does not raise \exception{KeyError} + for missing keys. Raises a \exception{TypeError} if the key is unhashable. + Unlike the Python \method{discard()} method, this function does + not automatically convert unhashable sets into temporary frozensets. +\end{cfuncdesc} + + +The following functions are available for instances of \class{set} or +its subtypes but not for instances of \class{frozenset} or its subtypes. + +\begin{cfuncdesc}{int}{PySet_Add}{PyObject *set, PyObject *key} + Adds \var{key} to a \class{set} instance. Does not apply to + \class{frozenset} instances. Returns 0 on success or -1 on failure. + Raises a \exception{TypeError} if the key is unhashable. + Raises a \exception{MemoryError} if there is no room to grow. + Raises a \exception{SystemError} if \var{key} is an not an instance + of \class{set} or its subtype. +\end{cfuncdesc} + +\begin{cfuncdesc}{PyObject*}{PySet_Pop}{PyObject *set} + Returns a new reference to an arbitrary object in the \var{set}, + and removes the object from the \var{set}. Returns \NULL{} on + failure. Raises \exception{KeyError} if the set is empty. + Raises a \exception{SystemError} if \var{key} is an not an instance + of \class{set} or its subtype. +\end{cfuncdesc} + + From rhettinger at users.sourceforge.net Tue Aug 16 05:48:01 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 05:48:01 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python marshal.c,1.87,1.88 Message-ID: <20050816034801.F26001E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31184/Python Modified Files: marshal.c Log Message: Add a C API for sets and frozensets. Index: marshal.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/marshal.c,v retrieving revision 1.87 retrieving revision 1.88 diff -u -d -r1.87 -r1.88 --- marshal.c 25 Jun 2005 08:23:41 -0000 1.87 +++ marshal.c 16 Aug 2005 03:47:52 -0000 1.88 @@ -773,11 +773,9 @@ if (v == NULL) return v; if (type == TYPE_SET) - v3 = PyObject_CallFunctionObjArgs( - (PyObject *)&PySet_Type, v, NULL); + v3 = PySet_New(v); else - v3 = PyObject_CallFunctionObjArgs( - (PyObject *)&PyFrozenSet_Type, v, NULL); + v3 = PyFrozenSet_New(v); Py_DECREF(v); return v3; From rhettinger at users.sourceforge.net Tue Aug 16 05:48:02 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 05:48:02 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Include setobject.h,2.9,2.10 Message-ID: <20050816034802.19A201E4029@bag.python.org> Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31184/Include Modified Files: setobject.h Log Message: Add a C API for sets and frozensets. Index: setobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/setobject.h,v retrieving revision 2.9 retrieving revision 2.10 diff -u -d -r2.9 -r2.10 --- setobject.h 7 Aug 2005 13:02:52 -0000 2.9 +++ setobject.h 16 Aug 2005 03:47:51 -0000 2.10 @@ -74,6 +74,15 @@ PyType_IsSubtype((ob)->ob_type, &PySet_Type) || \ PyType_IsSubtype((ob)->ob_type, &PyFrozenSet_Type)) +PyAPI_FUNC(PyObject *) PySet_New(PyObject *); +PyAPI_FUNC(PyObject *) PyFrozenSet_New(PyObject *); +PyAPI_FUNC(int) PySet_Size(PyObject *anyset); +#define PySet_GET_SIZE(so) (((PySetObject *)(so))->used) +PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key); +PyAPI_FUNC(int) PySet_Discard(PyObject *anyset, PyObject *key); +PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); +PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); + #ifdef __cplusplus } #endif From rhettinger at users.sourceforge.net Tue Aug 16 05:48:02 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 05:48:02 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.49,1.50 Message-ID: <20050816034802.303BD1E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31184/Objects Modified Files: setobject.c Log Message: Add a C API for sets and frozensets. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.49 retrieving revision 1.50 diff -u -d -r1.49 -r1.50 --- setobject.c 13 Aug 2005 09:28:48 -0000 1.49 +++ setobject.c 16 Aug 2005 03:47:52 -0000 1.50 @@ -843,7 +843,7 @@ return iterable; } result = make_new_set(type, iterable); - if (result == NULL || set_len(result)) + if (result == NULL || PySet_GET_SIZE(result)) return result; Py_DECREF(result); } @@ -1052,7 +1052,7 @@ int pos = 0; setentry *entry; - if (set_len(other) > set_len((PyObject *)so)) { + if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) { tmp = (PyObject *)so; so = (PySetObject *)other; other = tmp; @@ -1381,7 +1381,7 @@ Py_DECREF(tmp); return result; } - if (set_len((PyObject *)so) > set_len(other)) + if (PySet_GET_SIZE(so) > PySet_GET_SIZE(other)) Py_RETURN_FALSE; while (set_next(so, &pos, &entry)) { @@ -1426,11 +1426,11 @@ } switch (op) { case Py_EQ: - if (set_len((PyObject *)v) != set_len(w)) + if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w)) Py_RETURN_FALSE; return set_issubset(v, w); case Py_NE: - if (set_len((PyObject *)v) != set_len(w)) + if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w)) Py_RETURN_TRUE; r1 = set_issubset(v, w); assert (r1 != NULL); @@ -1442,11 +1442,11 @@ case Py_GE: return set_issuperset(v, w); case Py_LT: - if (set_len((PyObject *)v) >= set_len(w)) + if (PySet_GET_SIZE(v) >= PySet_GET_SIZE(w)) Py_RETURN_FALSE; return set_issubset(v, w); case Py_GT: - if (set_len((PyObject *)v) <= set_len(w)) + if (PySet_GET_SIZE(v) <= PySet_GET_SIZE(w)) Py_RETURN_FALSE; return set_issuperset(v, w); } @@ -1472,7 +1472,7 @@ if (so->hash != -1) return so->hash; - hash *= set_len(self) + 1; + hash *= PySet_GET_SIZE(self) + 1; while (set_next(so, &pos, &entry)) { /* Work to increase the bit dispersion for closely spaced hash values. The is important because some use cases have many @@ -1918,3 +1918,67 @@ frozenset_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ }; + + +/***** C API functions *************************************************/ + +PyObject * +PySet_New(PyObject *iterable) +{ + return make_new_set(&PySet_Type, iterable); +} + +PyObject * +PyFrozenSet_New(PyObject *iterable) +{ + PyObject *args = NULL, *result; + + if (iterable != NULL) { + args = PyTuple_Pack(1, iterable); + if (args == NULL) + return NULL; + } + result = frozenset_new(&PyFrozenSet_Type, args, NULL); + Py_DECREF(args); + return result; +} + +int +PySet_Contains(PyObject *anyset, PyObject *key) +{ + if (!PyAnySet_Check(anyset)) { + PyErr_BadInternalCall(); + return -1; + } + return set_contains_key((PySetObject *)anyset, key); +} + +int +PySet_Discard(PyObject *anyset, PyObject *key) +{ + if (!PyAnySet_Check(anyset)) { + PyErr_BadInternalCall(); + return -1; + } + return set_discard_key((PySetObject *)anyset, key); +} + +int +PySet_Add(PyObject *set, PyObject *key) +{ + if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { + PyErr_BadInternalCall(); + return -1; + } + return set_add_key((PySetObject *)set, key); +} + +PyObject * +PySet_Pop(PyObject *set) +{ + if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { + PyErr_BadInternalCall(); + return NULL; + } + return set_pop((PySetObject *)set); +} From rhettinger at users.sourceforge.net Tue Aug 16 05:54:21 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 05:54:21 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.50,1.51 Message-ID: <20050816035421.6D3BA1E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32078 Modified Files: setobject.c Log Message: DECREF --> XDECREF Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.50 retrieving revision 1.51 diff -u -d -r1.50 -r1.51 --- setobject.c 16 Aug 2005 03:47:52 -0000 1.50 +++ setobject.c 16 Aug 2005 03:54:11 -0000 1.51 @@ -1939,7 +1939,7 @@ return NULL; } result = frozenset_new(&PyFrozenSet_Type, args, NULL); - Py_DECREF(args); + Py_XDECREF(args); return result; } From bcannon at users.sourceforge.net Tue Aug 16 08:22:03 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Tue, 16 Aug 2005 08:22:03 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0348.txt,1.8,1.9 Message-ID: <20050816062203.052D01E4002@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23030 Modified Files: pep-0348.txt Log Message: Revised based on Guido's wishes: no more TerminatingException and bare 'except' clauses act like ``except Exception``. Transition plan completely reworked to basically not go through hoops that will negatively impact performance. Basically now BaseException is added and everything else is not changed until Python 3.0 . Also suggests docs be changed to suggest a certain practice. Index: pep-0348.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0348.txt,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- pep-0348.txt 15 Aug 2005 04:28:28 -0000 1.8 +++ pep-0348.txt 16 Aug 2005 06:21:51 -0000 1.9 @@ -9,6 +9,8 @@ Created: 28-Jul-2005 Post-History: +.. |2.x| replace:: 2.5 + Abstract ======== @@ -26,11 +28,10 @@ interface of exceptions and to further enhance the natural hierarchy of exceptions. -Lastly, bare ``except`` clauses will be removed. While they had their -usefulness when exceptions could be any object, with the above -proposal -of a required superclass for exceptions bare ``except`` clauses lose -their purpose. +Lastly, bare ``except`` clauses will be changed to be semantically +equivalent to ``except Exception``. Most people currently use bare +``except`` clause for this purpose and with the exception hierarchy +reorganization becomes a viable default. Rationale For Wanting Change @@ -48,17 +49,19 @@ But exceptions do have a hierarchy, showing the severity of the exception. The hierarchy also groups related exceptions together to -simplify catching them in ``except`` clauses. To allow peopele to +simplify catching them in ``except`` clauses. To allow people to be able to rely on this hierarchy, a common superclass that all raise objects must inherit from is being proposed. It also allows guarantees about the interface to raised objects to be made (see PEP 344 [#PEP344]_). A discussion about all of this has occurred before on python-dev [#Summary2004-08-01]_. -With the requirement of a common superclass for all exceptions, bare -``except`` clauses are impacted. Currently used as a catch-all for -raised exceptions, its usefulness is terminally weakened. Now, the -same functionality is possible by catching the required superclass. +As bare ``except`` clauses stand now, they catch *all* exceptions. +While this can be handy, it is rather overreaching for the common +case. Thanks to having a required superclass, catching all +exceptions is as easy as catching just one specific exception. +This allows bare ``except`` clauses to be used for a more useful +purpose. Once again, this has been discussed on python-dev [#python-dev3]_. Finally, slight changes to the exception hierarchy will make it much @@ -74,7 +77,9 @@ For the reorganization of the hierarchy, there was a general philosophy followed that developed from discussion of earlier drafts of this PEP [#python-dev-thread1]_, [#python-dev-thread2]_, -[#python-dev-thread3]_. First and foremost was to not break anything +[#python-dev-thread3]_, [#python-dev-thread4]_, +[#python-dev-thread5]_, [#python-dev-thread6]_. +First and foremost was to not break anything that works. This meant that renaming exceptions was out of the question unless the name was deemed severely bad. This also meant no removal of exceptions unless they were viewed as @@ -152,10 +157,8 @@ +-- SyntaxWarning +-- UserWarning + -- WindowsError - +-- TerminatingException (new; stricter inheritance for - subclasses) - +-- KeyboardInterrupt - +-- SystemExit + +-- KeyboardInterrupt (stricter inheritance) + +-- SystemExit (stricter inheritance) Differences Compared to Python 2.4 @@ -190,79 +193,14 @@ work. -TerminatingException --------------------- - -Superclass for exceptions that are meant to symbolize the termination -of -the interpreter. It does not inherit from Exception so that the -common -``except Exception`` statement does not catch the exceptions. This -for ``try`` statements that want to catch all exceptions that are -signals of errors and handle them separately from exceptions that -signify that the interpreter should be terminated:: - - try: - ... - # Catch all exceptions that are expected to be caught - except Exception: - ... - # Catch exceptions expected to terminate the interpreter - except TerminatingException: - ... - -Compare this to:: - - try: - ... - except Exception: - ... - except (KeyboardInterrupt, SystemExit): - ... - -While more explicit, it is not necessarily obvious why the two -exceptions are being caught directly. By providing a common -superclass with a name that explicitly states the exceptions' typical -usage the reasoning behind the catch becomes more apparent. - -Comparing it to an even more general ``except`` clause:: - - try: - ... - except Exception: - ... - except BaseException: - ... - -While this will perform the same action and catch all exceptions, -guaranteed, it is once again not obvious why Exception and -BaseException are being caught separately and not just -BaseException based purely on the code. - -TerminatingException will also help with transitioning from Python -2.x to 3.0 . With TerminatingException being a new exception, when -it is used the new inheritance for KeyboardInterrupt and SystemExit -becomes more obvious. - -It has been argued that TerminatingException should not be added -because it goes against Flat Is Better Than Nested (FIBTN). -While this new exception will not make the hierarchy as flat is it -could be, the overall depth of the tree is not changed; Exception has -a much deeper inheritance tree below it. - -It has also been argued that since KeyboardInterrupt and SystemExit -are not caught together that often in 2.4, there might not be much of -a need for TerminatingException. But with their new position in the -hierarchy catching them separately from other exceptions should -become more prevalent. +KeyboardInterrupt and SystemExit +-------------------------------- -Naming is based on the idea that the interpreter is trying to -terminate when KeyboardInterrupt and SystemExit -are raised. An earlier proposal suggested -"TerminalException" but -avoidance of any confusion with an actual terminal along with -"terminal" being -more fatalistic than "terminating" led to the current name choice. +Both exceptions are no longer under Exception. This is to allow bare +``except`` clauses to act as a more viable default case by catching +exceptions that inherit from Exception. With both KeyboardInterrupt +and SystemExit acting as signals that the interpreter is expected to +exit, catching them in the common case is the wrong semantics. NotImplementedError @@ -298,140 +236,69 @@ inheritance check applied. -Removal of Bare ``except`` Clauses -================================== - -Bare ``except`` clauses serve the purpose of catching all exceptions -in Python 2.x . This is needed thanks to the fact that in 2.x any -exception can be raised as an exception. But if this PEP is accepted -this will no longer be the case because of a required superclass for -all raised objects. -This goes against a part of the Zen of Python; -One Way To Do It (OWTDI) [#zen]_. By having bare ``except`` clauses -keep their semantic meaning, there would be two ways of doing the -same things. It also goes against Exlpicit Is Better Than Implicit -(EIBTI) by implicitly doing something that can easily be covered by -a more explicit statement. +Bare ``except`` Clauses Catch Exception +======================================= -It has also been proposed that bare ``except`` clauses be changed to -semantically be equivalent to ``except Exception``. This has been -proposed since this is what most bare ``except`` clauses are meant to -do. This would make ``except`` clauses have a more reasonable -default behavior. +In most existing Python 2.4 code, bare ``except`` clauses are too +broad in the exceptions they catch. Typically only exceptions that +signal an error are desired to be caught. This means that exceptions +that are used to signify that the interpreter should exit should not +be caught in the common case. -But this line of reasoning has some issues. First is that it also -goes against the Zen of Python; both OWTDI and EIBTI by providing -an implicit alternative to ``except Exception``. Secondly, -backwards-compatibility becomes more difficult. While removal will -break code, it can mechanically be changed to have the same semantic -meaning as it currently has by finding all occurances of ``except:`` -and replacing them with ``except BaseException:``. But going with -this semantic change makes compatibility more subtle. Was a bare -``except`` clause meant to catch all exceptions, or actually meant -to catch all reasonable exceptions (i.e., everything but -TerminatingException)? Every case will need to be carefully -examined, and could easily be incorrectly examined, leading to subtle -bugs. +With KeyboardInterrupt and SystemExit moved to inherit from +BaseException instead of Exception, changing bare ``except`` clauses +to act as ``except Exception`` becomes a much more reasonable +default. This change also will break very little code since these +semantics are what most people want for bare ``except`` clauses. -The shorter typing afforded by bare ``except`` statements also does -not justify its existence. "Exception", the typical exception that\ -will be caught, is only nine characters. Add in the needed space to -separate "Exception" from "except" you get only 10 more characters to -type. While this might be a nuisance in quick-and-dirty scripts, the -impact is minimal. +The complete removal of bare ``except`` clauses has been argued for. +The case has been made that they violate both Only One Way To Do It +(OOWTDI) and Explicit Is Better Than Implicit (EIBTI) as listed in the +Zen of Python [#zen]_. But Practicality Beats Purity (PBP), also in +the Zen of Python, trumps both of these in this case. The BDFL has +stated that bare ``except`` clauses will work this way +[#python-dev8]_. Implementation -------------- -Changing Grammar/Grammar is all that is needed to remove bare -``except`` clauses. +The compiler will emit the bytecode for ``except Exception`` whenever +a bare ``except`` clause is reached. Transition Plan =============== -Exception Hierarchy Changes ---------------------------- - -New Exceptions -'''''''''''''' - -New exceptions can simply be added to the built-in namespace. Any -pre-existing objects with the same name will mask the new exceptions, -preserving backwards-compatibility. - - -New Inheritance for Old Exceptions -'''''''''''''''''''''''''''''''''' - -Using multiple inheritance to our advantage, exceptions whose -inheritance is now more resrictive can be made backwards-compatible. -By inheriting from both the new superclasses as well as the original -superclasses, existing ``except`` clauses will continue to work as -before while allowing the new inheritance to be used for new code. - -A PendingDeprecationWarning will be raised based on whether the -bytecode ``COMPARE_OP(10)`` results in an exception being caught that -would not have under the new hierarchy. This will require hard-coding -in the implementation of the bytecode. - - -Required Superclass for ``raise`` ---------------------------------- - -A DeprecationWarning will be raised when an object is passed to -``raise`` that does not have the proper inheritance. - - -Removal of Bare ``except`` Clauses ----------------------------------- - -A PendingDeprecationWarning will be raised when a bare ``except`` -clause is found in code. One release before they are removed the -warning will be changed to DeprecationWarning. - -Doing ``from __future__ import exceptions`` will cause bare -``except`` clauses to be considered syntax errors. - +Because of the complexity and clutter that would be required to add +all features planned in this PEP, the transition plan is very simple. +In Python |2.x| BaseException is added. In Python 3.0, all remaining +features (required superclass, change in inheritance, bare ``except`` +clauses becoming the same as ``except Exception``) will go into +affect. In order to make all of this work in a backwards-compatible +way in Python |2.x| would require very deep hacks in the exception +machinery which could be error-prone and lead to a slowdown in +performance for little benefit. -Roadmap -------- +To help with the transition, the documentation will be changed to +reflect several programming guidelines: -Python 2.x is the first version that contains changes. Python 3.0 -will be when transition will be complete. Version 3.0-1 represents -one version before 3.0 is released, 3.0-2 two versions before, etc. +- When one wants to catch *all* exceptions, catch BaseException +- To catch all exceptions that do not represent the termination of + the interpreter, catch Exception explicitly +- Explicitly catch KeyboardInterrupt and SystemExit; don't rely on + inheritance from Exception to lead to the capture +- Always catch NotImplementedError explicitly instead of relying on + the inheritance from RuntimeError -* 2.x - - Add BaseException, TerminatingException - - Have KeyboardInterrupt and SystemExit inherit from both - Exception and TerminatingException - - Introduce ``from __future__ import exceptions`` - - Provide a script that mechanically changes all bare ``except`` - clauses to catch BaseException in a .py file - - PendingDeprecationWarning for bare ``except`` clauses - - PendingDeprecationWarning for all objects raised that do not - inherit from BaseException - - PendingDeprecationWarning raised when KeyboardInterrupt or - SystemExit are caught because of their inheritance of Exception -* 3.0-1 - - Turn all introduced PendingDeprecationWarnings into - DeprecationWarning -* 3.0 - - Remove DeprecationWarnings - - Have KeyboardInterrupt and SystemExit only inherit from - TerminatingException - - Remove ``exceptions`` __future__ import support +The documentation for the 'exceptions' module [#exceptions-stdlib]_, +tutorial [#tutorial]_, and PEP 290 [#PEP290]_ will all require +updating. Rejected Ideas ============== -Multiple threads on python-dev discussing this PEP have lead to -various ideas being rejected [#python-dev-thread1]_, -[#python-dev-thread2]_, [#python-dev-thread3]_. - - DeprecationWarning Inheriting From PendingDeprecationWarning ------------------------------------------------------------ @@ -553,6 +420,17 @@ warrant it staying. +Superclass for KeyboardInterrupt and SystemExit +----------------------------------------------- + +Proposed to make catching non-Exception inheriting exceptions easier +along with easing the transition to the new hierarchy, the idea was +rejected by the BDFL [#python-dev8]_. The argument that existing +code did not show enough instances of the pair of exceptions being +caught and thus did not justify cluttering the built-in namespace +was used. + + Acknowledgements ================ @@ -572,6 +450,9 @@ .. [#PEP344] PEP 344 (Exception Chaining and Embedded Tracebacks) http://www.python.org/peps/pep-0344.html +.. [#PEP290] PEP 290 (Code Migration and Modernization) + http://www.python.org/peps/pep-0290.html + .. [#Summary2004-08-01] python-dev Summary (An exception is an exception, unless it doesn't inherit from Exception) http://www.python.org/dev/summary/2004-08-01_2004-08-15.html#an-exception-is-an-exception-unless-it-doesn-t-inherit-from-exception @@ -595,6 +476,15 @@ .. [#python-dev-thread3] python-dev thread (Reorg PEP checked in) http://mail.python.org/pipermail/python-dev/2005-August/055138.html +.. [#python-dev-thread4] python-dev thread (Major revision of PEP 348 committed) + http://mail.python.org/pipermail/python-dev/2005-August/055199.html + +.. [#python-dev-thread5] python-dev thread (Exception Reorg PEP revised yet again) + http://mail.python.org/pipermail/python-dev/2005-August/055292.html + +.. [#python-dev-thread6] python-dev thread (PEP 348 (exception reorg) revised again) + http://mail.python.org/pipermail/python-dev/2005-August/055412.html + .. [#python-dev4] python-dev email (Pre-PEP: Exception Reorganization for Python 3.0) http://mail.python.org/pipermail/python-dev/2005-July/055019.html @@ -609,9 +499,15 @@ .. [#python-dev7] python-dev email (Exception Reorg PEP checked in) http://mail.python.org/pipermail/python-dev/2005-August/055175.html +.. [#python-dev8] python-dev email (PEP 348 (exception reorg) revised again) + http://mail.python.org/pipermail/python-dev/2005-August/055423.html + .. [#zen] PEP 20 (The Zen of Python) http://www.python.org/peps/pep-0020.html +.. [#tutorial] Python Tutorial + http://docs.python.org/tut/tut.html + Copyright ========= From rhettinger at users.sourceforge.net Tue Aug 16 12:44:25 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 12:44:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_set.py,1.21,1.22 Message-ID: <20050816104425.1201D1E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10493/Lib/test Modified Files: test_set.py Log Message: Numerous fix-ups to C API and docs. Added tests for C API. Index: test_set.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_set.py,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- test_set.py 12 Aug 2005 23:58:22 -0000 1.21 +++ test_set.py 16 Aug 2005 10:44:15 -0000 1.22 @@ -6,6 +6,7 @@ import pickle import os from random import randrange, shuffle +import sys class PassThru(Exception): pass @@ -402,6 +403,11 @@ s = None self.assertRaises(ReferenceError, str, p) + # C API test only available in a debug build + if hasattr(sys, "gettotalrefcount"): + def test_c_api(self): + self.assertEqual(set('abc').test_c_api(), True) + class SetSubclass(set): pass @@ -1372,7 +1378,6 @@ #============================================================================== def test_main(verbose=None): - import sys from test import test_sets test_classes = ( TestSet, From rhettinger at users.sourceforge.net Tue Aug 16 12:44:25 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 12:44:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Include setobject.h,2.10,2.11 Message-ID: <20050816104425.2F2441E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10493/Include Modified Files: setobject.h Log Message: Numerous fix-ups to C API and docs. Added tests for C API. Index: setobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/setobject.h,v retrieving revision 2.10 retrieving revision 2.11 diff -u -d -r2.10 -r2.11 --- setobject.h 16 Aug 2005 03:47:51 -0000 2.10 +++ setobject.h 16 Aug 2005 10:44:15 -0000 2.11 @@ -79,7 +79,7 @@ PyAPI_FUNC(int) PySet_Size(PyObject *anyset); #define PySet_GET_SIZE(so) (((PySetObject *)(so))->used) PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key); -PyAPI_FUNC(int) PySet_Discard(PyObject *anyset, PyObject *key); +PyAPI_FUNC(int) PySet_Discard(PyObject *set, PyObject *key); PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); From rhettinger at users.sourceforge.net Tue Aug 16 12:44:25 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 12:44:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/api concrete.tex,1.62,1.63 Message-ID: <20050816104425.470121E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/api In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10493/Doc/api Modified Files: concrete.tex Log Message: Numerous fix-ups to C API and docs. Added tests for C API. Index: concrete.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/api/concrete.tex,v retrieving revision 1.62 retrieving revision 1.63 diff -u -d -r1.62 -r1.63 --- concrete.tex 16 Aug 2005 03:47:51 -0000 1.62 +++ concrete.tex 16 Aug 2005 10:44:12 -0000 1.63 @@ -2959,14 +2959,16 @@ Returns a new \class{set} containing objects returned by the \var{iterable}. The \var{iterable} may be \NULL{} to create a new empty set. Returns the new set on success or \NULL{} on - failure. + failure. Raises \exception{TypeError} if \var{iterable} is + not actually iterable. \end{cfuncdesc} \begin{cfuncdesc}{PyObject*}{PyFrozenSet_New}{PyObject *iterable} Returns a new \class{frozenset} containing objects returned by the \var{iterable}. The \var{iterable} may be \NULL{} to create a new empty frozenset. Returns the new set on success or \NULL{} on - failure. + failure. Raises \exception{TypeError} if \var{iterable} is + not actually iterable. \end{cfuncdesc} @@ -2976,7 +2978,7 @@ \begin{cfuncdesc}{int}{PySet_Size}{PyObject *anyset} Returns the length of a \class{set} or \class{frozenset} object. Equivalent to \samp{len(\var{anyset})}. Raises a - \exception{PyExc_SystemError} if the argument is not a \class{set}, + \exception{PyExc_SystemError} if \var{anyset} is not a \class{set}, \class{frozenset}, or an instance of a subtype. \bifuncindex{len} \end{cfuncdesc} @@ -2989,15 +2991,9 @@ Returns 1 if found, 0 if not found, and -1 if an error is encountered. Unlike the Python \method{__contains__()} method, this function does not automatically convert unhashable sets into temporary - frozensets. Raises a \exception{TypeError} if the key is unhashable. -\end{cfuncdesc} - -\begin{cfuncdesc}{int}{PySet_Discard}{PyObject *anyset, PyObject *key} - Returns 1 if found and removed, 0 if not found (no action taken), - and -1 if an error is encountered. Does not raise \exception{KeyError} - for missing keys. Raises a \exception{TypeError} if the key is unhashable. - Unlike the Python \method{discard()} method, this function does - not automatically convert unhashable sets into temporary frozensets. + frozensets. Raises a \exception{TypeError} if the \var{key} is unhashable. + Raises \exception{PyExc_SystemError} if \var{anyset} is not a \class{set}, + \class{frozenset}, or an instance of a subtype. \end{cfuncdesc} @@ -3007,17 +3003,27 @@ \begin{cfuncdesc}{int}{PySet_Add}{PyObject *set, PyObject *key} Adds \var{key} to a \class{set} instance. Does not apply to \class{frozenset} instances. Returns 0 on success or -1 on failure. - Raises a \exception{TypeError} if the key is unhashable. + Raises a \exception{TypeError} if the \var{key} is unhashable. Raises a \exception{MemoryError} if there is no room to grow. - Raises a \exception{SystemError} if \var{key} is an not an instance + Raises a \exception{SystemError} if \var{set} is an not an instance of \class{set} or its subtype. \end{cfuncdesc} +\begin{cfuncdesc}{int}{PySet_Discard}{PyObject *set, PyObject *key} + Returns 1 if found and removed, 0 if not found (no action taken), + and -1 if an error is encountered. Does not raise \exception{KeyError} + for missing keys. Raises a \exception{TypeError} if the \var{key} is + unhashable. Unlike the Python \method{discard()} method, this function + does not automatically convert unhashable sets into temporary frozensets. + Raises \exception{PyExc_SystemError} if \var{set} is an not an instance + of \class{set} or its subtype. +\end{cfuncdesc} + \begin{cfuncdesc}{PyObject*}{PySet_Pop}{PyObject *set} Returns a new reference to an arbitrary object in the \var{set}, and removes the object from the \var{set}. Returns \NULL{} on failure. Raises \exception{KeyError} if the set is empty. - Raises a \exception{SystemError} if \var{key} is an not an instance + Raises a \exception{SystemError} if \var{set} is an not an instance of \class{set} or its subtype. \end{cfuncdesc} From rhettinger at users.sourceforge.net Tue Aug 16 12:44:25 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 16 Aug 2005 12:44:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.51,1.52 Message-ID: <20050816104425.4E61B1E4029@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10493/Objects Modified Files: setobject.c Log Message: Numerous fix-ups to C API and docs. Added tests for C API. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.51 retrieving revision 1.52 diff -u -d -r1.51 -r1.52 --- setobject.c 16 Aug 2005 03:54:11 -0000 1.51 +++ setobject.c 16 Aug 2005 10:44:15 -0000 1.52 @@ -1697,6 +1697,13 @@ /* set object ********************************************************/ +#ifdef Py_DEBUG +static PyObject *test_c_api(PySetObject *so); + +PyDoc_STRVAR(test_c_api_doc, "Exercises C API. Returns True.\n\ +All is well if assertions don't fail."); +#endif + static PyMethodDef set_methods[] = { {"add", (PyCFunction)set_add, METH_O, add_doc}, @@ -1730,6 +1737,10 @@ symmetric_difference_doc}, {"symmetric_difference_update",(PyCFunction)set_symmetric_difference_update, METH_O, symmetric_difference_update_doc}, +#ifdef Py_DEBUG + {"test_c_api", (PyCFunction)test_c_api, METH_NOARGS, + test_c_api_doc}, +#endif {"union", (PyCFunction)set_union, METH_O, union_doc}, {"update", (PyCFunction)set_update, METH_O, @@ -1931,19 +1942,30 @@ PyObject * PyFrozenSet_New(PyObject *iterable) { - PyObject *args = NULL, *result; + PyObject *args, *result; - if (iterable != NULL) { + if (iterable == NULL) + args = PyTuple_New(0); + else args = PyTuple_Pack(1, iterable); - if (args == NULL) - return NULL; - } + if (args == NULL) + return NULL; result = frozenset_new(&PyFrozenSet_Type, args, NULL); - Py_XDECREF(args); + Py_DECREF(args); return result; } int +PySet_Size(PyObject *anyset) +{ + if (!PyAnySet_Check(anyset)) { + PyErr_BadInternalCall(); + return -1; + } + return ((PySetObject *)anyset)->used; +} + +int PySet_Contains(PyObject *anyset, PyObject *key) { if (!PyAnySet_Check(anyset)) { @@ -1954,13 +1976,13 @@ } int -PySet_Discard(PyObject *anyset, PyObject *key) +PySet_Discard(PyObject *set, PyObject *key) { - if (!PyAnySet_Check(anyset)) { + if (!PyType_IsSubtype(set->ob_type, &PySet_Type)) { PyErr_BadInternalCall(); return -1; } - return set_discard_key((PySetObject *)anyset, key); + return set_discard_key((PySetObject *)set, key); } int @@ -1982,3 +2004,92 @@ } return set_pop((PySetObject *)set); } + + +#ifdef Py_DEBUG + +/* Test code to be called with any three element set. + Returns True and original set is restored. */ + +#define assertRaises(call_return_value, exception) \ + do { \ + assert(call_return_value); \ + assert(PyErr_ExceptionMatches(exception)); \ + PyErr_Clear(); \ + } while(0) + +static PyObject * +test_c_api(PySetObject *so) +{ + PyObject *elem, *dup, *t, *f, *ob = (PyObject *)so; + + /* Verify preconditions and exercise type/size checks */ + assert(PyAnySet_Check(ob)); + assert(PyAnySet_CheckExact(ob)); + assert(!PyFrozenSet_CheckExact(ob)); + assert(PySet_Size(ob) == 3); + assert(PySet_GET_SIZE(ob) == 3); + + /* Raise TypeError for non-iterable constructor arguments */ + assertRaises(PySet_New(Py_None) == NULL, PyExc_TypeError); + assertRaises(PyFrozenSet_New(Py_None) == NULL, PyExc_TypeError); + + /* Raise TypeError for unhashable key */ + dup = PySet_New(ob); + assertRaises(PySet_Discard(ob, dup) == -1, PyExc_TypeError); + assertRaises(PySet_Contains(ob, dup) == -1, PyExc_TypeError); + assertRaises(PySet_Add(ob, dup) == -1, PyExc_TypeError); + + /* Exercise successful pop, contains, add, and discard */ + elem = PySet_Pop(ob); + assert(PySet_Contains(ob, elem) == 0); + assert(PySet_GET_SIZE(ob) == 2); + assert(PySet_Add(ob, elem) == 0); + assert(PySet_Contains(ob, elem) == 1); + assert(PySet_GET_SIZE(ob) == 3); + assert(PySet_Discard(ob, elem) == 1); + assert(PySet_GET_SIZE(ob) == 2); + assert(PySet_Discard(ob, elem) == 0); + assert(PySet_GET_SIZE(ob) == 2); + + /* Raise SystemError when self argument is not a set or frozenset. */ + t = PyTuple_New(0); + assertRaises(PySet_Size(t) == -1, PyExc_SystemError); + assertRaises(PySet_Contains(t, elem) == -1, PyExc_SystemError); + Py_DECREF(t); + + /* Raise SystemError when self argument is not a set. */ + f = PyFrozenSet_New(dup); + assert(PySet_Size(f) == 3); + assert(PyFrozenSet_CheckExact(f)); + assertRaises(PySet_Add(f, elem) == -1, PyExc_SystemError); + assertRaises(PySet_Discard(f, elem) == -1, PyExc_SystemError); + assertRaises(PySet_Pop(f) == NULL, PyExc_SystemError); + Py_DECREF(f); + + /* Raise KeyError when popping from an empty set */ + set_clear_internal(so); + assert(PySet_GET_SIZE(ob) == 0); + assertRaises(PySet_Pop(ob) == NULL, PyExc_KeyError); + + /* Restore the set from the copy and use the abstract API */ + assert(PyObject_CallMethod(ob, "update", "O", dup) == Py_None); + Py_DECREF(Py_None); + + /* Verify constructors accept NULL arguments */ + f = PySet_New(NULL); + assert(f != NULL); + assert(PySet_GET_SIZE(f) == 0); + Py_DECREF(f); + f = PyFrozenSet_New(NULL); + assert(f != NULL); + assert(PyFrozenSet_CheckExact(f)); + assert(PySet_GET_SIZE(f) == 0); + Py_DECREF(f); + + Py_DECREF(elem); + Py_DECREF(dup); + Py_RETURN_TRUE; +} + +#endif From gregorykjohnson at users.sourceforge.net Tue Aug 16 19:12:14 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Tue, 16 Aug 2005 19:12:14 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.8, 1.9 libmailbox.tex, 1.9, 1.10 Message-ID: <20050816171214.BBD231E4002@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5623 Modified Files: mailbox.py libmailbox.tex Log Message: * Overhaul locking: * Introduce lock() and unlock() methods: * Locking granularity should be up to the user. Otherwise, either consecutive operations that should be atomic are not or locks grow stale (in as little as 30 seconds) and are stolen. * Correct miscellaneous ill-conceived sections of locking code. Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- mailbox.py 13 Aug 2005 22:41:33 -0000 1.8 +++ mailbox.py 16 Aug 2005 17:12:03 -0000 1.9 @@ -169,6 +169,14 @@ """Write any pending changes to the disk.""" raise NotImplementedError, "Method must be implemented by subclass" + def lock(self): + """Lock the mailbox.""" + raise NotImplementedError, "Method must be implemented by subclass" + + def unlock(self, f=None): + """Unlock the mailbox if it is locked.""" + raise NotImplementedError, "Method must be implemented by subclass" + def close(self): """Flush and close the mailbox.""" raise NotImplementedError, "Method must be implemented by subclass" @@ -315,6 +323,14 @@ """Write any pending changes to disk.""" return # Maildir changes are always written immediately. + def lock(self): + """Lock the mailbox.""" + return + + def unlock(self, f=None): + """Unlock the mailbox if it is locked.""" + return + def close(self): """Flush and close the mailbox.""" return @@ -437,7 +453,7 @@ self._toc = None self._next_key = 0 self._pending = False # No changes require rewriting the file. - self._mtime = os.fstat(self._file.fileno()).st_mtime + self._locked = False def add(self, message): """Add message and return assigned key.""" @@ -449,6 +465,7 @@ def remove(self, key): """Remove the keyed message; raise KeyError if it doesn't exist.""" + self._lookup(key) del self._toc[key] self._pending = True @@ -474,54 +491,59 @@ self._lookup() return len(self._toc) + def lock(self): + """Lock the mailbox.""" + if not self._locked: + _lock_file(self._file) + self._locked = True + + def unlock(self, f=None): + """Unlock the mailbox if it is locked.""" + if self._locked: + _unlock_file(self._file) + self._locked = False + def flush(self): """Write any pending changes to disk.""" if not self._pending: return self._lookup() - _lock_file(self._file, self._path) + new_file = _create_temporary(self._path) try: - os.rename(self._path, self._path + '~') - _lock_file(self._file, self._path + '~', system=False) + new_toc = {} + self._pre_mailbox_hook(new_file) + for key in sorted(self._toc.keys()): + start, stop = self._toc[key] + self._file.seek(start) + self._pre_message_hook(new_file) + new_start = new_file.tell() + while True: + buffer = self._file.read(min(4096, + stop - self._file.tell())) + if buffer == '': + break + new_file.write(buffer) + new_toc[key] = (new_start, new_file.tell()) + self._post_message_hook(new_file) except: - _unlock_file(self._file, self._path) + new_file.close() + os.remove(new_file.name) raise + new_file.close() + self._file.close() try: - self._assert_mtime() - f = _create_carefully(self._path) - try: - _lock_file(f, self._path, dot=False) - try: - self._pre_mailbox_hook(f) - new_toc = {} - for key in sorted(self._toc.keys()): - start, stop = self._toc[key][:2] - self._file.seek(start) - self._pre_message_hook(f) - new_start = f.tell() - while True: - buffer = self._file.read( - min(4096, stop - self._file.tell())) - if buffer == '': - break - f.write(buffer) - new_toc[key] = (new_start, f.tell()) + \ - self._toc[key][2:] # XXX: Wrong! - self._post_message_hook(f) - finally: - _unlock_file(f, self._path) - except: - f.close() + os.rename(new_file.name, self._path) + except OSError, e: + if e.errno == errno.EEXIST: + os.remove(self._path) + os.rename(new_file.name, self._path) + else: raise - finally: - _unlock_file(self._file, self._path + '~') - self._file.close() + self._file = file(self._path, 'r+') self._toc = new_toc - self._file = f - self._file.flush() - self._set_mtime() - os.remove(self._path + '~') self._pending = False + if self._locked: + _lock_file(new_file, dotlock=False) def _pre_mailbox_hook(self, f): """Called before writing the mailbox to file f.""" @@ -538,6 +560,8 @@ def close(self): """Flush and close the mailbox.""" self.flush() + if self._locked: + self.unlock() self._file.close() def _lookup(self, key=None): @@ -550,39 +574,23 @@ except KeyError: raise KeyError, "No message with key '%s'" % key - def _assert_mtime(self): - """Raise an exception if the file has been externally modified.""" - if self._mtime != os.fstat(self._file.fileno()).st_mtime: - raise ExternalClashError, \ - 'External modifications detected: use refresh()' - - def _set_mtime(self): - """Store the current mtime.""" - self._mtime = os.fstat(self._file.fileno()).st_mtime - def _append_message(self, message): """Append message to mailbox and return (start, stop, ...) offsets.""" - _lock_file(self._file, self._path) - try: - self._assert_mtime() - self._file.seek(0, 2) - self._pre_message_hook(self._file) - offsets = self._install_message(message) - self._post_message_hook(self._file) - self._file.flush() - self._set_mtime() - finally: - _unlock_file(self._file, self._path) + self._file.seek(0, 2) + self._pre_message_hook(self._file) + offsets = self._install_message(message) + self._post_message_hook(self._file) + self._file.flush() return offsets + class _mboxMMDF(_singlefileMailbox): """An mbox or MMDF mailbox.""" def get_message(self, key): """Return a Message representation or raise a KeyError.""" start, stop = self._lookup(key) - self._assert_mtime() self._file.seek(start) from_line = self._file.readline() msg = self._message_factory(self._file.read(stop - self._file.tell())) @@ -592,7 +600,6 @@ def get_string(self, key, from_=False): """Return a string representation or raise a KeyError.""" start, stop = self._lookup(key) - self._assert_mtime() self._file.seek(start) if not from_: self._file.readline() @@ -601,7 +608,6 @@ def get_file(self, key, from_=False): """Return a file-like representation or raise a KeyError.""" start, stop = self._lookup(key) - self._assert_mtime() self._file.seek(start) if not from_: self._file.readline() @@ -649,7 +655,6 @@ """Generate key-to-(start, stop) table of contents.""" starts, stops = [], [] self._file.seek(0) - self._assert_mtime() while True: line_pos = self._file.tell() line = self._file.readline() @@ -685,7 +690,6 @@ starts, stops = [], [] self._file.seek(0) next_pos = 0 - self._assert_mtime() while True: line_pos = next_pos line = self._file.readline() @@ -718,9 +722,10 @@ if create: os.mkdir(self._path, 0700) os.close(os.open(os.path.join(self._path, '.mh_sequences'), - os.O_CREAT | os.O_WRONLY, 0600)) + os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0600)) else: raise NoSuchMailboxError, self._path + self._locked = False def add(self, message): """Add message and return assigned key.""" @@ -732,62 +737,85 @@ new_path = os.path.join(self._path, str(new_key)) f = _create_carefully(new_path) try: - _lock_file(f, f.name) + if self._locked: + _lock_file(f) try: self._dump_message(message, f) if isinstance(message, MHMessage): self._dump_sequences(message, new_key) finally: - _unlock_file(f, f.name) + if self._locked: + _unlock_file(f) finally: f.close() return new_key def remove(self, key): """Remove the keyed message; raise KeyError if it doesn't exist.""" + path = os.path.join(self._path, str(key)) try: - os.remove(os.path.join(self._path, str(key))) - except OSError, e: + f = file(path, 'r+') + except IOError, e: if e.errno == errno.ENOENT: raise KeyError, "No message with key '%s'" % key else: raise + try: + if self._locked: + _lock_file(f) + try: + f.close() + os.remove(os.path.join(self._path, str(key))) + finally: + if self._locked: + _unlock_file(f) + finally: + f.close() def __setitem__(self, key, message): """Replace the keyed message; raise KeyError if it doesn't exist.""" + path = os.path.join(self._path, str(key)) try: - f_r = file(os.path.join(self._path, str(key)), 'r+') + f = file(path, 'r+') except IOError, e: if e.errno == errno.ENOENT: raise KeyError, "No message with key '%s'" % key else: raise try: - _lock_file(f_r, f_r.name) + if self._locked: + _lock_file(f) try: - f_w = file(os.path.join(self._path, str(key)), 'w') - try: - self._dump_message(message, f_w) - if isinstance(message, MHMessage): - self._dump_sequences(message, key) - finally: - f_w.close() + os.close(os.open(path, os.O_WRONLY | os.O_TRUNC)) + self._dump_message(message, f) + if isinstance(message, MHMessage): + self._dump_sequences(message, key) finally: - _unlock_file(f_r, f_r.name) + if self._locked: + _unlock_file(f) finally: - f_r.close() + f.close() def get_message(self, key): """Return a Message representation or raise a KeyError.""" try: - f = file(os.path.join(self._path, str(key)), 'r') + if self._locked: + f = file(os.path.join(self._path, str(key)), 'r+') + else: + f = file(os.path.join(self._path, str(key)), 'r') except IOError, e: if e.errno == errno.ENOENT: raise KeyError, "No message with key '%s'" % key else: raise try: - msg = MHMessage(f) + if self._locked: + _lock_file(f) + try: + msg = MHMessage(f) + finally: + if self._locked: + _unlock_file(f) finally: f.close() for name, key_list in self.get_sequences(): @@ -798,14 +826,23 @@ def get_string(self, key): """Return a string representation or raise a KeyError.""" try: - f = file(os.path.join(self._path, str(key)), 'r') + if self._locked: + f = file(os.path.join(self._path, str(key)), 'r+') + else: + f = file(os.path.join(self._path, str(key)), 'r') except IOError, e: if e.errno == errno.ENOENT: raise KeyError, "No message with key '%s'" % key else: raise try: - return f.read() + if self._locked: + _lock_file(f) + try: + return f.read() + finally: + if self._locked: + _unlock_file() finally: f.close() @@ -833,13 +870,29 @@ """Return a count of messages in the mailbox.""" return len(list(self.iterkeys())) + def lock(self): + """Lock the mailbox.""" + if not self._locked: + self._file = file(os.path.join(self._path, '.mh_sequences'), 'r+') + _lock_file(self._file) + self._locked = True + + def unlock(self, f=None): + """Unlock the mailbox if it is locked.""" + if self._locked: + _unlock_file(self._file) + self._file.close() + del self._file + self._locked = False + def flush(self): """Write any pending changes to the disk.""" return def close(self): """Flush and close the mailbox.""" - return + if self._locked: + self.unlock() def list_folders(self): """Return a list of folder names.""" @@ -855,7 +908,7 @@ def add_folder(self, folder): """Create a folder and return an MH instance representing it.""" - return Maildir(os.path.join(self._path, '.' + folder)) + return MH(os.path.join(self._path, '.' + folder)) def remove_folder(self, folder): """Delete the named folder, which must be empty.""" @@ -899,36 +952,28 @@ """Set sequences using the given name-to-key-list dictionary.""" f = file(os.path.join(self._path, '.mh_sequences'), 'r+') try: - _lock_file(f, f.name) - try: - # .truncate() is not portable, so re-open to truncate. - f_w = file(os.path.join(self._path, '.mh_sequences'), 'w') - try: - for name, keys in sequences.iteritems(): - if len(keys) == 0: - continue - f_w.write('%s:' % name) - prev = None + os.close(os.open(f.name, os.O_WRONLY | os.O_TRUNC)) + for name, keys in sequences.iteritems(): + if len(keys) == 0: + continue + f.write('%s:' % name) + prev = None + completing = False + for key in sorted(set(keys)): + if key - 1 == prev: + if not completing: + completing = True + fw.write('-') + elif completing: completing = False - for key in sorted(set(keys)): - if key - 1 == prev: - if not completing: - completing = True - f_w.write('-') - elif completing: - completing = False - f_w.write('%s %s' % (prev, key)) - else: - f_w.write(' %s' % key) - prev = key - if completing: - f_w.write('%s%s' % (prev, os.linesep)) - else: - f_w.write(os.linesep) - finally: - f_w.close() - finally: - _unlock_file(f, f.name) + f.write('%s %s' % (prev, key)) + else: + f.write(' %s' % key) + prev = key + if completing: + f.write('%s%s' % (prev, os.linesep)) + else: + f.write(os.linesep) finally: f.close() @@ -940,13 +985,24 @@ for key in self.iterkeys(): if key - 1 != prev: changes.append((key, prev + 1)) - if hasattr(os, 'link'): - os.link(os.path.join(self._path, str(key)), - os.path.join(self._path, str(prev + 1))) - os.unlink(os.path.join(self._path, str(key))) - else: - os.rename(os.path.join(self._path, str(key)), - os.path.join(self._path, str(prev + 1))) + f = file(os.path.join(self._path, str(key)), 'r+') + try: + if self._locked: + _lock_file(f) + try: + if hasattr(os, 'link'): + os.link(os.path.join(self._path, str(key)), + os.path.join(self._path, str(prev + 1))) + os.unlink(os.path.join(self._path, str(key))) + else: + f.close() + os.rename(os.path.join(self._path, str(key)), + os.path.join(self._path, str(prev + 1))) + finally: + if self._locked: + _unlock_file(f) + finally: + f.close() prev += 1 self._next_key = prev + 1 if len(changes) == 0: @@ -979,7 +1035,6 @@ def get_message(self, key): """Return a Message representation or raise a KeyError.""" start, stop = self._lookup(key) - self._assert_mtime() self._file.seek(start) self._file.readline() # XXX: parse this '1,' line for labels original_headers = StringIO.StringIO() @@ -1002,7 +1057,6 @@ def get_string(self, key): """Return a string representation or raise a KeyError.""" start, stop = self._lookup(key) - self._assert_mtime() self._file.seek(start) self._file.readline() # Skip '1,' line. original_headers = StringIO.StringIO() @@ -1031,7 +1085,6 @@ starts, stops = [], [] self._file.seek(0) next_pos = 0 - self._assert_mtime() while True: line_pos = next_pos line = self._file.readline() @@ -1614,35 +1667,30 @@ return _ProxyFile._read(self, size, read_method) -def _lock_file(f, path, system=True, dot=True): +def _lock_file(f, dotlock=True): """Lock file f using lockf, flock, and dot locking.""" - lockf_done = flock_done = dotlock_done = False try: - if system and fcntl: + if fcntl: try: fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB) - lockf_done = True except IOError, e: if e.errno == errno.EAGAIN: raise ExternalClashError, \ - "lockf: lock unavailable: %s" % path + "lockf: lock unavailable: %s" % f.name else: raise try: fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) - flock_done = True except IOError, e: if e.errno == errno.EWOULDBLOCK: raise ExternalClashError, \ - "flock: lock unavailable: %s" % path + "flock: lock unavailable: %s" % f.name else: raise - if dot: - tmp = '%s.lock.%s.%s.%s' % (path, int(time.time()), - socket.gethostname(), os.getpid()) + if dotlock: try: - os.close(os.open(tmp, os.O_WRONLY | os.O_EXCL | os.O_CREAT, - 0600)) + pre_lock = _create_temporary(f.name + '.lock') + pre_lock.close() except IOError, e: if e.errno == errno.EACCESS: return # Without write access, just skip dotlocking. @@ -1650,40 +1698,48 @@ raise try: if hasattr(os, 'link'): - os.link(tmp, path + '.lock') - os.unlink(tmp) + os.link(pre_lock.name, f.name + '.lock') + dotlock_done = True + os.unlink(pre_lock) else: - os.rename(tmp, path + '.lock') - dotlock_done = True + os.rename(pre_lock, f.name + '.lock') + dotlock_done = True except OSError, e: if e.errno == errno.EEXIST: - try: - os.remove(tmp) - except: - pass - raise ExternalClashError, 'dot lock unavailable: %s' % path + os.remove(pre_lock) + raise ExternalClashError, 'dot lock unavailable: %s' % \ + f.name else: raise except: - if lockf_done: + if fcntl: fcntl.lockf(f, fcntl.LOCK_UN) - if flock_done: fcntl.flock(f, fcntl.LOCK_UN) if dotlock_done: - os.remove(path + '.lock') + os.remove(f.name + '.lock') raise -def _unlock_file(f, path, system=True, dot=True): +def _unlock_file(f): """Unlock file f using lockf, flock, and dot locking.""" - if system and fcntl: + if fcntl: fcntl.lockf(f, fcntl.LOCK_UN) fcntl.flock(f, fcntl.LOCK_UN) - if dot and os.path.exists(path + '.lock'): - os.remove(path + '.lock') + if os.path.exists(path + '.lock'): + os.remove(f.name + '.lock') def _create_carefully(path): """Create a file if it doesn't exist and open for reading and writing.""" - return os.fdopen(os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR), 'r+') + fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR) + try: + return file(path, 'r+') + finally: + os.close(fd) + +def _create_temporary(path): + """Create a temp file based on path and open for reading and writing.""" + return _create_carefully('%s.%s.%s.%s' % (path, int(time.time()), + socket.gethostname(), + os.getpid())) class Error(Exception): """Raised for module-specific errors.""" Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- libmailbox.tex 13 Aug 2005 22:41:33 -0000 1.9 +++ libmailbox.tex 16 Aug 2005 17:12:03 -0000 1.10 @@ -221,9 +221,20 @@ subclasses, changes are written immediately and this method does nothing. \end{methoddesc} +\begin{methoddesc}{lock}{} +Acquire an exclusive advisory lock on the mailbox so that other processes know +not to modify it. An \exception{ExternalClashError} is raised if the lock is +not available. The particular locking mechanisms used depend upon the mailbox +format. +\end{methoddesc} + +\begin{methoddesc}{unlock}{} +Release the advisory lock on the mailbox, if any. +\end{methoddesc} + \begin{methoddesc}{close}{} -Flush the mailbox and close any open files. For some \class{Mailbox} -subclasses, this method does nothing. +Flush the mailbox, unlock it if necessary, and close any open files. For some +\class{Mailbox} subclasses, this method does nothing. \end{methoddesc} @@ -305,9 +316,14 @@ nothing. \end{methoddesc} +\begin{methoddesc}{lock}{} +\methodline{unlock}{} +Maildir mailboxes do not support (or require) locking, so these methods do +nothing. \end{methoddesc} + \begin{methoddesc}{close}{} -\class{Maildir} instances do not keep any open files, so this method does -nothing. +\class{Maildir} instances do not keep any open files and the underlying +mailboxes do not support locking, so this method does nothing. \end{methoddesc} \begin{methoddesc}{get_file}{key} @@ -356,6 +372,12 @@ XXX \end{methoddesc} +\begin{methoddesc}{lock}{} +\methodline{unlock}{} +Three locking mechanisms are used---dot locking and, if available, the +\cfunction{flock()} and \cfunction{lockf()} system calls. +\end{methoddesc} + \begin{seealso} \seelink{http://www.qmail.org/man/man5/mbox.html}{mbox man page from qmail}{A specification of the format and its variations.} @@ -450,6 +472,15 @@ marking a message for deletion by prepending a comma to its name is not used. \end{methoddesc} +\begin{methoddesc}{lock}{} +\methodline{unlock}{} +Three locking mechanisms are used---dot locking and, if available, the +\cfunction{flock()} and \cfunction{lockf()} system calls. For MH mailboxes, +locking the mailbox means locking the \file{.mh_sequences} file and, only for +the duration of any operations that affect them, locking individual message +files. +\end{methoddesc} + \begin{methoddesc}{get_file}{key} XXX \end{methoddesc} @@ -460,7 +491,8 @@ \end{methoddesc} \begin{methoddesc}{close}{} -\class{MH} instances do not keep any open files, so this method does nothing. +\class{MH} instances do not keep any open files, so this method is equivelant +to \method{unlock()}. \end{methoddesc} \class{MH} instances have all of the methods of \class{Mailbox} in addition to @@ -521,6 +553,12 @@ module), which may be used like a file. \end{methoddesc} +\begin{methoddesc}{lock}{} +\methodline{unlock}{} +Three locking mechanisms are used---dot locking and, if available, the +\cfunction{flock()} and \cfunction{lockf()} system calls. +\end{methoddesc} + \begin{seealso} \seelink{http://quimby.gnus.org/notes/BABYL}{Format of Version 5 Babyl Files}{A specification of the Babyl format.} @@ -554,6 +592,12 @@ XXX \end{methoddesc} +\begin{methoddesc}{lock}{} +\methodline{unlock}{} +Three locking mechanisms are used---dot locking and, if available, the +\cfunction{flock()} and \cfunction{lockf()} system calls. +\end{methoddesc} + \begin{seealso} \seelink{http://www.tin.org/bin/man.cgi?section=5\&topic=mmdf}{mmdf man page from tin}{A specification of MMDF format from the documentation of tin, a From loewis at users.sourceforge.net Tue Aug 16 20:17:10 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Tue, 16 Aug 2005 20:17:10 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.13,1.14 Message-ID: <20050816181710.F03C31E4002@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24270 Modified Files: pep-0347.txt Log Message: Remove remaining mentioning of basic auth. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- pep-0347.txt 13 Aug 2005 01:47:28 -0000 1.13 +++ pep-0347.txt 16 Aug 2005 18:17:00 -0000 1.14 @@ -151,6 +151,12 @@ support the project/trunk structure, each project needs to be converted separately. To get each conversion result into a separate directory in the target repository, svnadmin load must be used. + +Subversion has a different view on binary-vs-text files than CVS. +To correctly carry the CVS semantics forward, svn:eol-style should +be set to native on all files that are not marked binary in the +CVS. + In summary, the conversion script is:: #!/bin/sh @@ -184,18 +190,18 @@ Publish the Repository ------------------------ -The repository should be published at https://svn.python.org/projects. -Read-write access should be granted through basic authentication to -all current SF committers; read-only anonymous access should also be -granted. Read-write access will go through -svn+ssh://pythondev at svn.python.org/projects. +The repository should be published at http://svn.python.org/projects. +Read-write access should be granted to all current SF committers +through svn+ssh://pythondev at svn.python.org/projects; +read-only anonymous access through WebDAV should also be +granted. As an option, websvn (available e.g. from the Debian websvn package) could be provided. Unfortunately, in the test installation, websvn breaks because it runs out of memory. -The current SF project admins should get write access to the password -file, in order to create or delete new users. +The current SF project admins should get write access to the +authorized_keys file of the pythondev account. Disable CVS From gregorykjohnson at users.sourceforge.net Wed Aug 17 01:38:22 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Wed, 17 Aug 2005 01:38:22 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.9, 1.10 libmailbox.tex, 1.10, 1.11 test_mailbox.py, 1.7, 1.8 Message-ID: <20050816233822.5D4761E4002@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2326 Modified Files: mailbox.py libmailbox.tex test_mailbox.py Log Message: * Add delivery date support to MaildirMessage and Maildir, and support for conversion between delivery dates in MaildirMessage, mboxMessage, and MMDFMessage instances. * Don't guess delivery dates from headers. * Add full support for labels to Babyl. * Small tweaks: * Remove outdated "start, stop, ..." mentions in comments. * Change exception raising style: use "Exception(...)" instead of "Exception, ..." in accordance with Raymond Hettinger's comment in the Python Tutorial and A.M. Kuchling's recent post on python-dev. * Use ": %s" consistently in exception messages, not " '%s'". Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- mailbox.py 16 Aug 2005 17:12:03 -0000 1.9 +++ mailbox.py 16 Aug 2005 23:38:11 -0000 1.10 @@ -4,6 +4,7 @@ import os import time +import calendar import socket import errno import stat @@ -33,11 +34,11 @@ def add(self, message): """Add message and return assigned key.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def remove(self, key): """Remove the keyed message; raise KeyError if it doesn't exist.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def __delitem__(self, key): self.remove(key) @@ -51,7 +52,7 @@ def __setitem__(self, key, message): """Replace the keyed message; raise KeyError if it doesn't exist.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def get(self, key, default=None): """Return the keyed message, or default if it doesn't exist.""" @@ -69,19 +70,19 @@ def get_message(self, key): """Return a Message representation or raise a KeyError.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def get_string(self, key): """Return a string representation or raise a KeyError.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def get_file(self, key): """Return a file-like representation or raise a KeyError.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def iterkeys(self): """Return an iterator over keys.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def keys(self): """Return a list of keys.""" @@ -118,14 +119,14 @@ def has_key(self, key): """Return True if the keyed message exists, False otherwise.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def __contains__(self, key): return self.has_key(key) def __len__(self): """Return a count of messages in the mailbox.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def clear(self): """Delete all messages.""" @@ -146,7 +147,7 @@ for key in self.iterkeys(): return (key, self.pop(key)) # This is only run once. else: - raise KeyError, "No messages in mailbox" + raise KeyError('No messages in mailbox') def update(self, arg=None): """Change the messages that correspond to certain keys.""" @@ -163,23 +164,23 @@ except KeyError: bad_key = True if bad_key: - raise KeyError, "No message with key(s)" + raise KeyError('No message with key(s)') def flush(self): """Write any pending changes to the disk.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def lock(self): """Lock the mailbox.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def unlock(self, f=None): """Unlock the mailbox if it is locked.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def close(self): """Flush and close the mailbox.""" - raise NotImplementedError, "Method must be implemented by subclass" + raise NotImplementedError('Method must be implemented by subclass') def _dump_message(self, message, target): """Dump message contents to target file.""" @@ -195,7 +196,7 @@ break target.write(buffer) else: - raise TypeError, "Invalid message type" + raise TypeError('Invalid message type: %s' % type(message)) class Maildir(Mailbox): @@ -211,7 +212,7 @@ os.mkdir(os.path.join(self._path, 'new'), 0700) os.mkdir(os.path.join(self._path, 'cur'), 0700) else: - raise NoSuchMailboxError, self._path + raise NoSuchMailboxError(self._path) self._toc = {} def add(self, message): @@ -232,6 +233,8 @@ uniq = os.path.basename(tmp_file.name).split(':')[0] dest = os.path.join(self._path, subdir, uniq + suffix) os.rename(tmp_file.name, dest) + if isinstance(message, MaildirMessage): + os.utime(dest, (os.path.getatime(dest), message.get_date())) return uniq def remove(self, key): @@ -268,9 +271,11 @@ else: suffix = '' self.discard(key) - os.rename(os.path.join(self._path, temp_subpath), - os.path.join(self._path, subdir, key + suffix)) - # XXX: the mtime should be reset to keep delivery date + new_path = os.path.join(self._path, subdir, key + suffix) + os.rename(os.path.join(self._path, temp_subpath), new_path) + if isinstance(message, MaildirMessage): + os.utime(new_path, (os.path.getatime(new_path), + message.get_date())) def get_message(self, key): """Return a Message representation or raise a KeyError.""" @@ -284,6 +289,7 @@ msg.set_subdir(subdir) if ':' in name: msg.set_info(name.split(':')[-1]) + msg.set_date(os.path.getmtime(os.path.join(self._path, subpath))) return msg def get_string(self, key): @@ -363,12 +369,12 @@ for entry in os.listdir(os.path.join(path, 'new')) + \ os.listdir(os.path.join(path, 'cur')): if len(entry) < 1 or entry[0] != '.': - raise NotEmptyError, "Folder '%s' contains message" % folder + raise NotEmptyError('Folder contains message(s): %s' % folder) for entry in os.listdir(path): if entry != 'new' and entry != 'cur' and entry != 'tmp' and \ os.path.isdir(os.path.join(path, entry)): - raise NotEmptyError, "Folder '%s' contains subdirectory '%s'" \ - % (folder, entry) + raise NotEmptyError("Folder contains subdirectory '%s': %s" % + (folder, entry)) for root, dirs, files in os.walk(path, topdown=False): for entry in files: os.remove(os.path.join(root, entry)) @@ -406,8 +412,8 @@ else: raise else: - raise ExternalClashError, \ - "Name clash prevented file creation: '%s'" % path + raise ExternalClashError('Name clash prevented file creation: %s' % + path) def _refresh(self): """Update table of contents mapping.""" @@ -428,7 +434,7 @@ try: return self._toc[key] except KeyError: - raise KeyError, "No message with key '%s'" % key + raise KeyError('No message with key: %s' % key) class _singlefileMailbox(Mailbox): @@ -444,7 +450,7 @@ if create: f = file(self._path, 'w+') else: - raise NoSuchMailboxError, self._path + raise NoSuchMailboxError(self._path) elif e.errno == errno.EACCES: f = file(self._path, 'r') else: @@ -565,17 +571,17 @@ self._file.close() def _lookup(self, key=None): - """Return (start, stop), possibly with more info, or raise KeyError.""" + """Return (start, stop) or raise KeyError.""" if self._toc is None: self._generate_toc() if key is not None: try: return self._toc[key] except KeyError: - raise KeyError, "No message with key '%s'" % key + raise KeyError('No message with key: %s' % key) def _append_message(self, message): - """Append message to mailbox and return (start, stop, ...) offsets.""" + """Append message to mailbox and return (start, stop) offsets.""" self._file.seek(0, 2) self._pre_message_hook(self._file) offsets = self._install_message(message) @@ -629,8 +635,7 @@ elif isinstance(message, email.Message.Message): from_line = message.get_unixfrom() # May be None. if from_line is None: - from_line = 'From MAILER-DAEMON %s' % \ - time.strftime('%a %b %d %H:%M:%S %Y', time.gmtime()) + from_line = 'From MAILER-DAEMON %s' % time.asctime(time.gmtime()) start = self._file.tell() self._file.write('%s%s' % (from_line, os.linesep)) self._dump_message(message, self._file) @@ -724,7 +729,7 @@ os.close(os.open(os.path.join(self._path, '.mh_sequences'), os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0600)) else: - raise NoSuchMailboxError, self._path + raise NoSuchMailboxError(self._path) self._locked = False def add(self, message): @@ -757,7 +762,7 @@ f = file(path, 'r+') except IOError, e: if e.errno == errno.ENOENT: - raise KeyError, "No message with key '%s'" % key + raise KeyError('No message with key: %s' % key) else: raise try: @@ -779,7 +784,7 @@ f = file(path, 'r+') except IOError, e: if e.errno == errno.ENOENT: - raise KeyError, "No message with key '%s'" % key + raise KeyError('No message with key: %s' % key) else: raise try: @@ -805,7 +810,7 @@ f = file(os.path.join(self._path, str(key)), 'r') except IOError, e: if e.errno == errno.ENOENT: - raise KeyError, "No message with key '%s'" % key + raise KeyError('No message with key: %s' % key) else: raise try: @@ -832,7 +837,7 @@ f = file(os.path.join(self._path, str(key)), 'r') except IOError, e: if e.errno == errno.ENOENT: - raise KeyError, "No message with key '%s'" % key + raise KeyError('No message with key: %s' % key) else: raise try: @@ -852,7 +857,7 @@ f = file(os.path.join(self._path, str(key)), 'r') except IOError, e: if e.errno == errno.ENOENT: - raise KeyError, "No message with key '%s'" % key + raise KeyError('No message with key: %s' % key) else: raise return _ProxyFile(f) @@ -919,8 +924,7 @@ elif entries == []: pass else: - raise NotEmptyError, "Folder '%s' is not empty" % \ - self._path + raise NotEmptyError('Folder not empty: %s' % self._path) os.rmdir(path) def get_sequences(self): @@ -942,8 +946,8 @@ results[name] = [key for key in sorted(keys) \ if key in all_keys] except ValueError: - raise FormatError, "Invalid sequence specification: " % \ - "'%s'" % line.rstrip() + raise FormatError('Invalid sequence specification: %s' % + line.rstrip()) finally: f.close() return results @@ -1032,11 +1036,38 @@ class Babyl(_singlefileMailbox): """An Rmail-style Babyl mailbox.""" + _special_labels = frozenset(('unseen', 'deleted', 'filed', 'answered', + 'forwarded', 'edited', 'resent')) + + def __init__(self, path, factory=None, create=True): + """Initialize a Babyl mailbox.""" + _singlefileMailbox.__init__(self, path, factory, create) + self._labels = {} + + def add(self, message): + """Add message and return assigned key.""" + key = _singlefileMailbox.add(self, message) + if isinstance(message, BabylMessage): + self._labels[key] = message.get_labels() + return key + + def remove(self, key): + """Remove the keyed message; raise KeyError if it doesn't exist.""" + _singlefileMailbox.remove(self, key) + if key in self._labels: + del self._labels[key] + + def __setitem__(self, key, message): + """Replace the keyed message; raise KeyError if it doesn't exist.""" + _singlefileMailbox.__setitem__(self, key, message) + if isinstance(message, BabylMessage): + self._labels[key] = message.get_labels() + def get_message(self, key): """Return a Message representation or raise a KeyError.""" start, stop = self._lookup(key) self._file.seek(start) - self._file.readline() # XXX: parse this '1,' line for labels + self._file.readline() # Skip '1,' line specifying labels. original_headers = StringIO.StringIO() while True: line = self._file.readline() @@ -1052,13 +1083,15 @@ body = self._file.read(stop - self._file.tell()) msg = BabylMessage(original_headers.getvalue() + body) msg.set_visible(visible_headers.getvalue()) + if key in self._labels: + msg.set_labels(self._labels[key]) return msg def get_string(self, key): """Return a string representation or raise a KeyError.""" start, stop = self._lookup(key) self._file.seek(start) - self._file.readline() # Skip '1,' line. + self._file.readline() # Skip '1,' line specifying labels. original_headers = StringIO.StringIO() while True: line = self._file.readline() @@ -1078,13 +1111,19 @@ def get_labels(self): """Return a list of user-defined labels in the mailbox.""" - raise NotImplementedError, 'Method not yet implemented' + self._lookup() + labels = set() + for label_list in self._labels.values(): + labels.update(label_list) + labels.difference_update(self._special_labels) + return list(labels) def _generate_toc(self): - """Generate key-to-(start, stop, eooh, body) table of contents.""" + """Generate key-to-(start, stop) table of contents.""" starts, stops = [], [] self._file.seek(0) next_pos = 0 + label_lists = [] while True: line_pos = next_pos line = self._file.readline() @@ -1093,6 +1132,10 @@ if len(stops) < len(starts): stops.append(line_pos - len(os.linesep)) starts.append(next_pos) + labels = [label.strip() for label + in self._file.readline()[1:].split(',') + if label.strip() != ''] + label_lists.append(labels) elif line == '\037' or line == '\037' + os.linesep: if len(stops) < len(starts): stops.append(line_pos - len(os.linesep)) @@ -1100,12 +1143,13 @@ stops.append(line_pos - len(os.linesep)) break self._toc = dict(enumerate(zip(starts, stops))) + self._labels = dict(enumerate(label_lists)) self._next_key = len(self._toc) def _pre_mailbox_hook(self, f): """Called before writing the mailbox to file f.""" - f.write('BABYL OPTIONS:%sVersion: 5%s\037' % (os.linesep, os.linesep)) - # XXX: write "Labels:" line too + f.write('BABYL OPTIONS:\nVersion: 5\nLabels:%s\n\037' % + ','.join(self.get_labels())) def _pre_message_hook(self, f): """Called before writing each message to file f.""" @@ -1116,9 +1160,25 @@ f.write('\n\037') def _install_message(self, message): - """Write message contents and return (start, stop, ...).""" + """Write message contents and return (start, stop).""" start = self._file.tell() - self._file.write('1,,\n') # XXX: check for labels and add them + if isinstance(message, BabylMessage): + special_labels = [] + labels = [] + for label in message.get_labels(): + if label in self._special_labels: + special_labels.append(label) + else: + labels.append(label) + self._file.write('1') + for label in special_labels: + self._file.write(', ' + label) + self._file.write(',,') + for label in labels: + self._file.write(' ' + label + ',') + self._file.write('\n') + else: + self._file.write('1,,\n') if isinstance(message, email.Message.Message): pseudofile = StringIO.StringIO() ps_generator = email.Generator.Generator(pseudofile, False, 0) @@ -1175,7 +1235,7 @@ break self._file.write(buffer) else: - raise TypeError, "Invalid message type" + raise TypeError('Invalid message type: %s' % type(message)) stop = self._file.tell() return (start, stop) @@ -1196,7 +1256,7 @@ elif message is None: email.Message.Message.__init__(self) else: - raise TypeError, "Invalid message type" + raise TypeError('Invalid message type: %s' % type(message)) def _become_message(self, message): """Assume the non-format-specific state of message.""" @@ -1209,7 +1269,7 @@ if isinstance(message, Message): return # There's nothing format-specific to explain. else: - raise TypeError, "Cannot convert to specified type" + raise TypeError('Cannot convert to specified type') class MaildirMessage(Message): @@ -1219,6 +1279,7 @@ """Initialize a MaildirMessage instance.""" self._subdir = 'new' self._info = '' + self._date = time.time() Message.__init__(self, message) def get_subdir(self): @@ -1230,7 +1291,7 @@ if subdir == 'new' or subdir == 'cur': self._subdir = subdir else: - raise ValueError, "subdir must be 'new' or 'cur'" + raise ValueError("subdir must be 'new' or 'cur': %s" % subdir) def get_flags(self): """Return as a string the flags that are set.""" @@ -1252,6 +1313,17 @@ if self.get_flags() != '': self.set_flags(''.join(set(self.get_flags()) - set(flag))) + def get_date(self): + """Return delivery date of message, in seconds since the epoch.""" + return self._date + + def set_date(self, date): + """Set delivery date of message, in seconds since the epoch.""" + try: + self._date = float(date) + except ValueError: + raise TypeError("can't convert to float: %s" % date) + def get_info(self): """Get the message's "info" as a string.""" return self._info @@ -1261,13 +1333,14 @@ if isinstance(info, str): self._info = info else: - raise TypeError, "info must be a string" + raise TypeError('info must be a string: %s' % type(info)) def _explain_to(self, message): """Copy Maildir-specific state to message insofar as possible.""" if isinstance(message, MaildirMessage): message.set_flags(self.get_flags()) message.set_subdir(self.get_subdir()) + message.set_date(self.get_date()) elif isinstance(message, _mboxMMDFMessage): flags = set(self.get_flags()) if 'S' in flags: @@ -1280,6 +1353,7 @@ message.add_flag('F') if 'R' in flags: message.add_flag('A') + message.set_from('MAILER-DAEMON', time.gmtime(self.get_date())) elif isinstance(message, MHMessage): flags = set(self.get_flags()) if 'S' not in flags: @@ -1301,7 +1375,8 @@ elif isinstance(message, Message): pass else: - raise TypeError, "Cannot convert to specified type" + raise TypeError('Cannot convert to specified type: %s' % + type(message)) class _mboxMMDFMessage(Message): @@ -1314,10 +1389,6 @@ unixfrom = message.get_unixfrom() if unixfrom is not None and unixfrom[:5] == 'From ': self.set_from(unixfrom[5:]) - elif 'Return-Path' in message: - # XXX: generate "From " line from Return-Path: and Received: - pass - Message.__init__(self, message) def get_from(self): @@ -1329,7 +1400,7 @@ if time_ is not None: if time_ is True: time_ = time.gmtime() - from_ += time.strftime(" %a %b %d %H:%M:%S %Y", time_) + from_ += ' ' + time.asctime(time_) self._from = from_ def get_flags(self): @@ -1381,6 +1452,14 @@ message.add_flag('S') if 'D' in flags: message.add_flag('T') + del message['status'] + del message['x-status'] + maybe_date = ' '.join(self.get_from().split()[-5:]) + try: + message.set_date(calendar.timegm(time.strptime(maybe_date, + '%a %b %d %H:%M:%S %Y'))) + except ValueError, OverflowError: + pass elif isinstance(message, _mboxMMDFMessage): message.set_flags(self.get_flags()) message.set_from(self.get_from()) @@ -1392,6 +1471,8 @@ message.add_sequence('replied') if 'F' in flags: message.add_sequence('flagged') + del message['status'] + del message['x-status'] elif isinstance(message, BabylMessage): flags = set(self.get_flags()) if 'R' not in flags: @@ -1400,10 +1481,13 @@ message.add_label('deleted') if 'A' in flags: message.add_label('answered') + del message['status'] + del message['x-status'] elif isinstance(message, Message): pass else: - raise TypeError, "Cannot convert to specified type" + raise TypeError('Cannot convert to specified type: %s' % + type(message)) class mboxMessage(_mboxMMDFMessage): @@ -1432,7 +1516,7 @@ if not sequence in self._sequences: self._sequences.append(sequence) else: - raise TypeError, "sequence must be a string" + raise TypeError('sequence must be a string: %s' % type(sequence)) def remove_sequence(self, sequence): """Remove sequence from the list of sequences including the message.""" @@ -1476,7 +1560,8 @@ elif isinstance(message, Message): pass else: - raise TypeError, "Cannot convert to specified type" + raise TypeError('Cannot convert to specified type: %s' % + type(message)) class BabylMessage(Message): @@ -1502,7 +1587,7 @@ if label not in self._labels: self._labels.append(label) else: - raise TypeError, "label must be a string" + raise TypeError('label must be a string: %s' % type(label)) def remove_label(self, label): """Remove label from the list of labels on the message.""" @@ -1568,7 +1653,8 @@ elif isinstance(message, Message): pass else: - raise TypeError, "Cannot convert to specified type" + raise TypeError('Cannot convert to specified type: %s' % + type(message)) class MMDFMessage(_mboxMMDFMessage): @@ -1675,16 +1761,16 @@ fcntl.lockf(f, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError, e: if e.errno == errno.EAGAIN: - raise ExternalClashError, \ - "lockf: lock unavailable: %s" % f.name + raise ExternalClashError('lockf: lock unavailable: %s' % + f.name) else: raise try: fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) except IOError, e: if e.errno == errno.EWOULDBLOCK: - raise ExternalClashError, \ - "flock: lock unavailable: %s" % f.name + raise ExternalClashError('flock: lock unavailable: %s' % + f.name) else: raise if dotlock: @@ -1707,8 +1793,8 @@ except OSError, e: if e.errno == errno.EEXIST: os.remove(pre_lock) - raise ExternalClashError, 'dot lock unavailable: %s' % \ - f.name + raise ExternalClashError('dot lock unavailable: %s' % + f.name) else: raise except: Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- libmailbox.tex 16 Aug 2005 17:12:03 -0000 1.10 +++ libmailbox.tex 16 Aug 2005 23:38:11 -0000 1.11 @@ -720,6 +720,16 @@ current "info" is not modified. \end{methoddesc} +\begin{methoddesc}{get_date}{} +Return the delivery date of the message as a floating-point number representing +seconds since the epoch. +\end{methoddesc} + +\begin{methoddesc}{set_date}{date} +Set the delivery date of the message to \var{date}, a floating-point number +representing seconds since the epoch. +\end{methoddesc} + \begin{methoddesc}{get_info}{} Return a string containing the "info" for a message. This is useful for accessing and modifying "info" that is experimental (i.e., not a list of @@ -807,10 +817,11 @@ \begin{methoddesc}{set_from}{from_\optional{, time_=None}} Set the "From~" line to \var{from_}, which should be specified without a -leading "From~" or trailing newline. If \var{time_} is specified, it should be -a \class{struct_time} or a tuple suitable for passing to -\method{time.strftime()}; if \var{time_} is \code{True}, the result of -\method{time.gmtime()} is used. +leading "From~" or trailing newline. For convenience, \var{time_} may be +specified and will be formatted appropriately and appended to \var{from_}. If +\var{time_} is specified, it should be a \class{struct_time}, a tuple suitable +for passing to \method{time.strftime()}, or \code{True} (to use +\method{time.gmtime()}). \end{methoddesc} \begin{methoddesc}{get_flags}{} @@ -840,7 +851,9 @@ \end{methoddesc} When an \class{mboxMessage} instance is created based upon a -\class{MaildirMessage} instance, the following conversions take place: +\class{MaildirMessage} instance, a "From~" line is generated based upon the +\class{MaildirMessage} instance's delivery date, and the following conversions +take place: \begin{tableii}{l|l}{textrm} {Resulting state}{\class{MaildirMessage} state} @@ -1097,10 +1110,11 @@ \begin{methoddesc}{set_from}{from_\optional{, time_=None}} Set the "From~" line to \var{from_}, which should be specified without a -leading "From~" or trailing newline. If \var{time_} is specified, it should be -a \class{struct_time} or a tuple suitable for passing to -\method{time.strftime()}; if \var{time_} is \code{True}, the result of -\method{time.gmtime()} is used. +leading "From~" or trailing newline. For convenience, \var{time_} may be +specified to format a time appropriately and append it to \var{from_}. If +\var{time_} is specified, it should be a \class{struct_time}, a tuple suitable +for passing to \method{time.strftime()}, or \code{True} (to use +\method{time.gmtime()}). \end{methoddesc} \begin{methoddesc}{get_flags}{} @@ -1130,7 +1144,9 @@ \end{methoddesc} When an \class{MMDFMessage} instance is created based upon a -\class{MaildirMessage} instance, the following conversions take place: +\class{MaildirMessage} instance, a "From~" line is generated based upon the +\class{MaildirMessage} instance's delivery date, and the following conversions +take place: \begin{tableii}{l|l}{textrm} {Resulting state}{\class{MaildirMessage} state} Index: test_mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- test_mailbox.py 13 Aug 2005 22:41:33 -0000 1.7 +++ test_mailbox.py 16 Aug 2005 23:38:11 -0000 1.8 @@ -792,6 +792,13 @@ self.assert_(msg.get_subdir() == 'new') self._check_sample(msg) + def test_date(self): + # Use get_date() and set_date() + msg = mailbox.MaildirMessage(_sample_message) + self.assert_(abs(msg.get_date() - time.time()) < 60) + msg.set_date(0.0) + self.assert_(msg.get_date() == 0.0) + def test_info(self): # Use get_info() and set_info() msg = mailbox.MaildirMessage(_sample_message) @@ -995,10 +1002,12 @@ msg_maildir = mailbox.MaildirMessage(_sample_message) msg_maildir.set_flags('DFPRST') msg_maildir.set_subdir('cur') + date = msg_maildir.get_date() msg = mailbox.MaildirMessage(msg_maildir) self._check_sample(msg) self.assert_(msg.get_flags() == 'DFPRST') self.assert_(msg.get_subdir() == 'cur') + self.assert_(msg.get_date() == date) def test_maildir_to_mboxmmdf(self): # Convert MaildirMessage to mboxmessage and MMDFMessage @@ -1006,9 +1015,13 @@ ('T', 'D'), ('DFPRST', 'RDFA')) for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage): msg_maildir = mailbox.MaildirMessage(_sample_message) + msg_maildir.set_date(0.0) for setting, result in pairs: msg_maildir.set_flags(setting) - self.assert_(class_(msg_maildir).get_flags() == result) + msg = class_(msg_maildir) + self.assert_(msg.get_flags() == result) + self.assert_(msg.get_from() == 'MAILER-DAEMON %s' % + time.asctime(time.gmtime(0.0))) msg_maildir.set_subdir('cur') self.assert_(class_(msg_maildir).get_flags() == 'RODFA') @@ -1039,12 +1052,14 @@ # Convert mboxMessage and MMDFMessage to MaildirMessage for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage): msg_mboxMMDF = class_(_sample_message) + msg_mboxMMDF.set_from('foo at bar', time.gmtime(0.0)) pairs = (('R', 'S'), ('O', ''), ('D', 'T'), ('F', 'F'), ('A', 'R'), ('RODFA', 'FRST')) for setting, result in pairs: msg_mboxMMDF.set_flags(setting) - self.assert_(mailbox.MaildirMessage(msg_mboxMMDF).get_flags() \ - == result) + msg = mailbox.MaildirMessage(msg_mboxMMDF) + self.assert_(msg.get_flags() == result) + self.assert_(msg.get_date() == 0.0, msg.get_date()) msg_mboxMMDF.set_flags('O') self.assert_(mailbox.MaildirMessage(msg_mboxMMDF).get_subdir() == \ 'cur') From rhettinger at users.sourceforge.net Wed Aug 17 02:27:53 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 17 Aug 2005 02:27:53 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.52,1.53 Message-ID: <20050817002753.88F401E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10656 Modified Files: setobject.c Log Message: Results of a line-by-line comparison back to dictobject.c. * set_merge() cannot assume that the table doesn't resize during iteration. * convert some unnecessary tests to asserts -- they were necessary in dictobject.c because PyDict_Next() is a public function. The same is not true for set_next(). * re-arrange the order of functions to more closely match the order in dictobject.c. This makes it must easier to compare the two and ought to simplify any issues of maintaining both. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.52 retrieving revision 1.53 diff -u -d -r1.52 -r1.53 --- setobject.c 16 Aug 2005 10:44:15 -0000 1.52 +++ setobject.c 17 Aug 2005 00:27:42 -0000 1.53 @@ -492,8 +492,7 @@ assert (PyAnySet_Check(so)); i = *pos_ptr; - if (i < 0) - return 0; + assert(i >= 0); table = so->table; mask = so->mask; while (i <= mask && (table[i].key == NULL || table[i].key == dummy)) @@ -501,18 +500,86 @@ *pos_ptr = i+1; if (i > mask) return 0; - if (table[i].key) - *entry_ptr = &table[i]; + assert(table[i].key != NULL); + *entry_ptr = &table[i]; return 1; } +static void +set_dealloc(PySetObject *so) +{ + register setentry *entry; + int fill = so->fill; + PyObject_GC_UnTrack(so); + Py_TRASHCAN_SAFE_BEGIN(so) + if (so->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) so); + + for (entry = so->table; fill > 0; entry++) { + if (entry->key) { + --fill; + Py_DECREF(entry->key); + } + } + if (so->table != so->smalltable) + PyMem_DEL(so->table); + if (num_free_sets < MAXFREESETS && PyAnySet_CheckExact(so)) + free_sets[num_free_sets++] = so; + else + so->ob_type->tp_free(so); + Py_TRASHCAN_SAFE_END(so) +} + +static int +set_tp_print(PySetObject *so, FILE *fp, int flags) +{ + setentry *entry; + int pos=0; + char *emit = ""; /* No separator emitted on first pass */ + char *separator = ", "; + + fprintf(fp, "%s([", so->ob_type->tp_name); + while (set_next(so, &pos, &entry)) { + fputs(emit, fp); + emit = separator; + if (PyObject_Print(entry->key, fp, 0) != 0) + return -1; + } + fputs("])", fp); + return 0; +} + +static PyObject * +set_repr(PySetObject *so) +{ + PyObject *keys, *result, *listrepr; + + keys = PySequence_List((PyObject *)so); + if (keys == NULL) + return NULL; + listrepr = PyObject_Repr(keys); + Py_DECREF(keys); + if (listrepr == NULL) + return NULL; + + result = PyString_FromFormat("%s(%s)", so->ob_type->tp_name, + PyString_AS_STRING(listrepr)); + Py_DECREF(listrepr); + return result; +} + +static int +set_len(PyObject *so) +{ + return ((PySetObject *)so)->used; +} + static int set_merge(PySetObject *so, PyObject *otherset) { PySetObject *other; register int i; - register setentry *entry, *othertable; - register int othermask; + register setentry *entry; assert (PyAnySet_Check(so)); assert (PyAnySet_Check(otherset)); @@ -529,10 +596,8 @@ if (set_table_resize(so, (so->used + other->used)*2) != 0) return -1; } - othermask = other->mask; - othertable = other->table; - for (i = 0; i <= othermask; i++) { - entry = &othertable[i]; + for (i = 0; i <= other->mask; i++) { + entry = &other->table[i]; if (entry->key != NULL && entry->key != dummy) { Py_INCREF(entry->key); @@ -569,9 +634,9 @@ static PyObject * set_pop(PySetObject *so) { - PyObject *key; - register setentry *entry; register int i = 0; + register setentry *entry; + PyObject *key; assert (PyAnySet_Check(so)); if (so->used == 0) { @@ -612,9 +677,49 @@ PyDoc_STRVAR(pop_doc, "Remove and return an arbitrary set element."); static int -set_len(PyObject *so) +set_traverse(PySetObject *so, visitproc visit, void *arg) { - return ((PySetObject *)so)->used; + int pos = 0; + setentry *entry; + + while (set_next(so, &pos, &entry)) + Py_VISIT(entry->key); + return 0; +} + +static long +frozenset_hash(PyObject *self) +{ + PySetObject *so = (PySetObject *)self; + long h, hash = 1927868237L; + setentry *entry; + int pos = 0; + + if (so->hash != -1) + return so->hash; + + hash *= PySet_GET_SIZE(self) + 1; + while (set_next(so, &pos, &entry)) { + /* Work to increase the bit dispersion for closely spaced hash + values. The is important because some use cases have many + combinations of a small number of elements with nearby + hashes so that many distinct combinations collapse to only + a handful of distinct hash values. */ + h = entry->hash; + hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u; + } + hash = hash * 69069L + 907133923L; + if (hash == -1) + hash = 590923713L; + so->hash = hash; + return hash; +} + +static long +set_nohash(PyObject *self) +{ + PyErr_SetString(PyExc_TypeError, "set objects are unhashable"); + return -1; } /***** Set iterator type ***********************************************/ @@ -660,6 +765,7 @@ static PySequenceMethods setiter_as_sequence = { (inquiry)setiter_len, /* sq_length */ + 0, /* sq_concat */ }; static PyObject *setiter_iternext(setiterobject *si) @@ -681,8 +787,7 @@ } i = si->si_pos; - if (i < 0) - goto fail; + assert(i>=0); entry = so->table; mask = so->mask; while (i <= mask && (entry[i].key == NULL || entry[i].key == dummy)) @@ -874,44 +979,6 @@ return make_new_set(type, NULL); } -static void -set_dealloc(PySetObject *so) -{ - register setentry *entry; - int fill = so->fill; - - PyObject_GC_UnTrack(so); - Py_TRASHCAN_SAFE_BEGIN(so) - if (so->weakreflist != NULL) - PyObject_ClearWeakRefs((PyObject *) so); - - for (entry = so->table; fill > 0; entry++) { - if (entry->key) { - --fill; - Py_DECREF(entry->key); - } - } - if (so->table != so->smalltable) - PyMem_DEL(so->table); - - if (num_free_sets < MAXFREESETS && PyAnySet_CheckExact(so)) - free_sets[num_free_sets++] = so; - else - so->ob_type->tp_free(so); - Py_TRASHCAN_SAFE_END(so) -} - -static int -set_traverse(PySetObject *so, visitproc visit, void *arg) -{ - int pos = 0; - setentry *entry; - - while (set_next(so, &pos, &entry)) - Py_VISIT(entry->key); - return 0; -} - /* set_swap_bodies() switches the contents of any two sets by moving their internal data pointers and, if needed, copying the internal smalltables. Semantically equivalent to: @@ -1461,79 +1528,6 @@ return -1; } -static long -frozenset_hash(PyObject *self) -{ - PySetObject *so = (PySetObject *)self; - long h, hash = 1927868237L; - setentry *entry; - int pos = 0; - - if (so->hash != -1) - return so->hash; - - hash *= PySet_GET_SIZE(self) + 1; - while (set_next(so, &pos, &entry)) { - /* Work to increase the bit dispersion for closely spaced hash - values. The is important because some use cases have many - combinations of a small number of elements with nearby - hashes so that many distinct combinations collapse to only - a handful of distinct hash values. */ - h = entry->hash; - hash ^= (h ^ (h << 16) ^ 89869747L) * 3644798167u; - } - hash = hash * 69069L + 907133923L; - if (hash == -1) - hash = 590923713L; - so->hash = hash; - return hash; -} - -static long -set_nohash(PyObject *self) -{ - PyErr_SetString(PyExc_TypeError, "set objects are unhashable"); - return -1; -} - -static PyObject * -set_repr(PySetObject *so) -{ - PyObject *keys, *result, *listrepr; - - keys = PySequence_List((PyObject *)so); - if (keys == NULL) - return NULL; - listrepr = PyObject_Repr(keys); - Py_DECREF(keys); - if (listrepr == NULL) - return NULL; - - result = PyString_FromFormat("%s(%s)", so->ob_type->tp_name, - PyString_AS_STRING(listrepr)); - Py_DECREF(listrepr); - return result; -} - -static int -set_tp_print(PySetObject *so, FILE *fp, int flags) -{ - setentry *entry; - int pos=0; - char *emit = ""; /* No separator emitted on first pass */ - char *separator = ", "; - - fprintf(fp, "%s([", so->ob_type->tp_name); - while (set_next(so, &pos, &entry)) { - fputs(emit, fp); - emit = separator; - if (PyObject_Print(entry->key, fp, 0) != 0) - return -1; - } - fputs("])", fp); - return 0; -} - static PyObject * set_add(PySetObject *so, PyObject *key) { From rhettinger at users.sourceforge.net Wed Aug 17 04:19:46 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 17 Aug 2005 04:19:46 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects dictobject.c, 2.165, 2.166 Message-ID: <20050817021946.A24F71E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32522 Modified Files: dictobject.c Log Message: Fix nits. Index: dictobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/dictobject.c,v retrieving revision 2.165 retrieving revision 2.166 diff -u -d -r2.165 -r2.166 --- dictobject.c 14 May 2005 18:08:25 -0000 2.165 +++ dictobject.c 17 Aug 2005 02:19:36 -0000 2.166 @@ -113,7 +113,7 @@ */ /* Object used as dummy key to fill deleted entries */ -static PyObject *dummy; /* Initialized by first call to newdictobject() */ +static PyObject *dummy = NULL; /* Initialized by first call to newdictobject() */ /* forward declarations */ static dictentry * @@ -567,7 +567,7 @@ */ if (!(mp->ma_used > n_used && mp->ma_fill*3 >= (mp->ma_mask+1)*2)) return 0; - return dictresize(mp, mp->ma_used*(mp->ma_used>50000 ? 2 : 4)); + return dictresize(mp, (mp->ma_used>50000 ? mp->ma_used*2 : mp->ma_used*4)); } int From rhettinger at users.sourceforge.net Wed Aug 17 12:05:35 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 17 Aug 2005 12:05:35 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/api concrete.tex,1.63,1.64 Message-ID: <20050817100535.8CBD71E40C1@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/api In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7994 Modified Files: concrete.tex Log Message: Note that the PyNumber protocol can access most set methods directly. Index: concrete.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/api/concrete.tex,v retrieving revision 1.63 retrieving revision 1.64 diff -u -d -r1.63 -r1.64 --- concrete.tex 16 Aug 2005 10:44:12 -0000 1.63 +++ concrete.tex 17 Aug 2005 10:05:22 -0000 1.64 @@ -1144,7 +1144,7 @@ If \var{consumed} is \NULL{}, behaves like \cfunction{PyUnicode_DecodeUTF16()}. If \var{consumed} is not \NULL{}, \cfunction{PyUnicode_DecodeUTF16Stateful()} will not treat trailing incomplete - UTF-16 byte sequences (i.e. an odd number of bytes or a split surrogate pair) + UTF-16 byte sequences (such as an odd number of bytes or a split surrogate pair) as an error. Those bytes will not be decoded and the number of bytes that have been decoded will be stored in \var{consumed}. \versionadded{2.4} @@ -2908,11 +2908,18 @@ This section details the public API for \class{set} and \class{frozenset} objects. Any functionality not listed below is best accessed using the -abstract object API (including +either the abstract object protocol (including \cfunction{PyObject_CallMethod()}, \cfunction{PyObject_RichCompareBool()}, \cfunction{PyObject_Hash()}, \cfunction{PyObject_Repr()}, \cfunction{PyObject_IsTrue()}, \cfunction{PyObject_Print()}, and -\cfunction{PyObject_GetIter()}). +\cfunction{PyObject_GetIter()}) +or the abstract number protocol (including +\cfunction{PyNumber_Add()}, \cfunction{PyNumber_Subtract()}, +\cfunction{PyNumber_Or()}, \cfunction{PyNumber_Xor()}, +\cfunction{PyNumber_InplaceAdd()}, \cfunction{PyNumber_InplaceSubtract()}, +\cfunction{PyNumber_InplaceOr()}, and \cfunction{PyNumber_InplaceXor()}). +Note, the latter are also useful for copying (\code{c=s+s}) and clearing +(\code{s-=s}). \begin{ctypedesc}{PySetObject} This subtype of \ctype{PyObject} is used to hold the internal data for From rhettinger at users.sourceforge.net Wed Aug 17 14:23:59 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 17 Aug 2005 14:23:59 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/api concrete.tex,1.64,1.65 Message-ID: <20050817122359.732AE1E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/api In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1755 Modified Files: concrete.tex Log Message: Expand the API notes. Index: concrete.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/api/concrete.tex,v retrieving revision 1.64 retrieving revision 1.65 diff -u -d -r1.64 -r1.65 --- concrete.tex 17 Aug 2005 10:05:22 -0000 1.64 +++ concrete.tex 17 Aug 2005 12:23:45 -0000 1.65 @@ -2918,8 +2918,8 @@ \cfunction{PyNumber_Or()}, \cfunction{PyNumber_Xor()}, \cfunction{PyNumber_InplaceAdd()}, \cfunction{PyNumber_InplaceSubtract()}, \cfunction{PyNumber_InplaceOr()}, and \cfunction{PyNumber_InplaceXor()}). -Note, the latter are also useful for copying (\code{c=s+s}) and clearing -(\code{s-=s}). +Note, \cfunction{PyNumber_InplaceSubtract()} is also useful clearing +clearing a set (\code{s-=s}). \begin{ctypedesc}{PySetObject} This subtype of \ctype{PyObject} is used to hold the internal data for @@ -2929,7 +2929,7 @@ block of memory for medium and large sized sets (much like list storage). None of the fields of this structure should be considered public and are subject to change. All access should be done through the - documented API. + documented API rather than by manipulating the values in the structure. \end{ctypedesc} @@ -2967,7 +2967,8 @@ \var{iterable}. The \var{iterable} may be \NULL{} to create a new empty set. Returns the new set on success or \NULL{} on failure. Raises \exception{TypeError} if \var{iterable} is - not actually iterable. + not actually iterable. The constructor is also useful for + copying a set (\code{c=set(s)}). \end{cfuncdesc} \begin{cfuncdesc}{PyObject*}{PyFrozenSet_New}{PyObject *iterable} From rhettinger at users.sourceforge.net Wed Aug 17 14:27:31 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 17 Aug 2005 14:27:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.53,1.54 Message-ID: <20050817122731.5EEDB1E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2350 Modified Files: setobject.c Log Message: Add shortcuts for a|a and a&a. Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.53 retrieving revision 1.54 diff -u -d -r1.53 -r1.54 --- setobject.c 17 Aug 2005 00:27:42 -0000 1.53 +++ setobject.c 17 Aug 2005 12:27:17 -0000 1.54 @@ -1065,6 +1065,8 @@ result = (PySetObject *)set_copy(so); if (result == NULL) return NULL; + if ((PyObject *)so == other) + return (PyObject *)result; if (set_update_internal(result, other) == -1) { Py_DECREF(result); return NULL; @@ -1106,10 +1108,8 @@ PySetObject *result; PyObject *key, *it, *tmp; - if ((PyObject *)so == other) { - Py_INCREF(other); - return other; - } + if ((PyObject *)so == other) + return set_copy(so); result = (PySetObject *)make_new_set(so->ob_type, NULL); if (result == NULL) @@ -2062,13 +2062,14 @@ Py_DECREF(f); /* Raise KeyError when popping from an empty set */ - set_clear_internal(so); + assert(PyNumber_InPlaceSubtract(ob, ob) == ob); + Py_DECREF(ob); assert(PySet_GET_SIZE(ob) == 0); assertRaises(PySet_Pop(ob) == NULL, PyExc_KeyError); - /* Restore the set from the copy and use the abstract API */ - assert(PyObject_CallMethod(ob, "update", "O", dup) == Py_None); - Py_DECREF(Py_None); + /* Restore the set from the copy using the PyNumber API */ + assert(PyNumber_InPlaceOr(ob, dup) == ob); + Py_DECREF(ob); /* Verify constructors accept NULL arguments */ f = PySet_New(NULL); From gregorykjohnson at users.sourceforge.net Thu Aug 18 19:52:09 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Thu, 18 Aug 2005 19:52:09 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox libmailbox.tex, 1.11, 1.12 mailbox.py, 1.10, 1.11 Message-ID: <20050818175209.1F3DE1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27089 Modified Files: libmailbox.tex mailbox.py Log Message: * Overhaul existing documentation. * Minor fixes and tweaks: * Fix identifier typos in locking code. * Mangle "From " lines for mbox, as claimed. * Do tilde expansion on mailbox paths. Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- libmailbox.tex 16 Aug 2005 23:38:11 -0000 1.11 +++ libmailbox.tex 17 Aug 2005 20:32:36 -0000 1.12 @@ -7,33 +7,36 @@ \modulesynopsis{Manipulate mailboxes in various formats} -The \module{mailbox} module defines objects for accessing and manipulating -Maildir, mbox, MH, Babyl, and MMDF mailboxes and the messages they contain. -(These formats are commonly used on \UNIX{} to store email messages on disk.) +This module defines two classes, \class{Mailbox} and \class{Message}, for +accessing and manipulating on-disk mailboxes and the messages they contain. +\class{Mailbox} offers a dictionary-like mapping from keys to messages. +\class{Message} extends the \module{email.Message} module's \class{Message} +class with format-specific state and behavior. Supported mailbox formats are +Maildir, mbox, MH, Babyl, and MMDF. -\class{Mailbox} and \class{Message} are the two main classes offered by the -module. \class{Mailbox} offers a dictionary-like mapping from keys to -messages. \class{Message} extends the \module{email.Message} module's -\class{Message} class with format-specific state and behavior. Both -\class{Mailbox} and \class{Message} are extended by format-specific subclasses -and are generally not instantiated directly. +An example of using the module to sort mail: -A \class{Mailbox} instance's keys are immutable objects, issued by the -\class{Mailbox} instance, that are used to select messages from it. They -remain meaningful for the life of the \class{Mailbox} instance, even if the -mailbox is modified. Each time the value corresponding to a key is requested, -a new message representation is created. Typically, messages are representated -as \class{Message} instances, but a custom factory function may be specified. -A message representation is independent of the particular \class{Mailbox} -instance that created it (if any). For message modifications to be reflected -in a mailbox, the modified message representation must be explicitly assigned -back into the \class{Mailbox} instance's mapping. +\begin{verbatim} +>>> import mailbox +>>> inbox = mailbox.Maildir('~/Maildir', None) +>>> python_box = mailbox.Maildir('~/email/python-list', None) +>>> len(inbox) # Number of messages. +13 +>>> len(python_box) +818 +>>> for key, message in inbox.iteritems(): +... if 'python-list' in message['list-id']: +... python_box.add(message) # Add the message to python_box +... del inbox[key] # and remove it from inbox. +... +>>> len(inbox) +2 +>>> len(python_box) +829 +\end{verbatim} \begin{seealso} \seemodule{email}{Represent and manipulate messages.} - \seemodule{poplib}{Access mail via POP3.} - \seemodule{imaplib}{Access mail via IMAP4.} - \seemodule{smtplib}{Transfer mail via SMTP.} \end{seealso} \subsection{\class{Mailbox} objects} @@ -49,33 +52,29 @@ instance. A key continues to identify a message even if the corresponding message is modified, such as by replacing it with another message. Messages may be added to a \class{Mailbox} instance using the set-like method -\method{add()}. Because keys are issued by a \class{Mailbox} instance rather -than being chosen, the conventional method for adding an item to a mapping -(assigning a value to a new key) cannot be used. (\strong{Implementation note:} -\class{mbox}, \class{MH}, \class{Babyl}, and \class{MMDF} instances use -integers as keys, and \class{Maildir} instances use short strings.) +\method{add()} and removed using a \code{del} statement or the set-like methods +\method{remove()} and \method{discard()}. \class{Mailbox} interface semantics differ from dictionary semantics in some -ways. Each time a message is requested, a new message representation (typically -a \class{Message} instance) is generated based upon the current state of the -underlying message. The \class{Mailbox} instance does not reuse this -representation or keep a reference to it. Similarly, when a message -representation is assigned into a \class{Mailbox} instance's mapping, the -message representation's contents are copied into the mailbox. In neither case -is a reference to the message representation kept by the \class{Mailbox} +noteworthy ways. Each time a message is requested, a new representation +(typically a \class{Message} instance) is generated, based upon the current +state of the mailbox. Similarly, when a message is added to a \class{Mailbox} +instance, the provided message representation's contents are copied. In neither +case is a reference to the message representation kept by the \class{Mailbox} instance. The default \class{Mailbox} iterator iterates over message representations, not -keys as dictionaries do. Moreover, modification of a mailbox during iteration -is safe and well-defined. Messages added to the mailbox after an iterator is -created will not be seen by the iterator. Messages removed from the mailbox -before the iterator yields them will be silently skipped, though using a key -from an iterator may result in a \exception{KeyError} exception if the -corresponding message is subsequently removed. +keys as the default dictionary iterator does. Moreover, modification of a +mailbox during iteration is safe and well-defined. Messages added to the +mailbox after an iterator is created will not be seen by the iterator. Messages +removed from the mailbox before the iterator yields them will be silently +skipped, though using a key from an iterator may result in a +\exception{KeyError} exception if the corresponding message is subsequently +removed. \class{Mailbox} itself is intended to define an interface and to be inherited from by format-specific subclasses but is not intended to be instantiated. -Instead, directly instantiate a subclass. +Instead, you should instantiate a subclass. \class{Mailbox} instances have the following methods: @@ -97,16 +96,15 @@ Delete the message corresponding to \var{key} from the mailbox. If no such message exists, a \exception{KeyError} exception is raised if the -method was called as \method{remove()} or \method{__delitem__()} and no +method was called as \method{remove()} or \method{__delitem__()} but no exception is raised if the method was called as \method{discard()}. The behavior of \method{discard()} may be preferred if the underlying mailbox format supports concurrent modification by other processes. \end{methoddesc} \begin{methoddesc}{__setitem__}{key, message} -Replace the message corresponding to \var{key} with the message represented by -\var{message}. Raise a \exception{KeyError} exception if no message already -corresponds to \var{key}. +Replace the message corresponding to \var{key} with \var{message}. Raise a +\exception{KeyError} exception if no message already corresponds to \var{key}. As with \method{add()}, parameter \var{message} may be a \class{Message} instance, an \class{email.Message.Message} instance, a string, or a file-like @@ -129,9 +127,10 @@ Return an iterator over representations of all messages if called as \method{itervalues()} or \method{__iter__()} or return a list of such representations if called as \method{values()}. The messages are represented as -\class{Message} instances unless a custom message factory was specified when -the \class{Mailbox} instance was initialized. \note{The behavior of -\method{__iter__()} is unlike that of dictionaries, which iterate over keys.} +instances of the appropriate format-specific \class{Message} subclass unless a +custom message factory was specified when the \class{Mailbox} instance was +initialized. \note{The behavior of \method{__iter__()} is unlike that of +dictionaries, which iterate over keys.} \end{methoddesc} \begin{methoddesc}{iteritems}{} @@ -139,9 +138,9 @@ Return an iterator over (\var{key}, \var{message}) pairs, where \var{key} is a key and \var{message} is a message representation, if called as \method{iteritems()} or return a list of such pairs if called as -\method{items()}. The messages are represented as \class{Message} instances -unless a custom message factory was specified when the \class{Mailbox} instance -was initialized. +\method{items()}. The messages are represented as instances of the appropriate +format-specific \class{Message} subclass unless a custom message factory was +specified when the \class{Mailbox} instance was initialized. \end{methoddesc} \begin{methoddesc}{get}{key\optional{, default=None}} @@ -149,15 +148,16 @@ Return a representation of the message corresponding to \var{key}. If no such message exists, \var{default} is returned if the method was called as \method{get()} and a \exception{KeyError} exception is raised if the method was -called as \method{__getitem__()}. The message is represented as a -\class{Message} instance unless a custom message factory was specified when the -\class{Mailbox} instance was initialized. +called as \method{__getitem__()}. The message is represented as an instance of +the appropriate format-specific \class{Message} subclass unless a custom +message factory was specified when the \class{Mailbox} instance was +initialized. \end{methoddesc} \begin{methoddesc}{get_message}{key} -Return a \class{Message} representation of the message corresponding to -\var{key}, or raise a \exception{KeyError} exception if no such message -exists. +Return a representation of the message corresponding to \var{key} as an +instance of the appropriate format-specific \class{Message} subclass, or raise +a \exception{KeyError} exception if no such message exists. \end{methoddesc} \begin{methoddesc}{get_string}{key} @@ -171,13 +171,13 @@ should be closed once it is no longer needed. \note{Unlike other representations of messages, file-like representations are -not independent of the \class{Mailbox} instance that created them or of the -underlying mailbox, although their exact behavior is mailbox-format dependent. -More specific documentation is provided by each subclass.} +not necessarily independent of the \class{Mailbox} instance that created them +or of the underlying mailbox. More specific documentation is provided by each +subclass.} \end{methoddesc} \begin{methoddesc}{has_key}{key} -\methodline{__contains__}{} +\methodline{__contains__}{key} Return \code{True} if \var{key} corresponds to a message, \code{False} otherwise. \end{methoddesc} @@ -193,32 +193,36 @@ \begin{methoddesc}{pop}{key\optional{, default}} Return a representation of the message corresponding to \var{key} and delete the message. If no such message exists, return \var{default} if it was supplied -or else raise a \exception{KeyError} exception. The message is represented as a -\class{Message} instance unless a custom message factory was specified when the -\class{Mailbox} instance was initialized. +or else raise a \exception{KeyError} exception. The message is represented as +an instance of the appropriate format-specific \class{Message} subclass unless +a custom message factory was specified when the \class{Mailbox} instance was +initialized. \end{methoddesc} \begin{methoddesc}{popitem}{} Return an arbitrary (\var{key}, \var{message}) pair, where \var{key} is a key and \var{message} is a message representation, and delete the corresponding message. If the mailbox is empty, raise a \exception{KeyError} exception. The -message is represented as a \class{Message} instance unless a custom message -factory was specified when the \class{Mailbox} instance was initialized. +message is represented as an instance of the appropriate format-specific +\class{Message} subclass unless a custom message factory was specified when the +\class{Mailbox} instance was initialized. \end{methoddesc} \begin{methoddesc}{update}{arg} Parameter \var{arg} should be a \var{key}-to-\var{message} mapping or an iterable of (\var{key}, \var{message}) pairs. Updates the mailbox so that, for each given \var{key} and \var{message}, the message corresponding to \var{key} -is set to \var{message} as if by using \method{__setitem__()}. Each \var{key} -must already correspond to a message in the mailbox or a \exception{KeyError} -exception will be raised. \note{Unlike with dictionaries, keyword arguments -are not supported.} +is set to \var{message} as if by using \method{__setitem__()}. As with +\method{__setitem__()}, each \var{key} must already correspond to a message in +the mailbox or else a \exception{KeyError} exception will be raised, so in +general it is incorrect for \var{arg} to be a \class{Mailbox} instance. +\note{Unlike with dictionaries, keyword arguments are not supported.} \end{methoddesc} \begin{methoddesc}{flush}{} Write any pending changes to the filesystem. For some \class{Mailbox} -subclasses, changes are written immediately and this method does nothing. +subclasses, changes are always written immediately and this method does +nothing. \end{methoddesc} \begin{methoddesc}{lock}{} @@ -229,7 +233,7 @@ \end{methoddesc} \begin{methoddesc}{unlock}{} -Release the advisory lock on the mailbox, if any. +Release the lock on the mailbox, if any. \end{methoddesc} \begin{methoddesc}{close}{} @@ -244,30 +248,39 @@ \begin{classdesc}{Maildir}{dirname\optional{, factory=rfc822.Message\optional{, create=True}}} A subclass of \class{Mailbox} for mailboxes in Maildir format. Parameter -\var{factory} is a callable object that accepts a file-like object containing a -raw message as its parameter and returns a message representation. If -\var{factory} is \code{None}, \class{MaildirMessage} instances are used. -If \var{create} is \code{True}, the mailbox is created if it does not exist. +\var{factory} is a callable object that accepts a file-like message +representation and returns a custom representation. If \var{factory} is +\code{None}, \class{MaildirMessage} is used as the default message +representation. If \var{create} is \code{True}, the mailbox is created if it +does not exist. It is for historical reasons that \var{factory} defaults to \class{rfc822.Message} and that \var{dirname} is named as such rather than -\var{path}. +\var{path}. For a \class{Maildir} instance that behaves like instances of other +\class{Mailbox} subclasses, set \var{factory} to \code{None}. \end{classdesc} -Maildir is a directory-based mailbox format invented for the qmail MTA and now -widely supported by other programs. Messages in a Maildir mailbox are stored -in separate files within a shared directory structure. This structure allows -Maildir mailboxes to be accessed and modified by multiple unrelated programs -without data corruption, so file locking is unnecessary. +Maildir is a directory-based mailbox format invented for the qmail mail +transfer agent and now widely supported by other programs. Messages in a +Maildir mailbox are stored in separate files within a common directory +structure. This design allows Maildir mailboxes to be accessed and modified by +multiple unrelated programs without data corruption, so file locking is +unnecessary. -Folders, as introduced by the Courier MTA, are supported. Each folder is -itself a Maildir mailbox. Any subdirectory of the main Maildir directory is -considered a folder if \character{.} is the first character in its name. Folder -names are represented without the leading dot. For example, "Sent" would be the -name of a folder implemented with a directory called ".Sent" on the filesystem. -Folders should not be nested, i.e., a Maildir mailbox that is itself a folder -should not contain other folders. Instead, logical nesting may be indicated -using \character{.} to delimit levels---for example, "Archived.2005.07". +Maildir mailboxes contain three subdirectories, namely: \file{tmp}, \file{new}, +and \file{cur}. Messages are created momentarily in the \file{tmp} subdirectory +and then moved to the \file{new} subdirectory to finalize delivery. A mail user +agent may subsequently move the message to the \file{cur} subdirectory and +store information about the state of the message in a special "info" section +appended to its file name. + +Folders of the style introduced by the Courier mail transfer agent are also +supported. Any subdirectory of the main mailbox is considered a folder if +\character{.} is the first character in its name. Folder names are represented +by \class{Maildir} without the leading \character{.}. Each folder is itself a +Maildir mailbox but should not contain other folders. Instead, a logical +nesting is indicated using \character{.} to delimit levels, e.g., +"Archived.2005.07". \class{Maildir} instances have all of the methods of \class{Mailbox} in addition to the following: @@ -327,16 +340,15 @@ \end{methoddesc} \begin{methoddesc}{get_file}{key} -Depending upon the host platform, it may not be possible to use a -\class{Maildir} instance to modify or remove the underlying message while the -returned file remains open. +Depending upon the host platform, it may not be possible to modify or remove +the underlying message while the returned file remains open. \end{methoddesc} \begin{seealso} \seelink{http://www.qmail.org/man/man5/maildir.html}{maildir man page from qmail}{The original specification of the format.} \seelink{http://cr.yp.to/proto/maildir.html}{Using maildir format}{Notes - on Maildir by it's inventor. Includes an updated name-creation scheme and + on Maildir by its inventor. Includes an updated name-creation scheme and details on "info" semantics.} \seelink{http://www.courier-mta.org/?maildir.html}{maildir man page from Courier}{Another specification of the format. Describes a common extension @@ -348,15 +360,16 @@ \begin{classdesc}{mbox}{path\optional{, factory=None\optional{, create=True}}} A subclass of \class{Mailbox} for mailboxes in mbox format. Parameter -\var{factory} is a callable object that accepts a file-like object containing a -raw message as its parameter and returns a message representation. If -\var{factory} is \code{None}, \class{mboxMessage} instances are used. If -\var{create} is \code{True}, the mailbox is created if it does not exist. +\var{factory} is a callable object that accepts a file-like message +representation and returns a custom representation. If \var{factory} is +\code{None}, \class{mboxMessage} is used as the default message representation. +If \var{create} is \code{True}, the mailbox is created if it does not exist. \end{classdesc} The mbox format is the classic format for storing mail on \UNIX{} systems. All messages in an mbox mailbox are stored in a single file with the beginning of each message indicated by a line whose first five characters are "From~". + Several variations of the mbox format exist to address perceived shortcomings. In the interest of compatibility, \class{mbox} implements the original format, which is sometimes referred to as \dfn{mboxo}. This means that the @@ -369,7 +382,8 @@ remarks: \begin{methoddesc}{get_file}{key} -XXX +Using the file after calling \method{flush()} or \method{close()} on the +\class{mbox} instance may yield unpredictable results or raise an exception. \end{methoddesc} \begin{methoddesc}{lock}{} @@ -398,29 +412,24 @@ \begin{classdesc}{MH}{path\optional{, factory=None\optional{, create=True}}} A subclass of \class{Mailbox} for mailboxes in MH format. Parameter -\var{factory} is a callable object that accepts a file-like object containing a -raw message as its parameter and returns a message representation. If -\var{factory} is \code{None}, \class{MHMessage} instances are used. If -\var{create} is \code{True}, the mailbox is created if it does not exist. +\var{factory} is a callable object that accepts a file-like message +representation and returns a custom representation. If \var{factory} is +\code{None}, \class{MHMessage} is used as the default message representation. +If \var{create} is \code{True}, the mailbox is created if it does not exist. \end{classdesc} MH is a directory-based mailbox format invented for the MH Message Handling -System, a mail reading application. Each message in an MH mailbox resides in -its own file. An MH mailbox may contain other MH mailboxes (called -\dfn{folders}) in addition to messages. Folders may be nested indefinitely. - -MH mailboxes support \dfn{sequences}, which are named lists used to logically -group messages without moving them to sub-folders. Sequences are defined in a -file called \file{.mh_sequences} in each folder. Some mail reading programs -(although not the standard \program{mh} and \program{nmh} implementations) use -sequences to the same end as flags are used in other formats: unread messages -are added to the "unseen" sequence, replied-to messages are added to the -"replied" sequence, and important messages are added upon request to the -"flagged" sequence. +System, a mail user agent. Each message in an MH mailbox resides in its own +file. An MH mailbox may contain other MH mailboxes (called \dfn{folders}) in +addition to messages. Folders may be nested indefinitely. MH mailboxes also +support \dfn{sequences}, which are named lists used to logically group messages +without moving them to sub-folders. Sequences are defined in a file called +\file{.mh_sequences} in each folder. -\class{MH} manipulates MH mailboxes, but it does not attempt to emulate -\program{mh}. In particular, it does not access or modify \file{context} or -\file{.mh_profile} files. +The \class{MH} class manipulates MH mailboxes, but it does not attempt to +emulate all of \program{mh}'s behaviors. In particular, it does not access or +modify the \file{context} or \file{.mh_profile} files that are used by +\program{mh} to store its state and configuration. \class{MH} instances have all of the methods of \class{Mailbox} in addition to the following: @@ -453,14 +462,14 @@ \begin{methoddesc}{set_sequences}{sequences} Re-define the sequences that exist in the mailbox based upon \var{sequences}, a -dictionary of names mapped to key lists like returned by +dictionary of names mapped to key lists, like returned by \method{get_sequences()}. \end{methoddesc} \begin{methoddesc}{pack}{} -Renames messages in the mailbox as necessary to eliminate gaps in numbering. -Entries in the sequences list are updated correspondingly. Already-issued keys -are invalidated by this operation. +Rename messages in the mailbox as necessary to eliminate gaps in numbering. +Entries in the sequences list are updated correspondingly. \note{Already-issued +keys are invalidated by this operation and should not be subsequently used.} \end{methoddesc} Some \class{Mailbox} methods implemented by \class{MH} deserve special remarks: @@ -468,8 +477,8 @@ \begin{methoddesc}{remove}{key} \methodline{__delitem__}{key} \methodline{discard}{key} -These methods immediately delete the message. The \program{mh} convention of -marking a message for deletion by prepending a comma to its name is not used. +These methods immediately delete the message. The MH convention of marking a +message for deletion by prepending a comma to its name is not used. \end{methoddesc} \begin{methoddesc}{lock}{} @@ -482,7 +491,8 @@ \end{methoddesc} \begin{methoddesc}{get_file}{key} -XXX +Depending upon the host platform, it may not be possible to remove the +underlying message while the returned file remains open. \end{methoddesc} \begin{methoddesc}{flush}{} @@ -495,15 +505,6 @@ to \method{unlock()}. \end{methoddesc} -\class{MH} instances have all of the methods of \class{Mailbox} in addition to -the following: - -Some \class{Mailbox} methods implemented by \class{MH} deserve special remarks: - -\begin{methoddesc}{get_file}{key} -XXX -\end{methoddesc} - \begin{seealso} \seelink{http://www.nongnu.org/nmh/}{nmh - Message Handling System}{Home page of \program{nmh}, a modern version of the original \program{mh}.} @@ -517,30 +518,37 @@ \begin{classdesc}{Babyl}{path\optional{, factory=None\optional{, create=True}}} A subclass of \class{Mailbox} for mailboxes in Babyl format. Parameter -\var{factory} is a callable object that accepts a file-like object containing a -raw message as its parameter and returns a message representation. If -\var{factory} is \code{None}, \class{BabylMessage} instances are used. If -\var{create} is \code{True}, the mailbox is created if it does not exist. +\var{factory} is a callable object that accepts a file-like message +representation and returns a custom representation. If \var{factory} is +\code{None}, \class{BabylMessage} is used as the default message +representation. If \var{create} is \code{True}, the mailbox is created if it +does not exist. \end{classdesc} -Babyl is a single-file mailbox format invented for the \program{Rmail} mail -reading application included with Emacs. A Babyl mailbox begins with an options -section that indicates the format of the mailbox and contains a list of -user-defined labels that appear in the mailbox. Messages follow the options -section. The beginning of a message is indicated by a line containing exactly -two control characters, namely Control-Underscore -(\character{\textbackslash037}) followed by Control-L -(\character{\textbackslash014}). The end of a message is indicated by the start -of the next message or, in the case of the last message, a line containing only -a Control-Underscore (\character{\textbackslash037}) character. Each message in -a Babyl mailbox has an accompanying list of \dfn{labels}, or short strings that -record extra information about the message. +Babyl is a single-file mailbox format invented for the Rmail mail user agent +included with Emacs. The beginning of a message is indicated by a line +containing exactly the two characters Control-Underscore +(\character{\textbackslash037}) and Control-L (\character{\textbackslash014}). +The end of a message is indicated by the start of the next message or, in the +case of the last message, a line containing only a Control-Underscore +(\character{\textbackslash037}) character. + +Messages in a Babyl mailbox have two sets of headers, original headers and +so-called visible headers. Visible headers are typically a subset of the +original headers that have been reformatted or abridged to be more attractive. +Each message in a Babyl mailbox also has an accompanying list of \dfn{labels}, +or short strings that record extra information about the message, and a list of +all user-defined labels found in the mailbox is kept in the Babyl options +section. \class{Babyl} instances have all of the methods of \class{Mailbox} in addition to the following: \begin{methoddesc}{get_labels}{} Return a list of the names of all user-defined labels used in the mailbox. +\note{The actual messages are inspected to determine which labels exist in the +mailbox rather than consulting the list of labels in the Babyl options section, +but the Babyl section is updated whenever the mailbox is modified.} \end{methoddesc} Some \class{Mailbox} methods implemented by \class{Babyl} deserve special @@ -548,9 +556,11 @@ \begin{methoddesc}{get_file}{key} In Babyl mailboxes, the headers of a message are not stored contiguously with -the body of the message. To generate a file-like representation, they are -copied together into a \class{StringIO} instance (from the \module{StringIO} -module), which may be used like a file. +the body of the message. To generate a file-like representation, the headers +and body are copied together into a \class{StringIO} instance (from the +\module{StringIO} module), which has an API identical to that of a file. As a +result, the file-like object is truly independent of the underlying mailbox but +does not save memory compared to a string representation. \end{methoddesc} \begin{methoddesc}{lock}{} @@ -571,25 +581,28 @@ \begin{classdesc}{MMDF}{path\optional{, factory=None\optional{, create=True}}} A subclass of \class{Mailbox} for mailboxes in MMDF format. Parameter -\var{factory} is a callable object that accepts a file-like object containing a -raw message as its parameter and returns a message representation. If -\var{factory} is \code{None}, \class{MMDFMessage} instances are used. If -\var{create} is \code{True}, the mailbox is created if it does not exist. +\var{factory} is a callable object that accepts a file-like message +representation and returns a custom representation. If \var{factory} is +\code{None}, \class{MMDFMessage} is used as the default message representation. +If \var{create} is \code{True}, the mailbox is created if it does not exist. \end{classdesc} MMDF is a single-file mailbox format invented for the Multichannel Memorandum Distribution Facility, a mail transfer agent. Each message is in the same form as an mbox message but is bracketed before and after by lines containing four -Control-A characters. As with the mbox format, the beginning of each message -indicated by a line whose first five characters are "From~", but because of the -additional message separators it is unnecessary to transform "From~" to -">From~" when storing messages. +Control-A (\character{\textbackslash001}) characters. As with the mbox format, +the beginning of each message is indicated by a line whose first five +characters are "From~", but additional occurrences of "From~" are not +transformed to ">From~" when storing messages because the additional message +separator lines prevent mistaking such occurrences for the starts of subsequent +messages. Some \class{Mailbox} methods implemented by \class{MMDF} deserve special remarks: \begin{methoddesc}{get_file}{key} -XXX +Using the file after calling \method{flush()} or \method{close()} on the +\class{MMDF} instance may yield unpredictable results or raise an exception. \end{methoddesc} \begin{methoddesc}{lock}{} @@ -609,42 +622,33 @@ \subsection{\class{Message} objects} \label{mailbox-message-objects} -The \class{Message} class is an extension of a class of the same name from the -\module{email.Message} module. In addition, subclasses of \class{Message} -support mailbox-format-specific state and behavior. - \begin{classdesc}{Message}{\optional{message}} -A message with mailbox-format-specific properties. +A subclass of the \module{email.Message} module's \class{Message}. Subclasses +of \class{mailbox.Message} add mailbox-format-specific state and behavior. If \var{message} is omitted, the new instance is created in a default, empty state. If \var{message} is an \class{email.Message.Message} instance, its -contents are copied, converting any format-specific information insofar as -possible if \var{message} is a \class{Message} instance. If \var{message} is a -string or a file, it should contain an \rfc{2822}-compliant message, which is -read and parsed. +contents are copied; furthermore, any format-specific information is converted +insofar as possible if \var{message} is a \class{Message} instance. If +\var{message} is a string or a file, it should contain an \rfc{2822}-compliant +message, which is read and parsed. \end{classdesc} The format-specific state and behaviors offered by subclasses vary, but in -general it is only the properties that are not specific to a particular -mailbox that are supported (although presumably the properties are specific to -a particular mailbox format). For example, file offsets for single-file mailbox +general it is only the properties that are not specific to a particular mailbox +that are supported (although presumably the properties are specific to a +particular mailbox format). For example, file offsets for single-file mailbox formats and file names for directory-based mailbox formats are not retained, -but state such as whether a message has been read or marked as important by the -user is. - -In some situations, the time and memory overhead involved in generating -\class{Message} representations might not not justified. For such situations, -\class{Mailbox} instances also offer string and file-like representations, and -a custom message factory may be specified when a \class{Mailbox} instance is -initialized. There is no requirement to use the \class{Message} class to -represent messages from a mailbox. - -All of the \class{email.Message.Message} class's methods and members are -supported by \class{Message}, and subclasses of \class{Message} provide many -additional format-specific methods. Some functionality supported by all -\class{Message} subclasses is accessible via the following methods: +because they are only applicable to the original mailbox. But state such as +whether a message has been read by the user or marked as important is retained, +because it applies to the message itself. -XXX +There is no requirement that \class{Message} instances be used to represent +messages retrieved using \class{Mailbox} instances. In some situations, the +time and memory required to generate \class{Message} representations might not +not acceptable. For such situations, \class{Mailbox} instances also offer +string and file-like representations, and a custom message factory may be +specified when a \class{Mailbox} instance is initialized. \subsubsection{\class{MaildirMessage}} \label{mailbox-maildirmessage} @@ -654,26 +658,22 @@ has the same meaning as with the \class{Message} constructor. \end{classdesc} -Maildir messages are stored in individual files, in either the \file{new} or -the \file{cur} subdirectory of the Maildir. Messages are delivered to the -\file{new} subdirectory. Typically, a mail reading application moves messages -to the \file{cur} subdirectory after the user opens and closes the mailbox, -thereby recording that the messages are old whether or not they've actually -been read. - -Each message in \file{cur} has an "info" section added to its file name to -store information about its state. (Some mail readers may also add an "info" -section to messages in \file{new}.) The "info" section may take one of two -forms: it may contain "2," followed by a list of standardized flags (e.g., -"2,FR") or it may contain "1," followed by so-called experimental information. -Standard flags for Maildir messages are as follows: +Typically, a mail user agent application moves all of the messages in the +\file{new} subdirectory to the \file{cur} subdirectory after the first time the +user opens and closes the mailbox, recording that the messages are old whether +or not they've actually been read. Each message in \file{cur} has an "info" +section added to its file name to store information about its state. (Some mail +readers may also add an "info" section to messages in \file{new}.) The "info" +section may take one of two forms: it may contain "2," followed by a list of +standardized flags (e.g., "2,FR") or it may contain "1," followed by so-called +experimental information. Standard flags for Maildir messages are as follows: \begin{tableiii}{l|l|l}{textrm}{Flag}{Meaning}{Explanation} \lineiii{D}{Draft}{Under composition} -\lineiii{F}{Flagged}{Marked by the user as important} -\lineiii{P}{Passed}{Forwarded, resent, or bounced by the user} -\lineiii{R}{Replied}{Responded to} -\lineiii{S}{Seen}{Read by the user} +\lineiii{F}{Flagged}{Marked as important} +\lineiii{P}{Passed}{Forwarded, resent, or bounced} +\lineiii{R}{Replied}{Replied to} +\lineiii{S}{Seen}{Read} \lineiii{T}{Trashed}{Marked for subsequent deletion} \end{tableiii} @@ -684,7 +684,7 @@ subdirectory) or "cur" (if the message should be stored in the \file{cur} subdirectory). \note{A message is typically moved from \file{new} to \file{cur} after its mailbox has been accessed, whether or not the message is has been -read. A message has been read if \code{"S" not in get_flags()}.} +read. A message has been read if \code{"S" not in get_flags()} is \code{True}.} \end{methoddesc} \begin{methoddesc}{set_subdir}{subdir} @@ -796,11 +796,11 @@ Conventional flags for mbox messages are as follows: \begin{tableiii}{l|l|l}{textrm}{Flag}{Meaning}{Explanation} -\lineiii{R}{Read}{Read by the user} -\lineiii{O}{Old}{Previously detected by mail reader} +\lineiii{R}{Read}{Read} +\lineiii{O}{Old}{Previously detected by MUA} \lineiii{D}{Deleted}{Marked for subsequent deletion} -\lineiii{F}{Flagged}{Marked by the user as important} -\lineiii{A}{Answered}{Responded to} +\lineiii{F}{Flagged}{Marked as important} +\lineiii{A}{Answered}{Replied to} \end{tableiii} The "R" and "O" flags are stored in the \mailheader{Status} header, and the @@ -819,8 +819,8 @@ Set the "From~" line to \var{from_}, which should be specified without a leading "From~" or trailing newline. For convenience, \var{time_} may be specified and will be formatted appropriately and appended to \var{from_}. If -\var{time_} is specified, it should be a \class{struct_time}, a tuple suitable -for passing to \method{time.strftime()}, or \code{True} (to use +\var{time_} is specified, it should be a \class{struct_time} instance, a tuple +suitable for passing to \method{time.strftime()}, or \code{True} (to use \method{time.gmtime()}). \end{methoddesc} @@ -907,17 +907,14 @@ \end{classdesc} MH messages do not support marks or flags in the traditional sense, but they do -support sequences, which are logical groupings of arbitrary messages. Because -sequences are often used to indicate the state of a messsage, they are -maintained by the \class{MHMessage} class even though they are not, strictly -speaking, a property of the message itself. - -Some mail user agents make use of sequences to record message state as follows: +support sequences, which are logical groupings of arbitrary messages. Some mail +reading programs (although not the standard \program{mh} and \program{nmh}) use +sequences in much the same way flags are used with other formats, as follows: \begin{tableii}{l|l}{textrm}{Sequence}{Explanation} -\lineii{unseen}{Previously detected by mail reader but not read} -\lineii{replied}{Responded to} -\lineii{flagged}{Marked by the user as important} +\lineii{unseen}{Not read, but previously detected by MUA} +\lineii{replied}{Replied to} +\lineii{flagged}{Marked as important} \end{tableii} \class{MHMessage} instances offer the following methods: @@ -977,27 +974,23 @@ meaning as with the \class{Message} constructor. \end{classdesc} -Information about Babyl messages is recorded using \dfn{labels}, or short -strings which are stored in an MH mailbox just before each message. Some -labels are assigned special meaning and are called \dfn{attributes}. Other -labels are user-defined. The attributes are as follows: +Certain message labels, called \dfn{attributes}, are defined by convention to +have special meanings. The attributes are as follows: \begin{tableii}{l|l}{textrm}{Label}{Explanation} -\lineii{unseen}{Previously detected by mail reader but not read} +\lineii{unseen}{Not read, but previously detected by MUA} \lineii{deleted}{Marked for subsequent deletion} \lineii{filed}{Copied to another file or mailbox} -\lineii{answered}{Responded to} -\lineii{forwarded}{Forwarded by the the user} -\lineii{edited}{Message content modified by the user} -\lineii{resent}{Resent by the user} +\lineii{answered}{Replied to} +\lineii{forwarded}{Forwarded} +\lineii{edited}{Modified by the user} +\lineii{resent}{Resent} \end{tableii} -Each message in a Babyl mailbox has two sets of headers, original headers and -visible headers. Visible headers are typically a subset of the original -headers reformatted to be more attractive. By default, \program{Rmail} displays -only visible headers. \class{BabylMessage} uses the original headers because -they are more complete, though the visible headers may be accessed explicitly -if desired. +By default, Rmail displays only +visible headers. The \class{BabylMessage} class, though, uses the original +headers because they are more complete. Visible headers may be accessed +explicitly if desired. \class{BabylMessage} instances offer the following methods: @@ -1088,11 +1081,11 @@ are as follows: \begin{tableiii}{l|l|l}{textrm}{Flag}{Meaning}{Explanation} -\lineiii{R}{Read}{Read by the user} -\lineiii{O}{Old}{Previously detected by mail reader} +\lineiii{R}{Read}{Read} +\lineiii{O}{Old}{Previously detected by MUA} \lineiii{D}{Deleted}{Marked for subsequent deletion} -\lineiii{F}{Flagged}{Marked by the user as important} -\lineiii{A}{Answered}{Responded to} +\lineiii{F}{Flagged}{Marked as important} +\lineiii{A}{Answered}{Replied to} \end{tableiii} The "R" and "O" flags are stored in the \mailheader{Status} header, and the @@ -1111,9 +1104,9 @@ \begin{methoddesc}{set_from}{from_\optional{, time_=None}} Set the "From~" line to \var{from_}, which should be specified without a leading "From~" or trailing newline. For convenience, \var{time_} may be -specified to format a time appropriately and append it to \var{from_}. If -\var{time_} is specified, it should be a \class{struct_time}, a tuple suitable -for passing to \method{time.strftime()}, or \code{True} (to use +specified and will be formatted appropriately and appended to \var{from_}. If +\var{time_} is specified, it should be a \class{struct_time} instance, a tuple +suitable for passing to \method{time.strftime()}, or \code{True} (to use \method{time.gmtime()}). \end{methoddesc} Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- mailbox.py 16 Aug 2005 23:38:11 -0000 1.10 +++ mailbox.py 17 Aug 2005 20:32:36 -0000 1.11 @@ -29,7 +29,7 @@ def __init__(self, path, factory=None, create=True): """Initialize a Mailbox instance.""" - self._path = os.path.abspath(path) + self._path = os.path.abspath(os.path.expanduser(path)) self._factory = factory def add(self, message): @@ -182,19 +182,30 @@ """Flush and close the mailbox.""" raise NotImplementedError('Method must be implemented by subclass') - def _dump_message(self, message, target): + def _dump_message(self, message, target, mangle_from_=False): """Dump message contents to target file.""" if isinstance(message, email.Message.Message): - generator = email.Generator.Generator(target, False, 0) + generator = email.Generator.Generator(target, mangle_from_, 0) generator.flatten(message) elif isinstance(message, str): + if mangle_from_: + message = message.replace('\nFrom ', '\n>From ') target.write(message) elif hasattr(message, 'read'): - while True: - buffer = message.read(4096) # Buffer size is arbitrary. - if buffer == "": - break - target.write(buffer) + if mangle_from_: + while True: + line = message.readline() + if line == '': + break + if line[:5] == 'From ': + line = '>From ' + s[5:] + target.write(line) + else: + while True: + buffer = message.read(4096) # Buffer size is arbitrary. + if buffer == '': + break + target.write(buffer) else: raise TypeError('Invalid message type: %s' % type(message)) @@ -594,6 +605,8 @@ class _mboxMMDF(_singlefileMailbox): """An mbox or MMDF mailbox.""" + _mangle_from_ = True + def get_message(self, key): """Return a Message representation or raise a KeyError.""" start, stop = self._lookup(key) @@ -638,7 +651,7 @@ from_line = 'From MAILER-DAEMON %s' % time.asctime(time.gmtime()) start = self._file.tell() self._file.write('%s%s' % (from_line, os.linesep)) - self._dump_message(message, self._file) + self._dump_message(message, self._file, self._mangle_from_) stop = self._file.tell() return (start, stop) @@ -646,6 +659,8 @@ class mbox(_mboxMMDF): """A classic mbox mailbox.""" + _mangle_from_ = True + def __init__(self, path, factory=None, create=True): """Initialize an mbox mailbox.""" self._message_factory = mboxMessage @@ -1755,6 +1770,7 @@ def _lock_file(f, dotlock=True): """Lock file f using lockf, flock, and dot locking.""" + dotlock_done = False try: if fcntl: try: @@ -1786,13 +1802,13 @@ if hasattr(os, 'link'): os.link(pre_lock.name, f.name + '.lock') dotlock_done = True - os.unlink(pre_lock) + os.unlink(pre_lock.name) else: - os.rename(pre_lock, f.name + '.lock') + os.rename(pre_lock.name, f.name + '.lock') dotlock_done = True except OSError, e: if e.errno == errno.EEXIST: - os.remove(pre_lock) + os.remove(pre_lock.name) raise ExternalClashError('dot lock unavailable: %s' % f.name) else: @@ -1810,7 +1826,7 @@ if fcntl: fcntl.lockf(f, fcntl.LOCK_UN) fcntl.flock(f, fcntl.LOCK_UN) - if os.path.exists(path + '.lock'): + if os.path.exists(f.name + '.lock'): os.remove(f.name + '.lock') def _create_carefully(path): From doerwalter at users.sourceforge.net Thu Aug 18 21:40:50 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Thu, 18 Aug 2005 21:40:50 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libsimplexmlrpc.tex, 1.9, 1.10 Message-ID: <20050818194050.A41DF1E4058@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10086/lib Modified Files: libsimplexmlrpc.tex Log Message: Fix typo (fixes SF bug #1263086). Index: libsimplexmlrpc.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libsimplexmlrpc.tex,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- libsimplexmlrpc.tex 3 Feb 2005 15:01:23 -0000 1.9 +++ libsimplexmlrpc.tex 18 Aug 2005 19:40:39 -0000 1.10 @@ -61,7 +61,7 @@ not been registered using \method{register_function()}. If \var{instance} contains a \method{_dispatch()} method, it is called with the requested method name and the parameters from the request. Its - API is \code{def \method{_dispatch}(self, method, params)} (note tha + API is \code{def \method{_dispatch}(self, method, params)} (note that \var{params} does not represent a variable argument list). If it calls an underlying function to perform its task, that function is called as \code{func(*params)}, expanding the parameter list. From doerwalter at users.sourceforge.net Thu Aug 18 21:48:34 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Thu, 18 Aug 2005 21:48:34 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libsimplexmlrpc.tex, 1.7.2.1, 1.7.2.2 Message-ID: <20050818194834.A05121E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11778/Doc/lib Modified Files: Tag: release24-maint libsimplexmlrpc.tex Log Message: Backport checkin: Fix typo (fixes SF bug #1263086). Index: libsimplexmlrpc.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libsimplexmlrpc.tex,v retrieving revision 1.7.2.1 retrieving revision 1.7.2.2 diff -u -d -r1.7.2.1 -r1.7.2.2 --- libsimplexmlrpc.tex 3 Feb 2005 15:00:17 -0000 1.7.2.1 +++ libsimplexmlrpc.tex 18 Aug 2005 19:48:24 -0000 1.7.2.2 @@ -61,7 +61,7 @@ not been registered using \method{register_function()}. If \var{instance} contains a \method{_dispatch()} method, it is called with the requested method name and the parameters from the request. Its - API is \code{def \method{_dispatch}(self, method, params)} (note tha + API is \code{def \method{_dispatch}(self, method, params)} (note that \var{params} does not represent a variable argument list). If it calls an underlying function to perform its task, that function is called as \code{func(*params)}, expanding the parameter list. From rhettinger at users.sourceforge.net Thu Aug 18 23:27:21 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Thu, 18 Aug 2005 23:27:21 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libstdtypes.tex, 1.184, 1.185 Message-ID: <20050818212721.D27DB1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2695 Modified Files: libstdtypes.tex Log Message: Fix markup. Index: libstdtypes.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libstdtypes.tex,v retrieving revision 1.184 retrieving revision 1.185 diff -u -d -r1.184 -r1.185 --- libstdtypes.tex 4 Jul 2005 14:17:47 -0000 1.184 +++ libstdtypes.tex 18 Aug 2005 21:27:11 -0000 1.185 @@ -1300,7 +1300,7 @@ \end{seealso} -\subsection{Mapping Types --- class{dict} \label{typesmapping}} +\subsection{Mapping Types --- \class{dict} \label{typesmapping}} \obindex{mapping} \obindex{dictionary} From akuchling at users.sourceforge.net Thu Aug 18 23:45:41 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Thu, 18 Aug 2005 23:45:41 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib liblogging.tex, 1.38, 1.39 Message-ID: <20050818214541.BEAFF1E4067@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7096 Modified Files: liblogging.tex Log Message: Typo fix Index: liblogging.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liblogging.tex,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- liblogging.tex 29 Jul 2005 11:52:19 -0000 1.38 +++ liblogging.tex 18 Aug 2005 21:45:31 -0000 1.39 @@ -92,7 +92,7 @@ \item \class{FileHandler} instances send error messages to disk files. -\item \class{BaseRotatingHandler} is tha base class for handlers that +\item \class{BaseRotatingHandler} is the base class for handlers that rotate log files at a certain point. It is not meant to be instantiated directly. Instead, use \class{RotatingFileHandler} or \class{TimedRotatingFileHandler}. From akuchling at users.sourceforge.net Thu Aug 18 23:53:29 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Thu, 18 Aug 2005 23:53:29 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib liblogging.tex, 1.33.2.2, 1.33.2.3 Message-ID: <20050818215329.30DEB1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8888 Modified Files: Tag: release24-maint liblogging.tex Log Message: Typo fix Index: liblogging.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liblogging.tex,v retrieving revision 1.33.2.2 retrieving revision 1.33.2.3 diff -u -d -r1.33.2.2 -r1.33.2.3 --- liblogging.tex 31 Mar 2005 20:23:04 -0000 1.33.2.2 +++ liblogging.tex 18 Aug 2005 21:53:19 -0000 1.33.2.3 @@ -92,7 +92,7 @@ \item \class{FileHandler} instances send error messages to disk files. -\item \class{BaseRotatingHandler} is tha base class for handlers that +\item \class{BaseRotatingHandler} is the base class for handlers that rotate log files at a certain point. It is not meant to be instantiated directly. Instead, use \class{RotatingFileHandler} or \class{TimedRotatingFileHandler}. From pje at users.sourceforge.net Fri Aug 19 03:02:04 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Fri, 19 Aug 2005 03:02:04 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.py, 1.69, 1.70 Message-ID: <20050819010204.1808B1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18276 Modified Files: pkg_resources.py Log Message: Fix namespace packages not getting fixed up when the eggs are zipped and loaded late (i.e. via require). Thanks to Walter Doerwald for the bug report. Index: pkg_resources.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.py,v retrieving revision 1.69 retrieving revision 1.70 diff -u -d -r1.69 -r1.70 --- pkg_resources.py 14 Aug 2005 21:01:33 -0000 1.69 +++ pkg_resources.py 19 Aug 2005 01:01:53 -0000 1.70 @@ -1429,8 +1429,8 @@ handler = _find_adapter(_namespace_handlers, importer) subpath = handler(importer,path_item,packageName,module) if subpath is not None: - module.__path__.append(subpath) - loader.load_module(packageName) + path = module.__path__; path.append(subpath) + loader.load_module(packageName); module.__path__ = path return subpath def declare_namespace(packageName): From rhettinger at users.sourceforge.net Fri Aug 19 03:36:45 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri, 19 Aug 2005 03:36:45 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib random.py,1.71,1.72 Message-ID: <20050819013645.19C421E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27122 Modified Files: random.py Log Message: Implement random.sample() using sets instead of dicts. Index: random.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/random.py,v retrieving revision 1.71 retrieving revision 1.72 diff -u -d -r1.71 -r1.72 --- random.py 30 Apr 2005 09:02:51 -0000 1.71 +++ random.py 19 Aug 2005 01:36:35 -0000 1.72 @@ -41,7 +41,7 @@ from warnings import warn as _warn from types import MethodType as _MethodType, BuiltinMethodType as _BuiltinMethodType -from math import log as _log, exp as _exp, pi as _pi, e as _e +from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin from os import urandom as _urandom from binascii import hexlify as _hexlify @@ -286,15 +286,14 @@ """ # Sampling without replacement entails tracking either potential - # selections (the pool) in a list or previous selections in a - # dictionary. + # selections (the pool) in a list or previous selections in a set. # When the number of selections is small compared to the # population, then tracking selections is efficient, requiring - # only a small dictionary and an occasional reselection. For + # only a small set and an occasional reselection. For # a larger number of selections, the pool tracking method is # preferred since the list takes less space than the - # dictionary and it doesn't suffer from frequent reselections. + # set and it doesn't suffer from frequent reselections. n = len(population) if not 0 <= k <= n: @@ -302,7 +301,10 @@ random = self.random _int = int result = [None] * k - if n < 6 * k: # if n len list takes less space than a k len dict + setsize = 21 # size of a small set minus size of an empty list + if k > 5: + setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets + if n <= setsize: # is an n-length list smaller than a k-length set pool = list(population) for i in xrange(k): # invariant: non-selected at [0,n-i) j = _int(random() * (n-i)) @@ -311,14 +313,16 @@ else: try: n > 0 and (population[0], population[n//2], population[n-1]) - except (TypeError, KeyError): # handle sets and dictionaries + except (TypeError, KeyError): # handle non-sequence iterables population = tuple(population) - selected = {} + selected = set() + selected_add = selected.add for i in xrange(k): j = _int(random() * n) while j in selected: j = _int(random() * n) - result[i] = selected[j] = population[j] + selected_add(j) + result[i] = population[j] return result ## -------------------- real-valued distributions ------------------- From AmenhoCorley7411 at futureachievement.c Fri Aug 19 12:55:38 2005 From: AmenhoCorley7411 at futureachievement.c (Amenhotep Corley) Date: Fri, 19 Aug 2005 05:55:38 -0500 Subject: [Python-checkins] =?iso-8859-1?q?VIAGRR=C1-Good_for_your_life?= Message-ID: <002b01c5a4ac$886b7100$0048a8c0@eluvium> Hello, even Stravinsky, a psychiatrist of genius, did not, of course, believe you.the way up the mountain was open and from where it would have been mostdo. The mechanism of this forced adjustment is revealed in the chapterintact were flung open, peoples heads appeared in them and hid at once, He, for example, the present procurator of Judea and former tribune of Why? the procurator asked, his face darkening. `Am I disagreeable toare surprised theres no light? Economy, so you think, of course? Unh-unh!went and sold her to a brothel... I beg you not to teach me, replied Behemoth, `I have sat at table,Margarita, blown upon by the cool wind, opened her eyes, she saw how theoh, no, he did not blame her! Margarita said, with a crooked and bitter smile:hoarse voice, and pounding the table with her fist, she said she wouldeyes of Niza, which now seemed black. It could be seen that the broken line especially upset him for some `I see youre somewhat surprised, my dearest Stepan Bogdanovich? -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20050819/47508540/attachment.htm From gregorykjohnson at users.sourceforge.net Fri Aug 19 21:26:06 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Fri, 19 Aug 2005 21:26:06 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.11, 1.12 Message-ID: <20050819192606.A7E9E1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15071 Modified Files: mailbox.py Log Message: Fix some things pointed out by A.M. Kuchling. Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- mailbox.py 17 Aug 2005 20:32:36 -0000 1.11 +++ mailbox.py 19 Aug 2005 19:25:55 -0000 1.12 @@ -197,8 +197,8 @@ line = message.readline() if line == '': break - if line[:5] == 'From ': - line = '>From ' + s[5:] + if line.startswith('From '): + line = '>From ' + line[5:] target.write(line) else: while True: @@ -635,7 +635,7 @@ def _install_message(self, message): """Format a message and blindly write to self._file.""" from_line = None - if isinstance(message, str) and message[:5] == 'From ': + if isinstance(message, str) and message.startswith('From '): newline = message.find(os.linesep) if newline != -1: from_line = message[:newline] @@ -678,7 +678,7 @@ while True: line_pos = self._file.tell() line = self._file.readline() - if line[:5] == 'From ': + if line.startswith('From '): if len(stops) < len(starts): stops.append(line_pos - len(os.linesep)) starts.append(line_pos) @@ -714,7 +714,7 @@ line_pos = next_pos line = self._file.readline() next_pos = self._file.tell() - if line[:4 + len(os.linesep)] == '\001\001\001\001' + os.linesep: + if line.startswith('\001\001\001\001' + os.linesep): starts.append(next_pos) while True: line_pos = next_pos @@ -1216,14 +1216,14 @@ if line == os.linesep or line == '': break while True: - buffer = pseudofile.read(4069) # Buffer size is arbitrary. + buffer = pseudofile.read(4096) # Buffer size is arbitrary. if buffer == '': break self._file.write(buffer) elif isinstance(message, str): body_start = message.find(os.linesep + os.linesep) + \ 2 * len(os.linesep) - if body_start - 2 != -1: + if body_start - 2 * len(os.linesep) != -1: self._file.write(message[:body_start]) self._file.write('*** EOOH ***' + os.linesep) self._file.write(message[:body_start]) @@ -1310,7 +1310,7 @@ def get_flags(self): """Return as a string the flags that are set.""" - if len(self._info) > 2 and self._info[:2] == '2,': + if len(self._info) > 2 and self._info.startswith('2,'): return self._info[2:] else: return '' @@ -1402,7 +1402,7 @@ self.set_from('MAILER-DAEMON', True) if isinstance(message, email.Message.Message): unixfrom = message.get_unixfrom() - if unixfrom is not None and unixfrom[:5] == 'From ': + if unixfrom is not None and unixfrom.startswith('From '): self.set_from(unixfrom[5:]) Message.__init__(self, message) From goodger at users.sourceforge.net Sat Aug 20 15:49:00 2005 From: goodger at users.sourceforge.net (goodger@users.sourceforge.net) Date: Sat, 20 Aug 2005 15:49:00 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0008.txt,1.26,1.27 Message-ID: <20050820134900.9D7DE1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6037 Modified Files: pep-0008.txt Log Message: fixed raise syntax examples; closing http://python.org/sf/1264666 Index: pep-0008.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0008.txt,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- pep-0008.txt 7 Aug 2005 13:27:54 -0000 1.26 +++ pep-0008.txt 20 Aug 2005 13:48:50 -0000 1.27 @@ -96,10 +96,10 @@ if width == 0 and height == 0 and \ color == 'red' and emphasis == 'strong' or \ highlight > 100: - raise ValueError, "sorry, you lose" + raise ValueError("sorry, you lose") if width == 0 and height == 0 and (color == 'red' or emphasis is None): - raise ValueError, "I don't think so" + raise ValueError("I don't think so") Blob.__init__(self, width, height, color, emphasis, highlight) From rhettinger at users.sourceforge.net Sun Aug 21 01:52:42 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 01:52:42 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/api refcounts.dat,1.44,1.45 Message-ID: <20050820235242.8530F1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/api In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28881 Modified Files: refcounts.dat Log Message: Add info about the set API. Index: refcounts.dat =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/api/refcounts.dat,v retrieving revision 1.44 retrieving revision 1.45 diff -u -d -r1.44 -r1.45 --- refcounts.dat 4 Oct 2002 18:58:58 -0000 1.44 +++ refcounts.dat 20 Aug 2005 23:52:30 -0000 1.45 @@ -1009,6 +1009,25 @@ PySequence_Tuple:PyObject*::+1: PySequence_Tuple:PyObject*:o:0: +PySet_Append:int::: +PySet_Append:PyObject*:set:0: +PySet_Append:PyObject*:key:+1: + +PySet_Contains:int::: +PySet_Contains:PyObject*:anyset:0: +PySet_Contains:PyObject*:key:0: + +PySet_Discard:int::: +PySet_Discard:PyObject*:set:0: +PySet_Discard:PyObject*:key:-1:no effect if key not found + +PySet_Pop:PyObject*::+1:or NULL if key not found +PySet_Pop:PyObject*:set:0: +PySet_Pop:PyObject*:key:-1:no effect if key not found + +PySet_Size:int::: +PySet_Size:PyObject*:anyset:0: + PySlice_Check:int::: PySlice_Check:PyObject*:ob:0: From rhettinger at users.sourceforge.net Sun Aug 21 02:08:46 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 02:08:46 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/api refcounts.dat,1.45,1.46 Message-ID: <20050821000846.9FDA51E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/api In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31857 Modified Files: refcounts.dat Log Message: Fix PySet_Pop() notes. Index: refcounts.dat =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/api/refcounts.dat,v retrieving revision 1.45 retrieving revision 1.46 diff -u -d -r1.45 -r1.46 --- refcounts.dat 20 Aug 2005 23:52:30 -0000 1.45 +++ refcounts.dat 21 Aug 2005 00:08:36 -0000 1.46 @@ -1021,9 +1021,8 @@ PySet_Discard:PyObject*:set:0: PySet_Discard:PyObject*:key:-1:no effect if key not found -PySet_Pop:PyObject*::+1:or NULL if key not found +PySet_Pop:PyObject*::0:or returns NULL and raises KeyError if set is empty PySet_Pop:PyObject*:set:0: -PySet_Pop:PyObject*:key:-1:no effect if key not found PySet_Size:int::: PySet_Size:PyObject*:anyset:0: From birkenfeld at users.sourceforge.net Sun Aug 21 11:41:34 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sun, 21 Aug 2005 11:41:34 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref5.tex,1.88,1.89 Message-ID: <20050821094134.4F6EC1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20604/Doc/ref Modified Files: ref5.tex Log Message: Mention explicitly the False is considered false. Index: ref5.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref5.tex,v retrieving revision 1.88 retrieving revision 1.89 diff -u -d -r1.88 -r1.89 --- ref5.tex 19 Jan 2005 03:39:16 -0000 1.88 +++ ref5.tex 21 Aug 2005 09:41:21 -0000 1.89 @@ -1021,9 +1021,9 @@ In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted -as false: \code{None}, numeric zero of all types, empty sequences -(strings, tuples and lists), and empty mappings (dictionaries). All -other values are interpreted as true. +as false: \code{False}, \code{None}, numeric zero of all types, empty +sequences (strings, tuples and lists), and empty mappings (dictionaries). +All other values are interpreted as true. The operator \keyword{not} yields \code{True} if its argument is false, \code{False} otherwise. From birkenfeld at users.sourceforge.net Sun Aug 21 11:41:58 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sun, 21 Aug 2005 11:41:58 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref5.tex, 1.86.2.2, 1.86.2.3 Message-ID: <20050821094158.359BB1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20679/Doc/ref Modified Files: Tag: release24-maint ref5.tex Log Message: Mention explicitly that False is considered false. Index: ref5.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref5.tex,v retrieving revision 1.86.2.2 retrieving revision 1.86.2.3 diff -u -d -r1.86.2.2 -r1.86.2.3 --- ref5.tex 19 Jan 2005 03:42:09 -0000 1.86.2.2 +++ ref5.tex 21 Aug 2005 09:41:48 -0000 1.86.2.3 @@ -1021,9 +1021,9 @@ In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted -as false: \code{None}, numeric zero of all types, empty sequences -(strings, tuples and lists), and empty mappings (dictionaries). All -other values are interpreted as true. +as false: \code{False}, \code{None}, numeric zero of all types, empty +sequences (strings, tuples and lists), and empty mappings (dictionaries). +All other values are interpreted as true. The operator \keyword{not} yields \code{True} if its argument is false, \code{False} otherwise. From rhettinger at users.sourceforge.net Sun Aug 21 13:04:13 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:04:13 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python bltinmodule.c, 2.322, 2.323 Message-ID: <20050821110413.63CF11E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1877/Python Modified Files: bltinmodule.c Log Message: SF bug #1242657: list(obj) can swallow KeyboardInterrupt Fix over-aggressive PyErr_Clear(). The same code fragment appears in various guises in list.extend(), map(), filter(), zip(), and internally in PySequence_Tuple(). Index: bltinmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/bltinmodule.c,v retrieving revision 2.322 retrieving revision 2.323 diff -u -d -r2.322 -r2.323 --- bltinmodule.c 19 Jul 2005 22:20:20 -0000 2.322 +++ bltinmodule.c 21 Aug 2005 11:03:58 -0000 2.323 @@ -223,6 +223,10 @@ /* Guess a result list size. */ len = PyObject_Size(seq); if (len < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + goto Fail_it; + } PyErr_Clear(); len = 8; /* arbitrary */ } @@ -864,6 +868,10 @@ /* Update len. */ curlen = PyObject_Size(curseq); if (curlen < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + goto Fail_2; + } PyErr_Clear(); curlen = 8; /* arbitrary */ } @@ -2097,6 +2105,10 @@ PyObject *item = PyTuple_GET_ITEM(args, i); int thislen = PyObject_Size(item); if (thislen < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + return NULL; + } PyErr_Clear(); len = -1; break; From rhettinger at users.sourceforge.net Sun Aug 21 13:04:13 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:04:13 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test list_tests.py,1.6,1.7 Message-ID: <20050821110413.6DD281E4006@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1877/Lib/test Modified Files: list_tests.py Log Message: SF bug #1242657: list(obj) can swallow KeyboardInterrupt Fix over-aggressive PyErr_Clear(). The same code fragment appears in various guises in list.extend(), map(), filter(), zip(), and internally in PySequence_Tuple(). Index: list_tests.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/list_tests.py,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- list_tests.py 21 Mar 2005 21:31:47 -0000 1.6 +++ list_tests.py 21 Aug 2005 11:03:59 -0000 1.7 @@ -514,3 +514,12 @@ a = self.type2test(range(10)) a[::2] = tuple(range(5)) self.assertEqual(a, self.type2test([0, 1, 1, 3, 2, 5, 3, 7, 4, 9])) + + def test_constructor_exception_handling(self): + # Bug #1242657 + class F(object): + def __iter__(self): + yield 23 + def __len__(self): + raise KeyboardInterrupt + self.assertRaises(KeyboardInterrupt, list, F()) From rhettinger at users.sourceforge.net Sun Aug 21 13:04:13 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:04:13 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects abstract.c, 2.137, 2.138 listobject.c, 2.225, 2.226 Message-ID: <20050821110413.6FD3D1E4009@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1877/Objects Modified Files: abstract.c listobject.c Log Message: SF bug #1242657: list(obj) can swallow KeyboardInterrupt Fix over-aggressive PyErr_Clear(). The same code fragment appears in various guises in list.extend(), map(), filter(), zip(), and internally in PySequence_Tuple(). Index: abstract.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v retrieving revision 2.137 retrieving revision 2.138 diff -u -d -r2.137 -r2.138 --- abstract.c 12 Jul 2005 10:21:02 -0000 2.137 +++ abstract.c 21 Aug 2005 11:03:56 -0000 2.138 @@ -1401,6 +1401,11 @@ /* Guess result size and allocate space. */ n = PyObject_Size(v); if (n < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_DECREF(it); + return NULL; + } PyErr_Clear(); n = 10; /* arbitrary */ } Index: listobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v retrieving revision 2.225 retrieving revision 2.226 diff -u -d -r2.225 -r2.226 --- listobject.c 7 Oct 2004 03:58:07 -0000 2.225 +++ listobject.c 21 Aug 2005 11:03:57 -0000 2.226 @@ -777,6 +777,11 @@ /* Guess a result list size. */ n = PyObject_Size(b); if (n < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_DECREF(it); + return NULL; + } PyErr_Clear(); n = 8; /* arbitrary */ } From rhettinger at users.sourceforge.net Sun Aug 21 13:10:09 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:10:09 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python bltinmodule.c, 2.318.2.1, 2.318.2.2 Message-ID: <20050821111009.6AF161E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4160/Python Modified Files: Tag: release24-maint bltinmodule.c Log Message: SF bug #1242657: list(obj) can swallow KeyboardInterrupt Fix over-aggressive PyErr_Clear(). The same code fragment appears in various guises in list.extend(), map(), filter(), zip(), and internally in PySequence_Tuple(). Index: bltinmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/bltinmodule.c,v retrieving revision 2.318.2.1 retrieving revision 2.318.2.2 diff -u -d -r2.318.2.1 -r2.318.2.2 --- bltinmodule.c 19 Jul 2005 22:20:44 -0000 2.318.2.1 +++ bltinmodule.c 21 Aug 2005 11:09:58 -0000 2.318.2.2 @@ -160,6 +160,10 @@ /* Guess a result list size. */ len = PyObject_Size(seq); if (len < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + goto Fail_it; + } PyErr_Clear(); len = 8; /* arbitrary */ } @@ -801,6 +805,10 @@ /* Update len. */ curlen = PyObject_Size(curseq); if (curlen < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + goto Fail_2; + } PyErr_Clear(); curlen = 8; /* arbitrary */ } @@ -2002,6 +2010,10 @@ PyObject *item = PyTuple_GET_ITEM(args, i); int thislen = PyObject_Size(item); if (thislen < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + return NULL; + } PyErr_Clear(); len = -1; break; From rhettinger at users.sourceforge.net Sun Aug 21 13:10:09 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:10:09 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test list_tests.py, 1.5, 1.5.2.1 Message-ID: <20050821111009.7925C1E4006@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4160/Lib/test Modified Files: Tag: release24-maint list_tests.py Log Message: SF bug #1242657: list(obj) can swallow KeyboardInterrupt Fix over-aggressive PyErr_Clear(). The same code fragment appears in various guises in list.extend(), map(), filter(), zip(), and internally in PySequence_Tuple(). Index: list_tests.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/list_tests.py,v retrieving revision 1.5 retrieving revision 1.5.2.1 diff -u -d -r1.5 -r1.5.2.1 --- list_tests.py 30 Sep 2004 07:47:20 -0000 1.5 +++ list_tests.py 21 Aug 2005 11:09:58 -0000 1.5.2.1 @@ -494,3 +494,12 @@ a = self.type2test(range(10)) a[::2] = tuple(range(5)) self.assertEqual(a, self.type2test([0, 1, 1, 3, 2, 5, 3, 7, 4, 9])) + + def test_constructor_exception_handling(self): + # Bug #1242657 + class F(object): + def __iter__(self): + yield 23 + def __len__(self): + raise KeyboardInterrupt + self.assertRaises(KeyboardInterrupt, list, F()) From rhettinger at users.sourceforge.net Sun Aug 21 13:10:09 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:10:09 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects abstract.c, 2.132.2.1, 2.132.2.2 listobject.c, 2.225, 2.225.2.1 Message-ID: <20050821111009.7F43A1E4009@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4160/Objects Modified Files: Tag: release24-maint abstract.c listobject.c Log Message: SF bug #1242657: list(obj) can swallow KeyboardInterrupt Fix over-aggressive PyErr_Clear(). The same code fragment appears in various guises in list.extend(), map(), filter(), zip(), and internally in PySequence_Tuple(). Index: abstract.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/abstract.c,v retrieving revision 2.132.2.1 retrieving revision 2.132.2.2 diff -u -d -r2.132.2.1 -r2.132.2.2 --- abstract.c 17 Dec 2004 14:44:45 -0000 2.132.2.1 +++ abstract.c 21 Aug 2005 11:09:58 -0000 2.132.2.2 @@ -1411,6 +1411,11 @@ /* Guess result size and allocate space. */ n = PyObject_Size(v); if (n < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_DECREF(it); + return NULL; + } PyErr_Clear(); n = 10; /* arbitrary */ } Index: listobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/listobject.c,v retrieving revision 2.225 retrieving revision 2.225.2.1 diff -u -d -r2.225 -r2.225.2.1 --- listobject.c 7 Oct 2004 03:58:07 -0000 2.225 +++ listobject.c 21 Aug 2005 11:09:58 -0000 2.225.2.1 @@ -777,6 +777,11 @@ /* Guess a result list size. */ n = PyObject_Size(b); if (n < 0) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_AttributeError)) { + Py_DECREF(it); + return NULL; + } PyErr_Clear(); n = 8; /* arbitrary */ } From rhettinger at users.sourceforge.net Sun Aug 21 13:26:25 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:26:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref3.tex,1.125,1.126 Message-ID: <20050821112625.D28301E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32229 Modified Files: ref3.tex Log Message: SF bug #1249837: container methods raise KeyError not IndexError Minor clarification. Index: ref3.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref3.tex,v retrieving revision 1.125 retrieving revision 1.126 diff -u -d -r1.125 -r1.126 --- ref3.tex 2 Jul 2005 10:27:31 -0000 1.125 +++ ref3.tex 21 Aug 2005 11:26:14 -0000 1.126 @@ -1658,6 +1658,8 @@ raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), \exception{IndexError} should be raised. +For mapping types, if \var{key} is missing (not in the container), +\exception{KeyError} should be raised. \note{\keyword{for} loops expect that an \exception{IndexError} will be raised for illegal indexes to allow proper detection of the end of the sequence.} From rhettinger at users.sourceforge.net Sun Aug 21 13:27:45 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:27:45 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref3.tex, 1.121.2.4, 1.121.2.5 Message-ID: <20050821112745.86D261E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4777 Modified Files: Tag: release24-maint ref3.tex Log Message: SF bug #1249837: container methods raise KeyError not IndexError Minor clarification. Index: ref3.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref3.tex,v retrieving revision 1.121.2.4 retrieving revision 1.121.2.5 diff -u -d -r1.121.2.4 -r1.121.2.5 --- ref3.tex 2 Jul 2005 10:28:29 -0000 1.121.2.4 +++ ref3.tex 21 Aug 2005 11:27:35 -0000 1.121.2.5 @@ -1658,6 +1658,8 @@ raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values), \exception{IndexError} should be raised. +For mapping types, if \var{key} is missing (not in the container), +\exception{KeyError} should be raised. \note{\keyword{for} loops expect that an \exception{IndexError} will be raised for illegal indexes to allow proper detection of the end of the sequence.} From rhettinger at users.sourceforge.net Sun Aug 21 13:58:17 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:58:17 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libfuncs.tex, 1.186, 1.187 Message-ID: <20050821115817.6E7661E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10524 Modified Files: libfuncs.tex Log Message: SF bug #1121416: zip incorrectly and incompletely documented sequences ==> iterables Index: libfuncs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libfuncs.tex,v retrieving revision 1.186 retrieving revision 1.187 diff -u -d -r1.186 -r1.187 --- libfuncs.tex 3 Aug 2005 07:17:33 -0000 1.186 +++ libfuncs.tex 21 Aug 2005 11:58:06 -0000 1.187 @@ -1149,12 +1149,12 @@ that the number of elements fit in a native C long.} \end{funcdesc} -\begin{funcdesc}{zip}{\optional{seq1, \moreargs}} +\begin{funcdesc}{zip}{\optional{iterable, \moreargs}} This function returns a list of tuples, where the \var{i}-th tuple contains - the \var{i}-th element from each of the argument sequences. + the \var{i}-th element from each of the argument sequences or iterables. The returned list is truncated in length to the length of - the shortest argument sequence. When there are multiple argument - sequences which are all of the same length, \function{zip()} is + the shortest argument sequence. When there are multiple arguments + which are all of the same length, \function{zip()} is similar to \function{map()} with an initial argument of \code{None}. With a single sequence argument, it returns a list of 1-tuples. With no arguments, it returns an empty list. From rhettinger at users.sourceforge.net Sun Aug 21 13:59:14 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 13:59:14 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libfuncs.tex, 1.175.2.6, 1.175.2.7 Message-ID: <20050821115914.46D511E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10749 Modified Files: Tag: release24-maint libfuncs.tex Log Message: SF bug #1121416: zip incorrectly and incompletely documented sequences ==> iterables Index: libfuncs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libfuncs.tex,v retrieving revision 1.175.2.6 retrieving revision 1.175.2.7 diff -u -d -r1.175.2.6 -r1.175.2.7 --- libfuncs.tex 3 Aug 2005 07:18:04 -0000 1.175.2.6 +++ libfuncs.tex 21 Aug 2005 11:59:04 -0000 1.175.2.7 @@ -1111,12 +1111,12 @@ that the number of elements fit in a native C long.} \end{funcdesc} -\begin{funcdesc}{zip}{\optional{seq1, \moreargs}} +\begin{funcdesc}{zip}{\optional{iterable, \moreargs}} This function returns a list of tuples, where the \var{i}-th tuple contains - the \var{i}-th element from each of the argument sequences. + the \var{i}-th element from each of the argument sequences or iterables. The returned list is truncated in length to the length of - the shortest argument sequence. When there are multiple argument - sequences which are all of the same length, \function{zip()} is + the shortest argument sequence. When there are multiple arguments + which are all of the same length, \function{zip()} is similar to \function{map()} with an initial argument of \code{None}. With a single sequence argument, it returns a list of 1-tuples. With no arguments, it returns an empty list. From birkenfeld at users.sourceforge.net Sun Aug 21 14:23:13 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sun, 21 Aug 2005 14:23:13 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref5.tex,1.89,1.90 Message-ID: <20050821122313.7FE421E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15548/Doc/ref Modified Files: ref5.tex Log Message: Empty sets and frozensets are also false. Index: ref5.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref5.tex,v retrieving revision 1.89 retrieving revision 1.90 diff -u -d -r1.89 -r1.90 --- ref5.tex 21 Aug 2005 09:41:21 -0000 1.89 +++ ref5.tex 21 Aug 2005 12:22:58 -0000 1.90 @@ -1021,9 +1021,9 @@ In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted -as false: \code{False}, \code{None}, numeric zero of all types, empty -sequences (strings, tuples and lists), and empty mappings (dictionaries). -All other values are interpreted as true. +as false: \code{False}, \code{None}, numeric zero of all types, and empty +strings and containers (including strings, tuples, lists, dictionaries, +sets and frozensets). All other values are interpreted as true. The operator \keyword{not} yields \code{True} if its argument is false, \code{False} otherwise. From birkenfeld at users.sourceforge.net Sun Aug 21 14:23:16 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sun, 21 Aug 2005 14:23:16 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref5.tex, 1.86.2.3, 1.86.2.4 Message-ID: <20050821122316.A45471E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15598/Doc/ref Modified Files: Tag: release24-maint ref5.tex Log Message: Empty sets and frozensets are also false. Index: ref5.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref5.tex,v retrieving revision 1.86.2.3 retrieving revision 1.86.2.4 diff -u -d -r1.86.2.3 -r1.86.2.4 --- ref5.tex 21 Aug 2005 09:41:48 -0000 1.86.2.3 +++ ref5.tex 21 Aug 2005 12:23:06 -0000 1.86.2.4 @@ -1021,9 +1021,9 @@ In the context of Boolean operations, and also when expressions are used by control flow statements, the following values are interpreted -as false: \code{False}, \code{None}, numeric zero of all types, empty -sequences (strings, tuples and lists), and empty mappings (dictionaries). -All other values are interpreted as true. +as false: \code{False}, \code{None}, numeric zero of all types, and empty +strings and containers (including strings, tuples, lists, dictionaries, +sets and frozensets). All other values are interpreted as true. The operator \keyword{not} yields \code{True} if its argument is false, \code{False} otherwise. From rhettinger at users.sourceforge.net Sun Aug 21 14:35:39 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 14:35:39 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/tut glossary.tex,1.12,1.13 Message-ID: <20050821123539.69B4D1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17182 Modified Files: glossary.tex Log Message: SF bug #1168135: Python 2.5a0 Tutorial errors and observations (Contributed by Michael R Bax.) Index: glossary.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/glossary.tex,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- glossary.tex 14 May 2005 17:18:31 -0000 1.12 +++ glossary.tex 21 Aug 2005 12:35:29 -0000 1.13 @@ -24,9 +24,9 @@ \index{byte code} \item[byte code] The internal representation of a Python program in the interpreter. -The byte code is also cached in the \code{.pyc} and \code{.pyo} +The byte code is also cached in \code{.pyc} and \code{.pyo} files so that executing the same file is faster the second time -(compilation from source to byte code can be saved). This +(recompilation from source to byte code can be avoided). This ``intermediate language'' is said to run on a ``virtual machine'' that calls the subroutines corresponding to each bytecode. @@ -37,7 +37,6 @@ \index{coercion} \item[coercion] - The implicit conversion of an instance of one type to another during an operation which involves two arguments of the same type. For example, {}\code{int(3.15)} converts the floating point number to the integer @@ -53,7 +52,6 @@ \index{complex number} \item[complex number] - An extension of the familiar real number system in which all numbers are expressed as a sum of a real part and an imaginary part. Imaginary numbers are real multiples of the imaginary unit (the square root of {}\code{-1}), @@ -117,7 +115,7 @@ from __future__ import division \end{verbatim} -the expression \code{11/4} would evaluate to \code{2.75}. By actually +the expression \code{11/4} would evaluate to \code{2.75}. By importing the \ulink{\module{__future__}}{../lib/module-future.html} module and evaluating its variables, you can see when a new feature was first added to the language and when it will become the default: @@ -249,6 +247,13 @@ return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container. +\index{LBYL} +\item[LBYL] +Look before you leap. This coding style explicitly tests for +pre-conditions before making calls or lookups. This style contrasts +with the \emph{EAFP} approach and is characterized by the presence of +many \keyword{if} statements. + \index{list comprehension} \item[list comprehension] A compact way to process all or a subset of elements in a sequence and @@ -258,14 +263,6 @@ The \keyword{if} clause is optional. If omitted, all elements in {}\code{range(256)} are processed. - -\index{LBYL} -\item[LBYL] -Look before you leap. This coding style explicitly tests for -pre-conditions before making calls or lookups. This style contrasts -with the \emph{EAFP} approach and is characterized by the presence of -many \keyword{if} statements. - \index{mapping} \item[mapping] A container object (such as \class{dict}) that supports arbitrary key @@ -293,11 +290,11 @@ \item[namespace] The place where a variable is stored. Namespaces are implemented as dictionaries. There are the local, global and builtin namespaces -as well asnested namespaces in objects (in methods). Namespaces support +as well as nested namespaces in objects (in methods). Namespaces support modularity by preventing naming conflicts. For instance, the functions \function{__builtin__.open()} and \function{os.open()} are distinguished by their namespaces. Namespaces also aid readability -and maintainability by making it clear which modules implement a +and maintainability by making it clear which module implements a function. For instance, writing \function{random.seed()} or {}\function{itertools.izip()} makes it clear that those functions are implemented by the \ulink{\module{random}}{../lib/module-random.html} @@ -324,7 +321,7 @@ \index{Python3000} \item[Python3000] -A mythical python release, not required be backward compatible, with +A mythical python release, not required to be backward compatible, with telepathic interface. \index{__slots__} From rhettinger at users.sourceforge.net Sun Aug 21 14:36:33 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Sun, 21 Aug 2005 14:36:33 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/tut glossary.tex, 1.9.4.3, 1.9.4.4 Message-ID: <20050821123633.07B941E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17327 Modified Files: Tag: release24-maint glossary.tex Log Message: SF bug #1168135: Python 2.5a0 Tutorial errors and observations (Contributed by Michael R Bax.) Index: glossary.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/glossary.tex,v retrieving revision 1.9.4.3 retrieving revision 1.9.4.4 diff -u -d -r1.9.4.3 -r1.9.4.4 --- glossary.tex 14 May 2005 17:20:25 -0000 1.9.4.3 +++ glossary.tex 21 Aug 2005 12:36:21 -0000 1.9.4.4 @@ -24,9 +24,9 @@ \index{byte code} \item[byte code] The internal representation of a Python program in the interpreter. -The byte code is also cached in the \code{.pyc} and \code{.pyo} +The byte code is also cached in \code{.pyc} and \code{.pyo} files so that executing the same file is faster the second time -(compilation from source to byte code can be saved). This +(recompilation from source to byte code can be avoided). This ``intermediate language'' is said to run on a ``virtual machine'' that calls the subroutines corresponding to each bytecode. @@ -37,7 +37,6 @@ \index{coercion} \item[coercion] - The implicit conversion of an instance of one type to another during an operation which involves two arguments of the same type. For example, {}\code{int(3.15)} converts the floating point number to the integer @@ -53,7 +52,6 @@ \index{complex number} \item[complex number] - An extension of the familiar real number system in which all numbers are expressed as a sum of a real part and an imaginary part. Imaginary numbers are real multiples of the imaginary unit (the square root of {}\code{-1}), @@ -117,7 +115,7 @@ from __future__ import division \end{verbatim} -the expression \code{11/4} would evaluate to \code{2.75}. By actually +the expression \code{11/4} would evaluate to \code{2.75}. By importing the \ulink{\module{__future__}}{../lib/module-future.html} module and evaluating its variables, you can see when a new feature was first added to the language and when it will become the default: @@ -249,6 +247,13 @@ return the same exhausted iterator object used in the previous iteration pass, making it appear like an empty container. +\index{LBYL} +\item[LBYL] +Look before you leap. This coding style explicitly tests for +pre-conditions before making calls or lookups. This style contrasts +with the \emph{EAFP} approach and is characterized by the presence of +many \keyword{if} statements. + \index{list comprehension} \item[list comprehension] A compact way to process all or a subset of elements in a sequence and @@ -258,14 +263,6 @@ The \keyword{if} clause is optional. If omitted, all elements in {}\code{range(256)} are processed. - -\index{LBYL} -\item[LBYL] -Look before you leap. This coding style explicitly tests for -pre-conditions before making calls or lookups. This style contrasts -with the \emph{EAFP} approach and is characterized by the presence of -many \keyword{if} statements. - \index{mapping} \item[mapping] A container object (such as \class{dict}) that supports arbitrary key @@ -293,11 +290,11 @@ \item[namespace] The place where a variable is stored. Namespaces are implemented as dictionaries. There are the local, global and builtin namespaces -as well asnested namespaces in objects (in methods). Namespaces support +as well as nested namespaces in objects (in methods). Namespaces support modularity by preventing naming conflicts. For instance, the functions \function{__builtin__.open()} and \function{os.open()} are distinguished by their namespaces. Namespaces also aid readability -and maintainability by making it clear which modules implement a +and maintainability by making it clear which module implements a function. For instance, writing \function{random.seed()} or {}\function{itertools.izip()} makes it clear that those functions are implemented by the \ulink{\module{random}}{../lib/module-random.html} @@ -324,7 +321,7 @@ \index{Python3000} \item[Python3000] -A mythical python release, not required be backward compatible, with +A mythical python release, not required to be backward compatible, with telepathic interface. \index{__slots__} From loewis at users.sourceforge.net Sun Aug 21 15:03:25 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 21 Aug 2005 15:03:25 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.14,1.15 Message-ID: <20050821130325.289F51E4004@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21811 Modified Files: pep-0347.txt Log Message: Elaborate on admin access. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- pep-0347.txt 16 Aug 2005 18:17:00 -0000 1.14 +++ pep-0347.txt 21 Aug 2005 13:03:15 -0000 1.15 @@ -110,6 +110,27 @@ the SF account names, so that people can be better identified in log messages. +Administrator Access +-------------------- + +Administrator access to the pythondev account should be granted +to all current admins of the Python SF project. To distinguish +between shell login and svnserve login, admins need to maintain +two keys. Using OpenSSH, the following procedure can be +used to create a second key:: + + cd .ssh + ssh-keygen -t DSA -f pythondev -C @pythondev + vi config + +In the config file, the following lines need to be added:: + + Host pythondev + Hostname dinsdale.python.org + User pythondev + IdentityFile ~/.ssh/pythondev + +Then, shell login becomes possible through "ssh pythondev". Downloading the CVS Repository ------------------------------ @@ -201,7 +222,7 @@ breaks because it runs out of memory. The current SF project admins should get write access to the -authorized_keys file of the pythondev account. +authorized_keys2 file of the pythondev account. Disable CVS @@ -214,7 +235,7 @@ Discussion ----------- +========== Several alternatives had been suggested to the procedure above. The rejected alternatives are shortly discussed here: From loewis at users.sourceforge.net Sun Aug 21 15:26:46 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sun, 21 Aug 2005 15:26:46 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0347.txt,1.15,1.16 Message-ID: <20050821132646.CDA681E4004@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26912 Modified Files: pep-0347.txt Log Message: Update wush.net details. Index: pep-0347.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0347.txt,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- pep-0347.txt 21 Aug 2005 13:03:15 -0000 1.15 +++ pep-0347.txt 21 Aug 2005 13:26:34 -0000 1.16 @@ -279,7 +279,29 @@ * Greg Stein suggested http://www.wush.net/subversion.php. They offer 5 GB for $90/month, with 200 GB download/month. The data is on a RAID drive and fully backed up. Anonymous - access and email commit notifications are supported. + access and email commit notifications are supported. wush.net + elaborated the following details: + + - The machine would be a Virtuozzo Virtual Private Server (VPS), + hosted at PowerVPS. + + - The default repository URL would be http://python.wush.net/svn/projectname/, + but anything else could be arranged + + - we would get SSH login to the machine, with sudo capabilities. + + - They have a Web interface for management of the various SVN + repositories that we want to host, and to manage user accounts. + While svn+ssh would be supported, the user interface does not + yet support it. + + - For offsite mirroring/backup, they suggest to use rsync + instead of download of repository tarballs. + + Bob Ippolito reported that they had used wush.net for a + commercial project for about 6 months, after which time they + left wush.net, because the service was down for three days, + with nobody reachable, and no explanation when it came back. Copyright From birkenfeld at users.sourceforge.net Sun Aug 21 16:16:14 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sun, 21 Aug 2005 16:16:14 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_bz2.py,1.17,1.18 Message-ID: <20050821141614.D88061E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4264/Lib/test Modified Files: test_bz2.py Log Message: Fix BZ2File.(x)readlines() for files without a newline. Index: test_bz2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_bz2.py,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- test_bz2.py 3 Jun 2005 19:47:00 -0000 1.17 +++ test_bz2.py 21 Aug 2005 14:16:04 -0000 1.18 @@ -37,7 +37,7 @@ return bz2.decompress(data) class BZ2FileTest(BaseTest): - "Test MCRYPT type miscelaneous methods." + "Test BZ2File type miscellaneous methods." def setUp(self): self.filename = TESTFN @@ -245,6 +245,22 @@ self.assertEqual(f.tell(), len(self.DATA)) f.close() + def testBug1191043(self): + # readlines() for files containing no newline + data = 'BZh91AY&SY\xd9b\x89]\x00\x00\x00\x03\x80\x04\x00\x02\x00\x0c\x00 \x00!\x9ah3M\x13<]\xc9\x14\xe1BCe\x8a%t' + f = open(self.filename, "wb") + f.write(data) + f.close() + bz2f = BZ2File(self.filename) + lines = bz2f.readlines() + bz2f.close() + self.assertEqual(lines, ['Test']) + bz2f = BZ2File(self.filename) + xlines = bz2f.xreadlines() + bz2f.close() + self.assertEqual(lines, ['Test']) + + class BZ2CompressorTest(BaseTest): def testCompress(self): # "Test BZ2Compressor.compress()/flush()" From birkenfeld at users.sourceforge.net Sun Aug 21 16:16:15 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sun, 21 Aug 2005 16:16:15 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1335,1.1336 Message-ID: <20050821141615.0BB191E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4264/Misc Modified Files: NEWS Log Message: Fix BZ2File.(x)readlines() for files without a newline. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1335 retrieving revision 1.1336 diff -u -d -r1.1335 -r1.1336 --- NEWS 16 Aug 2005 03:47:51 -0000 1.1335 +++ NEWS 21 Aug 2005 14:16:03 -0000 1.1336 @@ -1570,6 +1570,9 @@ Extension modules ----------------- +- Fix bz2.BZ2File.(x)readlines() for files containing one line without + newlines. + - Added socket.getservbyport(), and make the second argument in getservbyname() and getservbyport() optional. From birkenfeld at users.sourceforge.net Sun Aug 21 16:16:15 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sun, 21 Aug 2005 16:16:15 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules bz2module.c,1.24,1.25 Message-ID: <20050821141615.14FC01E4006@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4264/Modules Modified Files: bz2module.c Log Message: Fix BZ2File.(x)readlines() for files without a newline. Index: bz2module.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/bz2module.c,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- bz2module.c 3 Jun 2005 19:47:00 -0000 1.24 +++ bz2module.c 21 Aug 2005 14:16:03 -0000 1.25 @@ -22,6 +22,18 @@ Gustavo Niemeyer \n\ "; +/* Our very own off_t-like type, 64-bit if possible */ +/* copied from Objects/fileobject.c */ +#if !defined(HAVE_LARGEFILE_SUPPORT) +typedef off_t Py_off_t; +#elif SIZEOF_OFF_T >= 8 +typedef off_t Py_off_t; +#elif SIZEOF_FPOS_T >= 8 +typedef fpos_t Py_off_t; +#else +#error "Large file support, but neither off_t nor fpos_t is large enough." +#endif + #define BUF(v) PyString_AS_STRING((PyStringObject *)v) #define MODE_CLOSED 0 @@ -405,7 +417,9 @@ Util_DropReadAhead(f); } if (f->mode == MODE_READ_EOF) { - return -1; + f->f_bufptr = f->f_buf; + f->f_bufend = f->f_buf; + return 0; } if ((f->f_buf = PyMem_Malloc(bufsize)) == NULL) { return -1; @@ -682,13 +696,13 @@ } totalread += nread; p = memchr(buffer+nfilled, '\n', nread); - if (p == NULL) { + if (!shortread && p == NULL) { /* Need a larger buffer to fit this line */ nfilled += nread; buffersize *= 2; if (buffersize > INT_MAX) { PyErr_SetString(PyExc_OverflowError, - "line is longer than a Python string can hold"); + "line is longer than a Python string can hold"); goto error; } if (big_buffer == NULL) { @@ -705,11 +719,11 @@ _PyString_Resize(&big_buffer, buffersize); buffer = PyString_AS_STRING(big_buffer); } - continue; + continue; } end = buffer+nfilled+nread; q = buffer; - do { + while (p != NULL) { /* Process complete lines */ p++; line = PyString_FromStringAndSize(q, p-q); @@ -721,7 +735,7 @@ goto error; q = p; p = memchr(q, '\n', end-q); - } while (p != NULL); + } /* Move the remaining incomplete line to the start */ nfilled = end-q; memmove(buffer, q, nfilled); @@ -962,7 +976,8 @@ BZ2File_seek(BZ2FileObject *self, PyObject *args) { int where = 0; - long offset; + PyObject *offobj; + Py_off_t offset; char small_buffer[SMALLCHUNK]; char *buffer = small_buffer; size_t buffersize = SMALLCHUNK; @@ -973,7 +988,15 @@ int rewind = 0; PyObject *ret = NULL; - if (!PyArg_ParseTuple(args, "l|i:seek", &offset, &where)) + if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &where)) + return NULL; +#if !defined(HAVE_LARGEFILE_SUPPORT) + offset = PyInt_AsLong(offobj); +#else + offset = PyLong_Check(offobj) ? + PyLong_AsLongLong(offobj) : PyInt_AsLong(offobj); +#endif + if (PyErr_Occurred()) return NULL; ACQUIRE_LOCK(self); From greg at users.sourceforge.net Sun Aug 21 20:46:11 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Sun, 21 Aug 2005 20:46:11 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew25.tex, 1.16, 1.17 Message-ID: <20050821184611.C41421E40E8@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32064/Doc/whatsnew Modified Files: whatsnew25.tex Log Message: [ sf.net patch # 1121611 ] A new hashlib module to replace the md5 and sha modules. It adds support for additional secure hashes such as SHA-256 and SHA-512. The hashlib module uses OpenSSL for fast platform optimized implementations of algorithms when available. The old md5 and sha modules still exist as wrappers around hashlib to preserve backwards compatibility. Index: whatsnew25.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew25.tex,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- whatsnew25.tex 2 Aug 2005 17:20:36 -0000 1.16 +++ whatsnew25.tex 21 Aug 2005 18:46:00 -0000 1.17 @@ -247,6 +247,15 @@ a different directory as the extraction target, and to unpack only a subset of the archive's members. (Contributed by Lars Gust\"abel.) +\item A new \module{hashlib} module has been added to replace the +\module{md5} and \module{sha} modules and adds support for additional +secure hashes such as SHA-256 and SHA-512. The \module{hashlib} module +uses OpenSSL for fast platform optimized implementations of algorithms +when available. The old \module{md5} and \module{sha} modules still +exist as wrappers around hashlib to preserve backwards compatibility. + +(Contributed by Gregory P. Smith.) + \end{itemize} From greg at users.sourceforge.net Sun Aug 21 20:46:11 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Sun, 21 Aug 2005 20:46:11 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib hashlib.py, NONE, 1.1 md5.py, NONE, 1.1 sha.py, NONE, 1.1 hmac.py, 1.8, 1.9 Message-ID: <20050821184611.E64811E40B4@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32064/Lib Modified Files: hmac.py Added Files: hashlib.py md5.py sha.py Log Message: [ sf.net patch # 1121611 ] A new hashlib module to replace the md5 and sha modules. It adds support for additional secure hashes such as SHA-256 and SHA-512. The hashlib module uses OpenSSL for fast platform optimized implementations of algorithms when available. The old md5 and sha modules still exist as wrappers around hashlib to preserve backwards compatibility. --- NEW FILE: hashlib.py --- # $Id: hashlib.py,v 1.1 2005/08/21 18:46:00 greg Exp $ # # Copyright (C) 2005 Gregory P. Smith (greg at electricrain.com) # Licensed to PSF under a Contributor Agreement. # __doc__ = """hashlib module - A common interface to many hash functions. new(name, string='') - returns a new hash object implementing the given hash function; initializing the hash using the given string data. Named constructor functions are also available, these are much faster than using new(): md5(), sha1(), sha224(), sha256(), sha384(), and sha512() More algorithms may be available on your platform but the above are guaranteed to exist. Choose your hash function wisely. Some have known weaknesses. sha384 and sha512 will be slow on 32 bit platforms. """ def __get_builtin_constructor(name): if name in ('SHA1', 'sha1'): import _sha return _sha.new elif name in ('MD5', 'md5'): import _md5 return _md5.new elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): import _sha256 bs = name[3:] if bs == '256': return _sha256.sha256 elif bs == '224': return _sha256.sha224 elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): import _sha512 bs = name[3:] if bs == '512': return _sha512.sha512 elif bs == '384': return _sha512.sha384 raise ValueError, "unsupported hash type" def __py_new(name, string=''): """new(name, string='') - Return a new hashing object using the named algorithm; optionally initialized with a string. """ return __get_builtin_constructor(name)(string) def __hash_new(name, string=''): """new(name, string='') - Return a new hashing object using the named algorithm; optionally initialized with a string. """ try: return _hashlib.new(name, string) except ValueError: # If the _hashlib module (OpenSSL) doesn't support the named # hash, try using our builtin implementations. # This allows for SHA224/256 and SHA384/512 support even though # the OpenSSL library prior to 0.9.8 doesn't provide them. return __get_builtin_constructor(name)(string) try: import _hashlib # use the wrapper of the C implementation new = __hash_new for opensslFuncName in filter(lambda n: n.startswith('openssl_'), dir(_hashlib)): funcName = opensslFuncName[len('openssl_'):] try: # try them all, some may not work due to the OpenSSL # version not supporting that algorithm. f = getattr(_hashlib, opensslFuncName) f() # Use the C function directly (very fast) exec funcName + ' = f' except ValueError: try: # Use the builtin implementation directly (fast) exec funcName + ' = __get_builtin_constructor(funcName)' except ValueError: # this one has no builtin implementation, don't define it pass # clean up our locals del f del opensslFuncName del funcName except ImportError: # We don't have the _hashlib OpenSSL module? # use the built in legacy interfaces via a wrapper function new = __py_new # lookup the C function to use directly for the named constructors md5 = __get_builtin_constructor('md5') sha1 = __get_builtin_constructor('sha1') sha224 = __get_builtin_constructor('sha224') sha256 = __get_builtin_constructor('sha256') sha384 = __get_builtin_constructor('sha384') sha512 = __get_builtin_constructor('sha512') --- NEW FILE: md5.py --- # $Id: md5.py,v 1.1 2005/08/21 18:46:00 greg Exp $ # # Copyright (C) 2005 Gregory P. Smith (greg at electricrain.com) # Licensed to PSF under a Contributor Agreement. from hashlib import md5 new = md5 blocksize = 1 # legacy value (wrong in any useful sense) digest_size = 16 --- NEW FILE: sha.py --- # $Id: sha.py,v 1.1 2005/08/21 18:46:00 greg Exp $ # # Copyright (C) 2005 Gregory P. Smith (greg at electricrain.com) # Licensed to PSF under a Contributor Agreement. from hashlib import sha1 as sha new = sha blocksize = 1 # legacy value (wrong in any useful sense) digest_size = 20 digestsize = 20 Index: hmac.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/hmac.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- hmac.py 20 Mar 2004 20:11:29 -0000 1.8 +++ hmac.py 21 Aug 2005 18:46:00 -0000 1.9 @@ -28,27 +28,33 @@ key: key for the keyed hash object. msg: Initial input for the hash, if provided. - digestmod: A module supporting PEP 247. Defaults to the md5 module. + digestmod: A module supporting PEP 247. *OR* + A hashlib constructor returning a new hash object. + Defaults to hashlib.md5. """ if key is _secret_backdoor_key: # cheap return if digestmod is None: - import md5 - digestmod = md5 + import hashlib + digestmod = hashlib.md5 - self.digestmod = digestmod - self.outer = digestmod.new() - self.inner = digestmod.new() - self.digest_size = digestmod.digest_size + if callable(digestmod): + self.digest_cons = digestmod + else: + self.digest_cons = lambda d='': digestmod.new(d) + + self.outer = self.digest_cons() + self.inner = self.digest_cons() + self.digest_size = self.inner.digest_size blocksize = 64 ipad = "\x36" * blocksize opad = "\x5C" * blocksize if len(key) > blocksize: - key = digestmod.new(key).digest() + key = self.digest_cons(key).digest() key = key + chr(0) * (blocksize - len(key)) self.outer.update(_strxor(key, opad)) @@ -70,7 +76,7 @@ An update to this copy won't affect the original object. """ other = HMAC(_secret_backdoor_key) - other.digestmod = self.digestmod + other.digest_cons = self.digest_cons other.digest_size = self.digest_size other.inner = self.inner.copy() other.outer = self.outer.copy() From greg at users.sourceforge.net Sun Aug 21 20:46:12 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Sun, 21 Aug 2005 20:46:12 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_hashlib.py, NONE, 1.1 test_hashlib_speed.py, NONE, 1.1 regrtest.py, 1.170, 1.171 test_hmac.py, 1.8, 1.9 Message-ID: <20050821184612.E336F1E416E@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32064/Lib/test Modified Files: regrtest.py test_hmac.py Added Files: test_hashlib.py test_hashlib_speed.py Log Message: [ sf.net patch # 1121611 ] A new hashlib module to replace the md5 and sha modules. It adds support for additional secure hashes such as SHA-256 and SHA-512. The hashlib module uses OpenSSL for fast platform optimized implementations of algorithms when available. The old md5 and sha modules still exist as wrappers around hashlib to preserve backwards compatibility. --- NEW FILE: test_hashlib.py --- # Test hashlib module # # $Id: test_hashlib.py,v 1.1 2005/08/21 18:46:01 greg Exp $ # # Copyright (C) 2005 Gregory P. Smith (greg at electricrain.com) # Licensed to PSF under a Contributor Agreement. # import hashlib import unittest from test import test_support def hexstr(s): import string h = string.hexdigits r = '' for c in s: i = ord(c) r = r + h[(i >> 4) & 0xF] + h[i & 0xF] return r class HashLibTestCase(unittest.TestCase): supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1', 'sha224', 'SHA224', 'sha256', 'SHA256', 'sha384', 'SHA384', 'sha512', 'SHA512' ) def test_unknown_hash(self): try: hashlib.new('spam spam spam spam spam') except ValueError: pass else: self.assert_(0 == "hashlib didn't reject bogus hash name") def test_hexdigest(self): for name in self.supported_hash_names: h = hashlib.new(name) self.assert_(hexstr(h.digest()) == h.hexdigest()) def test_large_update(self): aas = 'a' * 128 bees = 'b' * 127 cees = 'c' * 126 for name in self.supported_hash_names: m1 = hashlib.new(name) m1.update(aas) m1.update(bees) m1.update(cees) m2 = hashlib.new(name) m2.update(aas + bees + cees) self.assertEqual(m1.digest(), m2.digest()) def check(self, name, data, digest): # test the direct constructors computed = getattr(hashlib, name)(data).hexdigest() self.assert_(computed == digest) # test the general new() interface computed = hashlib.new(name, data).hexdigest() self.assert_(computed == digest) def test_case_md5_0(self): self.check('md5', '', 'd41d8cd98f00b204e9800998ecf8427e') def test_case_md5_1(self): self.check('md5', 'abc', '900150983cd24fb0d6963f7d28e17f72') def test_case_md5_2(self): self.check('md5', 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789', 'd174ab98d277d9f5a5611c2c9f419d9f') # use the three examples from Federal Information Processing Standards # Publication 180-1, Secure Hash Standard, 1995 April 17 # http://www.itl.nist.gov/div897/pubs/fip180-1.htm def test_case_sha1_0(self): self.check('sha1', "", "da39a3ee5e6b4b0d3255bfef95601890afd80709") def test_case_sha1_1(self): self.check('sha1', "abc", "a9993e364706816aba3e25717850c26c9cd0d89d") def test_case_sha1_2(self): self.check('sha1', "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1") def test_case_sha1_3(self): self.check('sha1', "a" * 1000000, "34aa973cd4c4daa4f61eeb2bdbad27316534016f") # use the examples from Federal Information Processing Standards # Publication 180-2, Secure Hash Standard, 2002 August 1 # http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf def test_case_sha224_0(self): self.check('sha224', "", "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f") def test_case_sha224_1(self): self.check('sha224', "abc", "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7") def test_case_sha224_2(self): self.check('sha224', "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525") def test_case_sha224_3(self): self.check('sha224', "a" * 1000000, "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67") def test_case_sha256_0(self): self.check('sha256', "", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855") def test_case_sha256_1(self): self.check('sha256', "abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") def test_case_sha256_2(self): self.check('sha256', "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1") def test_case_sha256_3(self): self.check('sha256', "a" * 1000000, "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0") def test_case_sha384_0(self): self.check('sha384', "", "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da"+ "274edebfe76f65fbd51ad2f14898b95b") def test_case_sha384_1(self): self.check('sha384', "abc", "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed"+ "8086072ba1e7cc2358baeca134c825a7") def test_case_sha384_2(self): self.check('sha384', "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712"+ "fcc7c71a557e2db966c3e9fa91746039") def test_case_sha384_3(self): self.check('sha384', "a" * 1000000, "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b"+ "07b8b3dc38ecc4ebae97ddd87f3d8985") def test_case_sha512_0(self): self.check('sha512', "", "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce"+ "47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e") def test_case_sha512_1(self): self.check('sha512', "abc", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"+ "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f") def test_case_sha512_2(self): self.check('sha512', "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"+ "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909") def test_case_sha512_3(self): self.check('sha512', "a" * 1000000, "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"+ "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b") def test_main(): test_support.run_unittest(HashLibTestCase) if __name__ == "__main__": test_main() --- NEW FILE: test_hashlib_speed.py --- import sys, time import hashlib from test import test_support def creatorFunc(): raise RuntimeError, "eek, creatorFunc not overridden" def test_scaled_msg(scale, name): iterations = 106201/scale * 20 longStr = 'Z'*scale localCF = creatorFunc start = time.time() for f in xrange(iterations): x = localCF(longStr).digest() end = time.time() print ('%2.2f' % (end-start)), "seconds", iterations, "x", len(longStr), "bytes", name def test_create(): start = time.time() for f in xrange(20000): d = creatorFunc() end = time.time() print ('%2.2f' % (end-start)), "seconds", '[20000 creations]' def test_zero(): start = time.time() for f in xrange(20000): x = creatorFunc().digest() end = time.time() print ('%2.2f' % (end-start)), "seconds", '[20000 "" digests]' ### this 'test' is not normally run. skip it if the test runner finds it if __name__ != '__main__': raise test_support.TestSkipped, "not a unit test (stand alone benchmark)" hName = sys.argv[1] # # setup our creatorFunc to test the requested hash # if hName in ('_md5', '_sha'): exec 'import '+hName exec 'creatorFunc = '+hName+'.new' print "testing speed of old", hName, "legacy interface" elif hName == '_hashlib' and len(sys.argv) > 3: import _hashlib exec 'creatorFunc = _hashlib.%s' % sys.argv[2] print "testing speed of _hashlib.%s" % sys.argv[2], getattr(_hashlib, sys.argv[2]) elif hName == '_hashlib' and len(sys.argv) == 3: import _hashlib exec 'creatorFunc = lambda x=_hashlib.new : x(%r)' % sys.argv[2] print "testing speed of _hashlib.new(%r)" % sys.argv[2] elif hasattr(hashlib, hName) and callable(getattr(hashlib, hName)): creatorFunc = getattr(hashlib, hName) print "testing speed of hashlib."+hName, getattr(hashlib, hName) else: exec "creatorFunc = lambda x=hashlib.new : x(%r)" % hName print "testing speed of hashlib.new(%r)" % hName try: test_create() except ValueError: print print "pass argument(s) naming the hash to run a speed test on:" print " '_md5' and '_sha' test the legacy builtin md5 and sha" print " '_hashlib' 'openssl_hName' 'fast' tests the builtin _hashlib" print " '_hashlib' 'hName' tests builtin _hashlib.new(shaFOO)" print " 'hName' tests the hashlib.hName() implementation if it exists" print " otherwise it uses hashlib.new(hName)." print raise test_zero() test_scaled_msg(scale=106201, name='[huge data]') test_scaled_msg(scale=10620, name='[large data]') test_scaled_msg(scale=1062, name='[medium data]') test_scaled_msg(scale=424, name='[4*small data]') test_scaled_msg(scale=336, name='[3*small data]') test_scaled_msg(scale=212, name='[2*small data]') test_scaled_msg(scale=106, name='[small data]') test_scaled_msg(scale=creatorFunc().digest_size, name='[digest_size data]') test_scaled_msg(scale=10, name='[tiny data]') Index: regrtest.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/regrtest.py,v retrieving revision 1.170 retrieving revision 1.171 diff -u -d -r1.170 -r1.171 --- regrtest.py 17 Jul 2005 02:37:00 -0000 1.170 +++ regrtest.py 21 Aug 2005 18:46:01 -0000 1.171 @@ -1090,6 +1090,9 @@ s = _expectations[sys.platform] self.expected = set(s.split()) + # this isn't a regularly run unit test, it is always skipped + self.expected.add('test_hashlib_speed') + if not os.path.supports_unicode_filenames: self.expected.add('test_pep277') Index: test_hmac.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_hmac.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- test_hmac.py 27 May 2003 16:16:41 -0000 1.8 +++ test_hmac.py 21 Aug 2005 18:46:01 -0000 1.9 @@ -105,9 +105,10 @@ def test_default_is_md5(self): # Testing if HMAC defaults to MD5 algorithm. - import md5 + # NOTE: this whitebox test depends on the hmac class internals + import hashlib h = hmac.HMAC("key") - self.failUnless(h.digestmod == md5) + self.failUnless(h.digest_cons == hashlib.md5) def test_exercise_all_methods(self): # Exercising all methods once. @@ -127,8 +128,8 @@ # Testing if attributes are of same type. h1 = hmac.HMAC("key") h2 = h1.copy() - self.failUnless(h1.digestmod == h2.digestmod, - "Modules don't match.") + self.failUnless(h1.digest_cons == h2.digest_cons, + "digest constructors don't match.") self.failUnless(type(h1.inner) == type(h2.inner), "Types of inner don't match.") self.failUnless(type(h1.outer) == type(h2.outer), From greg at users.sourceforge.net Sun Aug 21 20:46:13 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Sun, 21 Aug 2005 20:46:13 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules _hashopenssl.c, NONE, 2.1 sha256module.c, NONE, 2.1 sha512module.c, NONE, 2.1 md5module.c, 2.35, 2.36 shamodule.c, 2.22, 2.23 Message-ID: <20050821184613.A45C11E4288@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32064/Modules Modified Files: md5module.c shamodule.c Added Files: _hashopenssl.c sha256module.c sha512module.c Log Message: [ sf.net patch # 1121611 ] A new hashlib module to replace the md5 and sha modules. It adds support for additional secure hashes such as SHA-256 and SHA-512. The hashlib module uses OpenSSL for fast platform optimized implementations of algorithms when available. The old md5 and sha modules still exist as wrappers around hashlib to preserve backwards compatibility. --- NEW FILE: _hashopenssl.c --- /* Module that wraps all OpenSSL hash algorithms */ /* * Copyright (C) 2005 Gregory P. Smith (greg at electricrain.com) * Licensed to PSF under a Contributor Agreement. * * Derived from a skeleton of shamodule.c containing work performed by: * * Andrew Kuchling (amk at amk.ca) * Greg Stein (gstein at lyra.org) * */ #include "Python.h" #include "structmember.h" /* EVP is the preferred interface to hashing in OpenSSL */ #include typedef struct { PyObject_HEAD PyObject *name; /* name of this hash algorithm */ EVP_MD_CTX ctx; /* OpenSSL message digest context */ } EVPobject; static PyTypeObject EVPtype; #define DEFINE_CONSTS_FOR_NEW(Name) \ static PyObject *CONST_ ## Name ## _name_obj; \ static EVP_MD_CTX CONST_new_ ## Name ## _ctx; \ static EVP_MD_CTX *CONST_new_ ## Name ## _ctx_p = NULL; DEFINE_CONSTS_FOR_NEW(md5); DEFINE_CONSTS_FOR_NEW(sha1); DEFINE_CONSTS_FOR_NEW(sha224); DEFINE_CONSTS_FOR_NEW(sha256); DEFINE_CONSTS_FOR_NEW(sha384); DEFINE_CONSTS_FOR_NEW(sha512); static EVPobject * newEVPobject(PyObject *name) { EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, &EVPtype); /* save the name for .name to return */ if (retval != NULL) { Py_INCREF(name); retval->name = name; } return retval; } /* Internal methods for a hash object */ static void EVP_dealloc(PyObject *ptr) { EVP_MD_CTX_cleanup(&((EVPobject *)ptr)->ctx); Py_XDECREF(((EVPobject *)ptr)->name); PyObject_Del(ptr); } /* External methods for a hash object */ PyDoc_STRVAR(EVP_copy__doc__, "Return a copy of the hash object."); static PyObject * EVP_copy(EVPobject *self, PyObject *args) { EVPobject *newobj; if (!PyArg_ParseTuple(args, ":copy")) return NULL; if ( (newobj = newEVPobject(self->name))==NULL) return NULL; EVP_MD_CTX_copy(&newobj->ctx, &self->ctx); return (PyObject *)newobj; } PyDoc_STRVAR(EVP_digest__doc__, "Return the digest value as a string of binary data."); static PyObject * EVP_digest(EVPobject *self, PyObject *args) { unsigned char digest[EVP_MAX_MD_SIZE]; EVP_MD_CTX temp_ctx; PyObject *retval; unsigned int digest_size; if (!PyArg_ParseTuple(args, ":digest")) return NULL; EVP_MD_CTX_copy(&temp_ctx, &self->ctx); digest_size = EVP_MD_CTX_size(&temp_ctx); EVP_DigestFinal(&temp_ctx, (char *)digest, NULL); retval = PyString_FromStringAndSize((const char *)digest, digest_size); EVP_MD_CTX_cleanup(&temp_ctx); return retval; } PyDoc_STRVAR(EVP_hexdigest__doc__, "Return the digest value as a string of hexadecimal digits."); static PyObject * EVP_hexdigest(EVPobject *self, PyObject *args) { unsigned char digest[EVP_MAX_MD_SIZE]; EVP_MD_CTX temp_ctx; PyObject *retval; char *hex_digest; unsigned int i, j, digest_size; if (!PyArg_ParseTuple(args, ":hexdigest")) return NULL; /* Get the raw (binary) digest value */ EVP_MD_CTX_copy(&temp_ctx, &self->ctx); digest_size = EVP_MD_CTX_size(&temp_ctx); EVP_DigestFinal(&temp_ctx, digest, NULL); EVP_MD_CTX_cleanup(&temp_ctx); /* Create a new string */ /* NOTE: not thread safe! modifying an already created string object */ /* (not a problem because we hold the GIL by default) */ retval = PyString_FromStringAndSize(NULL, digest_size * 2); if (!retval) return NULL; hex_digest = PyString_AsString(retval); if (!hex_digest) { Py_DECREF(retval); return NULL; } /* Make hex version of the digest */ for(i=j=0; i> 4) & 0xf; c = (c>9) ? c+'a'-10 : c + '0'; hex_digest[j++] = c; c = (digest[i] & 0xf); c = (c>9) ? c+'a'-10 : c + '0'; hex_digest[j++] = c; } return retval; } PyDoc_STRVAR(EVP_update__doc__, "Update this hash object's state with the provided string."); static PyObject * EVP_update(EVPobject *self, PyObject *args) { unsigned char *cp; int len; if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) return NULL; EVP_DigestUpdate(&self->ctx, cp, len); Py_INCREF(Py_None); return Py_None; } static PyMethodDef EVP_methods[] = { {"update", (PyCFunction)EVP_update, METH_VARARGS, EVP_update__doc__}, {"digest", (PyCFunction)EVP_digest, METH_VARARGS, EVP_digest__doc__}, {"hexdigest", (PyCFunction)EVP_hexdigest, METH_VARARGS, EVP_hexdigest__doc__}, {"copy", (PyCFunction)EVP_copy, METH_VARARGS, EVP_copy__doc__}, {NULL, NULL} /* sentinel */ }; static PyObject * EVP_get_block_size(EVPobject *self, void *closure) { return PyInt_FromLong(EVP_MD_CTX_block_size(&((EVPobject *)self)->ctx)); } static PyObject * EVP_get_digest_size(EVPobject *self, void *closure) { return PyInt_FromLong(EVP_MD_CTX_size(&((EVPobject *)self)->ctx)); } static PyMemberDef EVP_members[] = { {"name", T_OBJECT, offsetof(EVPobject, name), READONLY, PyDoc_STR("algorithm name.")}, {NULL} /* Sentinel */ }; static PyGetSetDef EVP_getseters[] = { {"digest_size", (getter)EVP_get_digest_size, NULL, NULL, NULL}, {"block_size", (getter)EVP_get_block_size, NULL, NULL, NULL}, /* the old md5 and sha modules support 'digest_size' as in PEP 247. * the old sha module also supported 'digestsize'. ugh. */ {"digestsize", (getter)EVP_get_digest_size, NULL, NULL, NULL}, {NULL} /* Sentinel */ }; static PyObject * EVP_repr(PyObject *self) { char buf[100]; PyOS_snprintf(buf, sizeof(buf), "<%s HASH object @ %p>", PyString_AsString(((EVPobject *)self)->name), self); return PyString_FromString(buf); } #if HASH_OBJ_CONSTRUCTOR static int EVP_tp_init(EVPobject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"name", "string", NULL}; PyObject *name_obj = NULL; char *nameStr; unsigned char *cp = NULL; unsigned int len; const EVP_MD *digest; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s#:HASH", kwlist, &name_obj, &cp, &len)) { return -1; } if (!PyArg_Parse(name_obj, "s", &nameStr)) { PyErr_SetString(PyExc_TypeError, "name must be a string"); return -1; } digest = EVP_get_digestbyname(nameStr); if (!digest) { PyErr_SetString(PyExc_ValueError, "unknown hash function"); return -1; } EVP_DigestInit(&self->ctx, digest); self->name = name_obj; Py_INCREF(self->name); if (cp && len) EVP_DigestUpdate(&self->ctx, cp, len); return 0; } #endif PyDoc_STRVAR(hashtype_doc, "A hash represents the object used to calculate a checksum of a\n\ string of information.\n\ \n\ Methods:\n\ \n\ update() -- updates the current digest with an additional string\n\ digest() -- return the current digest value\n\ hexdigest() -- return the current digest as a string of hexadecimal digits\n\ copy() -- return a copy of the current hash object\n\ \n\ Attributes:\n\ \n\ name -- the hash algorithm being used by this object\n\ digest_size -- number of bytes in this hashes output\n"); static PyTypeObject EVPtype = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "_hashlib.HASH", /*tp_name*/ sizeof(EVPobject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ EVP_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ EVP_repr, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ hashtype_doc, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ EVP_methods, /* tp_methods */ EVP_members, /* tp_members */ EVP_getseters, /* tp_getset */ #if 1 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ #endif #if HASH_OBJ_CONSTRUCTOR (initproc)EVP_tp_init, /* tp_init */ #endif }; static PyObject * EVPnew(PyObject *name_obj, const EVP_MD *digest, const EVP_MD_CTX *initial_ctx, const char *cp, unsigned int len) { EVPobject *self; if (!digest && !initial_ctx) { PyErr_SetString(PyExc_ValueError, "unsupported hash type"); return NULL; } if ((self = newEVPobject(name_obj)) == NULL) return NULL; if (initial_ctx) { EVP_MD_CTX_copy(&self->ctx, initial_ctx); } else { EVP_DigestInit(&self->ctx, digest); } if (cp && len) EVP_DigestUpdate(&self->ctx, cp, len); return (PyObject *)self; } /* The module-level function: new() */ PyDoc_STRVAR(EVP_new__doc__, "Return a new hash object using the named algorithm.\n\ An optional string argument may be provided and will be\n\ automatically hashed.\n\ \n\ The MD5 and SHA1 algorithms are always supported.\n"); static PyObject * EVP_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"name", "string", NULL}; PyObject *name_obj = NULL; char *name; const EVP_MD *digest; unsigned char *cp = NULL; unsigned int len; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O|s#:new", kwlist, &name_obj, &cp, &len)) { return NULL; } if (!PyArg_Parse(name_obj, "s", &name)) { PyErr_SetString(PyExc_TypeError, "name must be a string"); return NULL; } digest = EVP_get_digestbyname(name); return EVPnew(name_obj, digest, NULL, cp, len); } /* * This macro generates constructor function definitions for specific * hash algorithms. These constructors are much faster than calling * the generic one passing it a python string and are noticably * faster than calling a python new() wrapper. Thats important for * code that wants to make hashes of a bunch of small strings. */ #define GEN_CONSTRUCTOR(NAME) \ static PyObject * \ EVP_new_ ## NAME (PyObject *self, PyObject *args) \ { \ unsigned char *cp = NULL; \ unsigned int len; \ \ if (!PyArg_ParseTuple(args, "|s#:" #NAME , &cp, &len)) { \ return NULL; \ } \ \ return EVPnew( \ CONST_ ## NAME ## _name_obj, \ NULL, \ CONST_new_ ## NAME ## _ctx_p, \ cp, len); \ } /* a PyMethodDef structure for the constructor */ #define CONSTRUCTOR_METH_DEF(NAME) \ {"openssl_" #NAME, (PyCFunction)EVP_new_ ## NAME, METH_VARARGS, \ PyDoc_STR("Returns a " #NAME \ " hash object; optionally initialized with a string") \ } /* used in the init function to setup a constructor */ #define INIT_CONSTRUCTOR_CONSTANTS(NAME) do { \ CONST_ ## NAME ## _name_obj = PyString_FromString(#NAME); \ if (EVP_get_digestbyname(#NAME)) { \ CONST_new_ ## NAME ## _ctx_p = &CONST_new_ ## NAME ## _ctx; \ EVP_DigestInit(CONST_new_ ## NAME ## _ctx_p, EVP_get_digestbyname(#NAME)); \ } \ } while (0); GEN_CONSTRUCTOR(md5) GEN_CONSTRUCTOR(sha1) GEN_CONSTRUCTOR(sha224) GEN_CONSTRUCTOR(sha256) GEN_CONSTRUCTOR(sha384) GEN_CONSTRUCTOR(sha512) /* List of functions exported by this module */ static struct PyMethodDef EVP_functions[] = { {"new", (PyCFunction)EVP_new, METH_VARARGS|METH_KEYWORDS, EVP_new__doc__}, CONSTRUCTOR_METH_DEF(md5), CONSTRUCTOR_METH_DEF(sha1), CONSTRUCTOR_METH_DEF(sha224), CONSTRUCTOR_METH_DEF(sha256), CONSTRUCTOR_METH_DEF(sha384), CONSTRUCTOR_METH_DEF(sha512), {NULL, NULL} /* Sentinel */ }; /* Initialize this module. */ PyMODINIT_FUNC init_hashlib(void) { PyObject *m; OpenSSL_add_all_digests(); /* TODO build EVP_functions openssl_* entries dynamically based * on what hashes are supported rather than listing many * but having some be unsupported. Only init appropriate * constants. */ EVPtype.ob_type = &PyType_Type; if (PyType_Ready(&EVPtype) < 0) return; m = Py_InitModule("_hashlib", EVP_functions); if (m == NULL) return; #if HASH_OBJ_CONSTRUCTOR Py_INCREF(&EVPtype); PyModule_AddObject(m, "HASH", (PyObject *)&EVPtype); #endif /* these constants are used by the convenience constructors */ INIT_CONSTRUCTOR_CONSTANTS(md5); INIT_CONSTRUCTOR_CONSTANTS(sha1); INIT_CONSTRUCTOR_CONSTANTS(sha224); INIT_CONSTRUCTOR_CONSTANTS(sha256); INIT_CONSTRUCTOR_CONSTANTS(sha384); INIT_CONSTRUCTOR_CONSTANTS(sha512); } --- NEW FILE: sha256module.c --- /* SHA256 module */ /* This module provides an interface to NIST's SHA-256 and SHA-224 Algorithms */ /* See below for information about the original code this module was based upon. Additional work performed by: Andrew Kuchling (amk at amk.ca) Greg Stein (gstein at lyra.org) Trevor Perrin (trevp at trevp.net) Copyright (C) 2005 Gregory P. Smith (greg at electricrain.com) Licensed to PSF under a Contributor Agreement. */ /* SHA objects */ #include "Python.h" #include "structmember.h" /* Endianness testing and definitions */ #define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\ if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;} #define PCT_LITTLE_ENDIAN 1 #define PCT_BIG_ENDIAN 0 /* Some useful types */ typedef unsigned char SHA_BYTE; #if SIZEOF_INT == 4 typedef unsigned int SHA_INT32; /* 32-bit integer */ #else /* not defined. compilation will die. */ #endif /* The SHA block size and message digest sizes, in bytes */ #define SHA_BLOCKSIZE 64 #define SHA_DIGESTSIZE 32 /* The structure for storing SHA info */ typedef struct { PyObject_HEAD SHA_INT32 digest[8]; /* Message digest */ SHA_INT32 count_lo, count_hi; /* 64-bit bit count */ SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ int Endianness; int local; /* unprocessed amount in data */ int digestsize; } SHAobject; /* When run on a little-endian CPU we need to perform byte reversal on an array of longwords. */ static void longReverse(SHA_INT32 *buffer, int byteCount, int Endianness) { SHA_INT32 value; if ( Endianness == PCT_BIG_ENDIAN ) return; byteCount /= sizeof(*buffer); while (byteCount--) { value = *buffer; value = ( ( value & 0xFF00FF00L ) >> 8 ) | \ ( ( value & 0x00FF00FFL ) << 8 ); *buffer++ = ( value << 16 ) | ( value >> 16 ); } } static void SHAcopy(SHAobject *src, SHAobject *dest) { dest->Endianness = src->Endianness; dest->local = src->local; dest->digestsize = src->digestsize; dest->count_lo = src->count_lo; dest->count_hi = src->count_hi; memcpy(dest->digest, src->digest, sizeof(src->digest)); memcpy(dest->data, src->data, sizeof(src->data)); } /* ------------------------------------------------------------------------ * * This code for the SHA-256 algorithm was noted as public domain. The * original headers are pasted below. * * Several changes have been made to make it more compatible with the * Python environment and desired interface. * */ /* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * gurantee it works. * * Tom St Denis, tomstdenis at iahu.ca, http://libtomcrypt.org */ /* SHA256 by Tom St Denis */ /* Various logical functions */ #define ROR(x, y)\ ( ((((unsigned long)(x)&0xFFFFFFFFUL)>>(unsigned long)((y)&31)) | \ ((unsigned long)(x)<<(unsigned long)(32-((y)&31)))) & 0xFFFFFFFFUL) #define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Maj(x,y,z) (((x | y) & z) | (x & y)) #define S(x, n) ROR((x),(n)) #define R(x, n) (((x)&0xFFFFFFFFUL)>>(n)) #define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22)) #define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25)) #define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3)) #define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10)) static void sha_transform(SHAobject *sha_info) { int i; SHA_INT32 S[8], W[64], t0, t1; memcpy(W, sha_info->data, sizeof(sha_info->data)); longReverse(W, (int)sizeof(sha_info->data), sha_info->Endianness); for (i = 16; i < 64; ++i) { W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; } for (i = 0; i < 8; ++i) { S[i] = sha_info->digest[i]; } /* Compress */ #define RND(a,b,c,d,e,f,g,h,i,ki) \ t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ t1 = Sigma0(a) + Maj(a, b, c); \ d += t0; \ h = t0 + t1; RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x71374491); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcf); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba5); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25b); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b01); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a7); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c1); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc6); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dc); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c8); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf3); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x14292967); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a85); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b2138); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d13); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a7354); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c85); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a1); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664b); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a3); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd6990624); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e3585); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa070); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c08); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774c); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4a); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc70208); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506ceb); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2); #undef RND /* feedback */ for (i = 0; i < 8; i++) { sha_info->digest[i] = sha_info->digest[i] + S[i]; } } /* initialize the SHA digest */ static void sha_init(SHAobject *sha_info) { TestEndianness(sha_info->Endianness) sha_info->digest[0] = 0x6A09E667L; sha_info->digest[1] = 0xBB67AE85L; sha_info->digest[2] = 0x3C6EF372L; sha_info->digest[3] = 0xA54FF53AL; sha_info->digest[4] = 0x510E527FL; sha_info->digest[5] = 0x9B05688CL; sha_info->digest[6] = 0x1F83D9ABL; sha_info->digest[7] = 0x5BE0CD19L; sha_info->count_lo = 0L; sha_info->count_hi = 0L; sha_info->local = 0; sha_info->digestsize = 32; } static void sha224_init(SHAobject *sha_info) { TestEndianness(sha_info->Endianness) sha_info->digest[0] = 0xc1059ed8L; sha_info->digest[1] = 0x367cd507L; sha_info->digest[2] = 0x3070dd17L; sha_info->digest[3] = 0xf70e5939L; sha_info->digest[4] = 0xffc00b31L; sha_info->digest[5] = 0x68581511L; sha_info->digest[6] = 0x64f98fa7L; sha_info->digest[7] = 0xbefa4fa4L; sha_info->count_lo = 0L; sha_info->count_hi = 0L; sha_info->local = 0; sha_info->digestsize = 28; } /* update the SHA digest */ static void sha_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) { int i; SHA_INT32 clo; clo = sha_info->count_lo + ((SHA_INT32) count << 3); if (clo < sha_info->count_lo) { ++sha_info->count_hi; } sha_info->count_lo = clo; sha_info->count_hi += (SHA_INT32) count >> 29; if (sha_info->local) { i = SHA_BLOCKSIZE - sha_info->local; if (i > count) { i = count; } memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); count -= i; buffer += i; sha_info->local += i; if (sha_info->local == SHA_BLOCKSIZE) { sha_transform(sha_info); } else { return; } } while (count >= SHA_BLOCKSIZE) { memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); buffer += SHA_BLOCKSIZE; count -= SHA_BLOCKSIZE; sha_transform(sha_info); } memcpy(sha_info->data, buffer, count); sha_info->local = count; } /* finish computing the SHA digest */ static void sha_final(unsigned char digest[SHA_DIGESTSIZE], SHAobject *sha_info) { int count; SHA_INT32 lo_bit_count, hi_bit_count; lo_bit_count = sha_info->count_lo; hi_bit_count = sha_info->count_hi; count = (int) ((lo_bit_count >> 3) & 0x3f); ((SHA_BYTE *) sha_info->data)[count++] = 0x80; if (count > SHA_BLOCKSIZE - 8) { memset(((SHA_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count); sha_transform(sha_info); memset((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8); } else { memset(((SHA_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - 8 - count); } /* GJS: note that we add the hi/lo in big-endian. sha_transform will swap these values into host-order. */ sha_info->data[56] = (hi_bit_count >> 24) & 0xff; sha_info->data[57] = (hi_bit_count >> 16) & 0xff; sha_info->data[58] = (hi_bit_count >> 8) & 0xff; sha_info->data[59] = (hi_bit_count >> 0) & 0xff; sha_info->data[60] = (lo_bit_count >> 24) & 0xff; sha_info->data[61] = (lo_bit_count >> 16) & 0xff; sha_info->data[62] = (lo_bit_count >> 8) & 0xff; sha_info->data[63] = (lo_bit_count >> 0) & 0xff; sha_transform(sha_info); digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); digest[ 3] = (unsigned char) ((sha_info->digest[0] ) & 0xff); digest[ 4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); digest[ 5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); digest[ 6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); digest[ 7] = (unsigned char) ((sha_info->digest[1] ) & 0xff); digest[ 8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); digest[ 9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); digest[11] = (unsigned char) ((sha_info->digest[2] ) & 0xff); digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); digest[15] = (unsigned char) ((sha_info->digest[3] ) & 0xff); digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); digest[19] = (unsigned char) ((sha_info->digest[4] ) & 0xff); digest[20] = (unsigned char) ((sha_info->digest[5] >> 24) & 0xff); digest[21] = (unsigned char) ((sha_info->digest[5] >> 16) & 0xff); digest[22] = (unsigned char) ((sha_info->digest[5] >> 8) & 0xff); digest[23] = (unsigned char) ((sha_info->digest[5] ) & 0xff); digest[24] = (unsigned char) ((sha_info->digest[6] >> 24) & 0xff); digest[25] = (unsigned char) ((sha_info->digest[6] >> 16) & 0xff); digest[26] = (unsigned char) ((sha_info->digest[6] >> 8) & 0xff); digest[27] = (unsigned char) ((sha_info->digest[6] ) & 0xff); digest[28] = (unsigned char) ((sha_info->digest[7] >> 24) & 0xff); digest[29] = (unsigned char) ((sha_info->digest[7] >> 16) & 0xff); digest[30] = (unsigned char) ((sha_info->digest[7] >> 8) & 0xff); digest[31] = (unsigned char) ((sha_info->digest[7] ) & 0xff); } /* * End of copied SHA code. * * ------------------------------------------------------------------------ */ static PyTypeObject SHA224type; static PyTypeObject SHA256type; static SHAobject * newSHA224object(void) { return (SHAobject *)PyObject_New(SHAobject, &SHA224type); } static SHAobject * newSHA256object(void) { return (SHAobject *)PyObject_New(SHAobject, &SHA256type); } /* Internal methods for a hash object */ static void SHA_dealloc(PyObject *ptr) { PyObject_Del(ptr); } /* External methods for a hash object */ PyDoc_STRVAR(SHA256_copy__doc__, "Return a copy of the hash object."); static PyObject * SHA256_copy(SHAobject *self, PyObject *args) { SHAobject *newobj; if (!PyArg_ParseTuple(args, ":copy")) { return NULL; } if (((PyObject*)self)->ob_type == &SHA256type) { if ( (newobj = newSHA256object())==NULL) return NULL; } else { if ( (newobj = newSHA224object())==NULL) return NULL; } SHAcopy(self, newobj); return (PyObject *)newobj; } PyDoc_STRVAR(SHA256_digest__doc__, "Return the digest value as a string of binary data."); static PyObject * SHA256_digest(SHAobject *self, PyObject *args) { unsigned char digest[SHA_DIGESTSIZE]; SHAobject temp; if (!PyArg_ParseTuple(args, ":digest")) return NULL; SHAcopy(self, &temp); sha_final(digest, &temp); return PyString_FromStringAndSize((const char *)digest, self->digestsize); } PyDoc_STRVAR(SHA256_hexdigest__doc__, "Return the digest value as a string of hexadecimal digits."); static PyObject * SHA256_hexdigest(SHAobject *self, PyObject *args) { unsigned char digest[SHA_DIGESTSIZE]; SHAobject temp; PyObject *retval; char *hex_digest; int i, j; if (!PyArg_ParseTuple(args, ":hexdigest")) return NULL; /* Get the raw (binary) digest value */ SHAcopy(self, &temp); sha_final(digest, &temp); /* Create a new string */ retval = PyString_FromStringAndSize(NULL, self->digestsize * 2); if (!retval) return NULL; hex_digest = PyString_AsString(retval); if (!hex_digest) { Py_DECREF(retval); return NULL; } /* Make hex version of the digest */ for(i=j=0; idigestsize; i++) { char c; c = (digest[i] >> 4) & 0xf; c = (c>9) ? c+'a'-10 : c + '0'; hex_digest[j++] = c; c = (digest[i] & 0xf); c = (c>9) ? c+'a'-10 : c + '0'; hex_digest[j++] = c; } return retval; } PyDoc_STRVAR(SHA256_update__doc__, "Update this hash object's state with the provided string."); static PyObject * SHA256_update(SHAobject *self, PyObject *args) { unsigned char *cp; int len; if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) return NULL; sha_update(self, cp, len); Py_INCREF(Py_None); return Py_None; } static PyMethodDef SHA_methods[] = { {"copy", (PyCFunction)SHA256_copy, METH_VARARGS, SHA256_copy__doc__}, {"digest", (PyCFunction)SHA256_digest, METH_VARARGS, SHA256_digest__doc__}, {"hexdigest", (PyCFunction)SHA256_hexdigest, METH_VARARGS, SHA256_hexdigest__doc__}, {"update", (PyCFunction)SHA256_update, METH_VARARGS, SHA256_update__doc__}, {NULL, NULL} /* sentinel */ }; static PyObject * SHA256_get_block_size(PyObject *self, void *closure) { return PyInt_FromLong(SHA_BLOCKSIZE); } static PyObject * SHA256_get_name(PyObject *self, void *closure) { if (((SHAobject *)self)->digestsize == 32) return PyString_FromStringAndSize("SHA256", 6); else return PyString_FromStringAndSize("SHA224", 6); } static PyGetSetDef SHA_getseters[] = { {"block_size", (getter)SHA256_get_block_size, NULL, NULL, NULL}, {"name", (getter)SHA256_get_name, NULL, NULL, NULL}, {NULL} /* Sentinel */ }; static PyMemberDef SHA_members[] = { {"digest_size", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, /* the old md5 and sha modules support 'digest_size' as in PEP 247. * the old sha module also supported 'digestsize'. ugh. */ {"digestsize", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, {NULL} /* Sentinel */ }; static PyTypeObject SHA224type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "_sha256.sha224", /*tp_name*/ sizeof(SHAobject), /*tp_size*/ 0, /*tp_itemsize*/ /* methods */ SHA_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ SHA_methods, /* tp_methods */ SHA_members, /* tp_members */ SHA_getseters, /* tp_getset */ }; static PyTypeObject SHA256type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "_sha256.sha256", /*tp_name*/ sizeof(SHAobject), /*tp_size*/ 0, /*tp_itemsize*/ /* methods */ SHA_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ SHA_methods, /* tp_methods */ SHA_members, /* tp_members */ SHA_getseters, /* tp_getset */ }; /* The single module-level function: new() */ PyDoc_STRVAR(SHA256_new__doc__, "Return a new SHA-256 hash object; optionally initialized with a string."); static PyObject * SHA256_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; SHAobject *new; unsigned char *cp = NULL; int len; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, &cp, &len)) { return NULL; } if ((new = newSHA256object()) == NULL) return NULL; sha_init(new); if (PyErr_Occurred()) { Py_DECREF(new); return NULL; } if (cp) sha_update(new, cp, len); return (PyObject *)new; } PyDoc_STRVAR(SHA224_new__doc__, "Return a new SHA-224 hash object; optionally initialized with a string."); static PyObject * SHA224_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; SHAobject *new; unsigned char *cp = NULL; int len; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, &cp, &len)) { return NULL; } if ((new = newSHA224object()) == NULL) return NULL; sha224_init(new); if (PyErr_Occurred()) { Py_DECREF(new); return NULL; } if (cp) sha_update(new, cp, len); return (PyObject *)new; } /* List of functions exported by this module */ static struct PyMethodDef SHA_functions[] = { {"sha256", (PyCFunction)SHA256_new, METH_VARARGS|METH_KEYWORDS, SHA256_new__doc__}, {"sha224", (PyCFunction)SHA224_new, METH_VARARGS|METH_KEYWORDS, SHA224_new__doc__}, {NULL, NULL} /* Sentinel */ }; /* Initialize this module. */ #define insint(n,v) { PyModule_AddIntConstant(m,n,v); } PyMODINIT_FUNC init_sha256(void) { PyObject *m; SHA224type.ob_type = &PyType_Type; if (PyType_Ready(&SHA224type) < 0) return; SHA256type.ob_type = &PyType_Type; if (PyType_Ready(&SHA256type) < 0) return; m = Py_InitModule("_sha256", SHA_functions); } --- NEW FILE: sha512module.c --- /* SHA512 module */ /* This module provides an interface to NIST's SHA-512 and SHA-384 Algorithms */ /* See below for information about the original code this module was based upon. Additional work performed by: Andrew Kuchling (amk at amk.ca) Greg Stein (gstein at lyra.org) Trevor Perrin (trevp at trevp.net) Copyright (C) 2005 Gregory P. Smith (greg at electricrain.com) Licensed to PSF under a Contributor Agreement. */ /* SHA objects */ #include "Python.h" #include "structmember.h" #ifdef PY_LONG_LONG /* If no PY_LONG_LONG, don't compile anything! */ /* Endianness testing and definitions */ #define TestEndianness(variable) {int i=1; variable=PCT_BIG_ENDIAN;\ if (*((char*)&i)==1) variable=PCT_LITTLE_ENDIAN;} #define PCT_LITTLE_ENDIAN 1 #define PCT_BIG_ENDIAN 0 /* Some useful types */ typedef unsigned char SHA_BYTE; #if SIZEOF_INT == 4 typedef unsigned int SHA_INT32; /* 32-bit integer */ typedef unsigned PY_LONG_LONG SHA_INT64; /* 64-bit integer */ #else /* not defined. compilation will die. */ #endif /* The SHA block size and message digest sizes, in bytes */ #define SHA_BLOCKSIZE 128 #define SHA_DIGESTSIZE 64 /* The structure for storing SHA info */ typedef struct { PyObject_HEAD SHA_INT64 digest[8]; /* Message digest */ SHA_INT32 count_lo, count_hi; /* 64-bit bit count */ SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ int Endianness; int local; /* unprocessed amount in data */ int digestsize; } SHAobject; /* When run on a little-endian CPU we need to perform byte reversal on an array of longwords. */ static void longReverse(SHA_INT64 *buffer, int byteCount, int Endianness) { SHA_INT64 value; if ( Endianness == PCT_BIG_ENDIAN ) return; byteCount /= sizeof(*buffer); while (byteCount--) { value = *buffer; ((unsigned char*)buffer)[0] = (unsigned char)(value >> 56) & 0xff; ((unsigned char*)buffer)[1] = (unsigned char)(value >> 48) & 0xff; ((unsigned char*)buffer)[2] = (unsigned char)(value >> 40) & 0xff; ((unsigned char*)buffer)[3] = (unsigned char)(value >> 32) & 0xff; ((unsigned char*)buffer)[4] = (unsigned char)(value >> 24) & 0xff; ((unsigned char*)buffer)[5] = (unsigned char)(value >> 16) & 0xff; ((unsigned char*)buffer)[6] = (unsigned char)(value >> 8) & 0xff; ((unsigned char*)buffer)[7] = (unsigned char)(value ) & 0xff; buffer++; } } static void SHAcopy(SHAobject *src, SHAobject *dest) { dest->Endianness = src->Endianness; dest->local = src->local; dest->digestsize = src->digestsize; dest->count_lo = src->count_lo; dest->count_hi = src->count_hi; memcpy(dest->digest, src->digest, sizeof(src->digest)); memcpy(dest->data, src->data, sizeof(src->data)); } /* ------------------------------------------------------------------------ * * This code for the SHA-512 algorithm was noted as public domain. The * original headers are pasted below. * * Several changes have been made to make it more compatible with the * Python environment and desired interface. * */ /* LibTomCrypt, modular cryptographic library -- Tom St Denis * * LibTomCrypt is a library that provides various cryptographic * algorithms in a highly modular and flexible manner. * * The library is free for all purposes without any express * gurantee it works. * * Tom St Denis, tomstdenis at iahu.ca, http://libtomcrypt.org */ /* SHA512 by Tom St Denis */ /* Various logical functions */ #define ROR64(x, y) \ ( ((((x) & 0xFFFFFFFFFFFFFFFFULL)>>((unsigned PY_LONG_LONG)(y) & 63)) | \ ((x)<<((unsigned PY_LONG_LONG)(64-((y) & 63))))) & 0xFFFFFFFFFFFFFFFFULL) #define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Maj(x,y,z) (((x | y) & z) | (x & y)) #define S(x, n) ROR64((x),(n)) #define R(x, n) (((x) & 0xFFFFFFFFFFFFFFFFULL) >> ((unsigned PY_LONG_LONG)n)) #define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) #define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) #define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) #define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) static void sha512_transform(SHAobject *sha_info) { int i; SHA_INT64 S[8], W[80], t0, t1; memcpy(W, sha_info->data, sizeof(sha_info->data)); longReverse(W, (int)sizeof(sha_info->data), sha_info->Endianness); for (i = 16; i < 80; ++i) { W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; } for (i = 0; i < 8; ++i) { S[i] = sha_info->digest[i]; } /* Compress */ #define RND(a,b,c,d,e,f,g,h,i,ki) \ t0 = h + Sigma1(e) + Ch(e, f, g) + ki + W[i]; \ t1 = Sigma0(a) + Maj(a, b, c); \ d += t0; \ h = t0 + t1; RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98d728ae22ULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x7137449123ef65cdULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcfec4d3b2fULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba58189dbbcULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25bf348b538ULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1b605d019ULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4af194f9bULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5da6d8118ULL); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98a3030242ULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b0145706fbeULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be4ee4b28cULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3d5ffb4e2ULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74f27b896fULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe3b1696b1ULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a725c71235ULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174cf692694ULL); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c19ef14ad2ULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786384f25e3ULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc68b8cd5b5ULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc77ac9c65ULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f592b0275ULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa6ea6e483ULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dcbd41fbd4ULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da831153b5ULL); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152ee66dfabULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d2db43210ULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c898fb213fULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7beef0ee4ULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf33da88fc2ULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147930aa725ULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351e003826fULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x142929670a0e6e70ULL); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a8546d22ffcULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b21385c26c926ULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc5ac42aedULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d139d95b3dfULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a73548baf63deULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb3c77b2a8ULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e47edaee6ULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c851482353bULL); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a14cf10364ULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664bbc423001ULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70d0f89791ULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a30654be30ULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819d6ef5218ULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd69906245565a910ULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e35855771202aULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa07032bbd1b8ULL); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116b8d2d0c8ULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c085141ab53ULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774cdf8eeb99ULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5e19b48a8ULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3c5c95a63ULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4ae3418acbULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f7763e373ULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3d6b2b8a3ULL); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee5defb2fcULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f43172f60ULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814a1f0ab72ULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc702081a6439ecULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa23631e28ULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506cebde82bde9ULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7b2c67915ULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2e372532bULL); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],64,0xca273eceea26619cULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],65,0xd186b8c721c0c207ULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],66,0xeada7dd6cde0eb1eULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],67,0xf57d4f7fee6ed178ULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],68,0x06f067aa72176fbaULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],69,0x0a637dc5a2c898a6ULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],70,0x113f9804bef90daeULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],71,0x1b710b35131c471bULL); RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],72,0x28db77f523047d84ULL); RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],73,0x32caab7b40c72493ULL); RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],74,0x3c9ebe0a15c9bebcULL); RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],75,0x431d67c49c100d4cULL); RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],76,0x4cc5d4becb3e42b6ULL); RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],77,0x597f299cfc657e2aULL); RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],78,0x5fcb6fab3ad6faecULL); RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],79,0x6c44198c4a475817ULL); #undef RND /* feedback */ for (i = 0; i < 8; i++) { sha_info->digest[i] = sha_info->digest[i] + S[i]; } } /* initialize the SHA digest */ static void sha512_init(SHAobject *sha_info) { TestEndianness(sha_info->Endianness) sha_info->digest[0] = 0x6a09e667f3bcc908ULL; sha_info->digest[1] = 0xbb67ae8584caa73bULL; sha_info->digest[2] = 0x3c6ef372fe94f82bULL; sha_info->digest[3] = 0xa54ff53a5f1d36f1ULL; sha_info->digest[4] = 0x510e527fade682d1ULL; sha_info->digest[5] = 0x9b05688c2b3e6c1fULL; sha_info->digest[6] = 0x1f83d9abfb41bd6bULL; sha_info->digest[7] = 0x5be0cd19137e2179ULL; sha_info->count_lo = 0L; sha_info->count_hi = 0L; sha_info->local = 0; sha_info->digestsize = 64; } static void sha384_init(SHAobject *sha_info) { TestEndianness(sha_info->Endianness) sha_info->digest[0] = 0xcbbb9d5dc1059ed8ULL; sha_info->digest[1] = 0x629a292a367cd507ULL; sha_info->digest[2] = 0x9159015a3070dd17ULL; sha_info->digest[3] = 0x152fecd8f70e5939ULL; sha_info->digest[4] = 0x67332667ffc00b31ULL; sha_info->digest[5] = 0x8eb44a8768581511ULL; sha_info->digest[6] = 0xdb0c2e0d64f98fa7ULL; sha_info->digest[7] = 0x47b5481dbefa4fa4ULL; sha_info->count_lo = 0L; sha_info->count_hi = 0L; sha_info->local = 0; sha_info->digestsize = 48; } /* update the SHA digest */ static void sha512_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) { int i; SHA_INT32 clo; clo = sha_info->count_lo + ((SHA_INT32) count << 3); if (clo < sha_info->count_lo) { ++sha_info->count_hi; } sha_info->count_lo = clo; sha_info->count_hi += (SHA_INT32) count >> 29; if (sha_info->local) { i = SHA_BLOCKSIZE - sha_info->local; if (i > count) { i = count; } memcpy(((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); count -= i; buffer += i; sha_info->local += i; if (sha_info->local == SHA_BLOCKSIZE) { sha512_transform(sha_info); } else { return; } } while (count >= SHA_BLOCKSIZE) { memcpy(sha_info->data, buffer, SHA_BLOCKSIZE); buffer += SHA_BLOCKSIZE; count -= SHA_BLOCKSIZE; sha512_transform(sha_info); } memcpy(sha_info->data, buffer, count); sha_info->local = count; } /* finish computing the SHA digest */ static void sha512_final(unsigned char digest[SHA_DIGESTSIZE], SHAobject *sha_info) { int count; SHA_INT32 lo_bit_count, hi_bit_count; lo_bit_count = sha_info->count_lo; hi_bit_count = sha_info->count_hi; count = (int) ((lo_bit_count >> 3) & 0x7f); ((SHA_BYTE *) sha_info->data)[count++] = 0x80; if (count > SHA_BLOCKSIZE - 16) { memset(((SHA_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count); sha512_transform(sha_info); memset((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 16); } else { memset(((SHA_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - 16 - count); } /* GJS: note that we add the hi/lo in big-endian. sha512_transform will swap these values into host-order. */ sha_info->data[112] = 0; sha_info->data[113] = 0; sha_info->data[114] = 0; sha_info->data[115] = 0; sha_info->data[116] = 0; sha_info->data[117] = 0; sha_info->data[118] = 0; sha_info->data[119] = 0; sha_info->data[120] = (hi_bit_count >> 24) & 0xff; sha_info->data[121] = (hi_bit_count >> 16) & 0xff; sha_info->data[122] = (hi_bit_count >> 8) & 0xff; sha_info->data[123] = (hi_bit_count >> 0) & 0xff; sha_info->data[124] = (lo_bit_count >> 24) & 0xff; sha_info->data[125] = (lo_bit_count >> 16) & 0xff; sha_info->data[126] = (lo_bit_count >> 8) & 0xff; sha_info->data[127] = (lo_bit_count >> 0) & 0xff; sha512_transform(sha_info); digest[ 0] = (unsigned char) ((sha_info->digest[0] >> 56) & 0xff); digest[ 1] = (unsigned char) ((sha_info->digest[0] >> 48) & 0xff); digest[ 2] = (unsigned char) ((sha_info->digest[0] >> 40) & 0xff); digest[ 3] = (unsigned char) ((sha_info->digest[0] >> 32) & 0xff); digest[ 4] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); digest[ 5] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); digest[ 6] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); digest[ 7] = (unsigned char) ((sha_info->digest[0] ) & 0xff); digest[ 8] = (unsigned char) ((sha_info->digest[1] >> 56) & 0xff); digest[ 9] = (unsigned char) ((sha_info->digest[1] >> 48) & 0xff); digest[10] = (unsigned char) ((sha_info->digest[1] >> 40) & 0xff); digest[11] = (unsigned char) ((sha_info->digest[1] >> 32) & 0xff); digest[12] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); digest[13] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); digest[14] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); digest[15] = (unsigned char) ((sha_info->digest[1] ) & 0xff); digest[16] = (unsigned char) ((sha_info->digest[2] >> 56) & 0xff); digest[17] = (unsigned char) ((sha_info->digest[2] >> 48) & 0xff); digest[18] = (unsigned char) ((sha_info->digest[2] >> 40) & 0xff); digest[19] = (unsigned char) ((sha_info->digest[2] >> 32) & 0xff); digest[20] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); digest[21] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); digest[22] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); digest[23] = (unsigned char) ((sha_info->digest[2] ) & 0xff); digest[24] = (unsigned char) ((sha_info->digest[3] >> 56) & 0xff); digest[25] = (unsigned char) ((sha_info->digest[3] >> 48) & 0xff); digest[26] = (unsigned char) ((sha_info->digest[3] >> 40) & 0xff); digest[27] = (unsigned char) ((sha_info->digest[3] >> 32) & 0xff); digest[28] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); digest[29] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); digest[30] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); digest[31] = (unsigned char) ((sha_info->digest[3] ) & 0xff); digest[32] = (unsigned char) ((sha_info->digest[4] >> 56) & 0xff); digest[33] = (unsigned char) ((sha_info->digest[4] >> 48) & 0xff); digest[34] = (unsigned char) ((sha_info->digest[4] >> 40) & 0xff); digest[35] = (unsigned char) ((sha_info->digest[4] >> 32) & 0xff); digest[36] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); digest[37] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); digest[38] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); digest[39] = (unsigned char) ((sha_info->digest[4] ) & 0xff); digest[40] = (unsigned char) ((sha_info->digest[5] >> 56) & 0xff); digest[41] = (unsigned char) ((sha_info->digest[5] >> 48) & 0xff); digest[42] = (unsigned char) ((sha_info->digest[5] >> 40) & 0xff); digest[43] = (unsigned char) ((sha_info->digest[5] >> 32) & 0xff); digest[44] = (unsigned char) ((sha_info->digest[5] >> 24) & 0xff); digest[45] = (unsigned char) ((sha_info->digest[5] >> 16) & 0xff); digest[46] = (unsigned char) ((sha_info->digest[5] >> 8) & 0xff); digest[47] = (unsigned char) ((sha_info->digest[5] ) & 0xff); digest[48] = (unsigned char) ((sha_info->digest[6] >> 56) & 0xff); digest[49] = (unsigned char) ((sha_info->digest[6] >> 48) & 0xff); digest[50] = (unsigned char) ((sha_info->digest[6] >> 40) & 0xff); digest[51] = (unsigned char) ((sha_info->digest[6] >> 32) & 0xff); digest[52] = (unsigned char) ((sha_info->digest[6] >> 24) & 0xff); digest[53] = (unsigned char) ((sha_info->digest[6] >> 16) & 0xff); digest[54] = (unsigned char) ((sha_info->digest[6] >> 8) & 0xff); digest[55] = (unsigned char) ((sha_info->digest[6] ) & 0xff); digest[56] = (unsigned char) ((sha_info->digest[7] >> 56) & 0xff); digest[57] = (unsigned char) ((sha_info->digest[7] >> 48) & 0xff); digest[58] = (unsigned char) ((sha_info->digest[7] >> 40) & 0xff); digest[59] = (unsigned char) ((sha_info->digest[7] >> 32) & 0xff); digest[60] = (unsigned char) ((sha_info->digest[7] >> 24) & 0xff); digest[61] = (unsigned char) ((sha_info->digest[7] >> 16) & 0xff); digest[62] = (unsigned char) ((sha_info->digest[7] >> 8) & 0xff); digest[63] = (unsigned char) ((sha_info->digest[7] ) & 0xff); } /* * End of copied SHA code. * * ------------------------------------------------------------------------ */ static PyTypeObject SHA384type; static PyTypeObject SHA512type; static SHAobject * newSHA384object(void) { return (SHAobject *)PyObject_New(SHAobject, &SHA384type); } static SHAobject * newSHA512object(void) { return (SHAobject *)PyObject_New(SHAobject, &SHA512type); } /* Internal methods for a hash object */ static void SHA512_dealloc(PyObject *ptr) { PyObject_Del(ptr); } /* External methods for a hash object */ PyDoc_STRVAR(SHA512_copy__doc__, "Return a copy of the hash object."); static PyObject * SHA512_copy(SHAobject *self, PyObject *args) { SHAobject *newobj; if (!PyArg_ParseTuple(args, ":copy")) { return NULL; } if (((PyObject*)self)->ob_type == &SHA512type) { if ( (newobj = newSHA512object())==NULL) return NULL; } else { if ( (newobj = newSHA384object())==NULL) return NULL; } SHAcopy(self, newobj); return (PyObject *)newobj; } PyDoc_STRVAR(SHA512_digest__doc__, "Return the digest value as a string of binary data."); static PyObject * SHA512_digest(SHAobject *self, PyObject *args) { unsigned char digest[SHA_DIGESTSIZE]; SHAobject temp; if (!PyArg_ParseTuple(args, ":digest")) return NULL; SHAcopy(self, &temp); sha512_final(digest, &temp); return PyString_FromStringAndSize((const char *)digest, self->digestsize); } PyDoc_STRVAR(SHA512_hexdigest__doc__, "Return the digest value as a string of hexadecimal digits."); static PyObject * SHA512_hexdigest(SHAobject *self, PyObject *args) { unsigned char digest[SHA_DIGESTSIZE]; SHAobject temp; PyObject *retval; char *hex_digest; int i, j; if (!PyArg_ParseTuple(args, ":hexdigest")) return NULL; /* Get the raw (binary) digest value */ SHAcopy(self, &temp); sha512_final(digest, &temp); /* Create a new string */ retval = PyString_FromStringAndSize(NULL, self->digestsize * 2); if (!retval) return NULL; hex_digest = PyString_AsString(retval); if (!hex_digest) { Py_DECREF(retval); return NULL; } /* Make hex version of the digest */ for(i=j=0; idigestsize; i++) { char c; c = (digest[i] >> 4) & 0xf; c = (c>9) ? c+'a'-10 : c + '0'; hex_digest[j++] = c; c = (digest[i] & 0xf); c = (c>9) ? c+'a'-10 : c + '0'; hex_digest[j++] = c; } return retval; } PyDoc_STRVAR(SHA512_update__doc__, "Update this hash object's state with the provided string."); static PyObject * SHA512_update(SHAobject *self, PyObject *args) { unsigned char *cp; int len; if (!PyArg_ParseTuple(args, "s#:update", &cp, &len)) return NULL; sha512_update(self, cp, len); Py_INCREF(Py_None); return Py_None; } static PyMethodDef SHA_methods[] = { {"copy", (PyCFunction)SHA512_copy, METH_VARARGS, SHA512_copy__doc__}, {"digest", (PyCFunction)SHA512_digest, METH_VARARGS, SHA512_digest__doc__}, {"hexdigest", (PyCFunction)SHA512_hexdigest, METH_VARARGS, SHA512_hexdigest__doc__}, {"update", (PyCFunction)SHA512_update, METH_VARARGS, SHA512_update__doc__}, {NULL, NULL} /* sentinel */ }; static PyObject * SHA512_get_block_size(PyObject *self, void *closure) { return PyInt_FromLong(SHA_BLOCKSIZE); } static PyObject * SHA512_get_name(PyObject *self, void *closure) { if (((SHAobject *)self)->digestsize == 64) return PyString_FromStringAndSize("SHA512", 6); else return PyString_FromStringAndSize("SHA384", 6); } static PyGetSetDef SHA_getseters[] = { {"block_size", (getter)SHA512_get_block_size, NULL, NULL, NULL}, {"name", (getter)SHA512_get_name, NULL, NULL, NULL}, {NULL} /* Sentinel */ }; static PyMemberDef SHA_members[] = { {"digest_size", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, /* the old md5 and sha modules support 'digest_size' as in PEP 247. * the old sha module also supported 'digestsize'. ugh. */ {"digestsize", T_INT, offsetof(SHAobject, digestsize), READONLY, NULL}, {NULL} /* Sentinel */ }; static PyTypeObject SHA384type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "_sha512.sha384", /*tp_name*/ sizeof(SHAobject), /*tp_size*/ 0, /*tp_itemsize*/ /* methods */ SHA512_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ SHA_methods, /* tp_methods */ SHA_members, /* tp_members */ SHA_getseters, /* tp_getset */ }; static PyTypeObject SHA512type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "_sha512.sha512", /*tp_name*/ sizeof(SHAobject), /*tp_size*/ 0, /*tp_itemsize*/ /* methods */ SHA512_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ 0, /*tp_call*/ 0, /*tp_str*/ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT, /*tp_flags*/ 0, /*tp_doc*/ 0, /*tp_traverse*/ 0, /*tp_clear*/ 0, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ 0, /*tp_iter*/ 0, /*tp_iternext*/ SHA_methods, /* tp_methods */ SHA_members, /* tp_members */ SHA_getseters, /* tp_getset */ }; /* The single module-level function: new() */ PyDoc_STRVAR(SHA512_new__doc__, "Return a new SHA-512 hash object; optionally initialized with a string."); static PyObject * SHA512_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; SHAobject *new; unsigned char *cp = NULL; int len; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, &cp, &len)) { return NULL; } if ((new = newSHA512object()) == NULL) return NULL; sha512_init(new); if (PyErr_Occurred()) { Py_DECREF(new); return NULL; } if (cp) sha512_update(new, cp, len); return (PyObject *)new; } PyDoc_STRVAR(SHA384_new__doc__, "Return a new SHA-384 hash object; optionally initialized with a string."); static PyObject * SHA384_new(PyObject *self, PyObject *args, PyObject *kwdict) { static char *kwlist[] = {"string", NULL}; SHAobject *new; unsigned char *cp = NULL; int len; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|s#:new", kwlist, &cp, &len)) { return NULL; } if ((new = newSHA384object()) == NULL) return NULL; sha384_init(new); if (PyErr_Occurred()) { Py_DECREF(new); return NULL; } if (cp) sha512_update(new, cp, len); return (PyObject *)new; } /* List of functions exported by this module */ static struct PyMethodDef SHA_functions[] = { {"sha512", (PyCFunction)SHA512_new, METH_VARARGS|METH_KEYWORDS, SHA512_new__doc__}, {"sha384", (PyCFunction)SHA384_new, METH_VARARGS|METH_KEYWORDS, SHA384_new__doc__}, {NULL, NULL} /* Sentinel */ }; /* Initialize this module. */ #define insint(n,v) { PyModule_AddIntConstant(m,n,v); } PyMODINIT_FUNC init_sha512(void) { PyObject *m; SHA384type.ob_type = &PyType_Type; if (PyType_Ready(&SHA384type) < 0) return; SHA512type.ob_type = &PyType_Type; if (PyType_Ready(&SHA512type) < 0) return; m = Py_InitModule("_sha512", SHA_functions); } #endif Index: md5module.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/md5module.c,v retrieving revision 2.35 retrieving revision 2.36 diff -u -d -r2.35 -r2.36 --- md5module.c 8 Jul 2003 21:17:25 -0000 2.35 +++ md5module.c 21 Aug 2005 18:46:02 -0000 2.36 @@ -10,6 +10,7 @@ /* MD5 objects */ #include "Python.h" +#include "structmember.h" #include "md5.h" typedef struct { @@ -150,15 +151,46 @@ }; static PyObject * -md5_getattr(md5object *self, char *name) +md5_get_block_size(PyObject *self, void *closure) { - if (strcmp(name, "digest_size") == 0) { - return PyInt_FromLong(16); - } + return PyInt_FromLong(64); +} - return Py_FindMethod(md5_methods, (PyObject *)self, name); +static PyObject * +md5_get_digest_size(PyObject *self, void *closure) +{ + return PyInt_FromLong(16); +} + +static PyObject * +md5_get_name(PyObject *self, void *closure) +{ + return PyString_FromStringAndSize("MD5", 3); } +static PyGetSetDef md5_getseters[] = { + {"digest_size", + (getter)md5_get_digest_size, NULL, + NULL, + NULL}, + {"block_size", + (getter)md5_get_block_size, NULL, + NULL, + NULL}, + {"name", + (getter)md5_get_name, NULL, + NULL, + NULL}, + /* the old md5 and sha modules support 'digest_size' as in PEP 247. + * the old sha module also supported 'digestsize'. ugh. */ + {"digestsize", + (getter)md5_get_digest_size, NULL, + NULL, + NULL}, + {NULL} /* Sentinel */ +}; + + PyDoc_STRVAR(module_doc, "This module implements the interface to RSA's MD5 message digest\n\ algorithm (see also Internet RFC 1321). Its use is quite\n\ @@ -191,13 +223,13 @@ static PyTypeObject MD5type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ - "md5.md5", /*tp_name*/ + "_md5.md5", /*tp_name*/ sizeof(md5object), /*tp_size*/ 0, /*tp_itemsize*/ /* methods */ (destructor)md5_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - (getattrfunc)md5_getattr, /*tp_getattr*/ + 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ @@ -210,8 +242,17 @@ 0, /*tp_getattro*/ 0, /*tp_setattro*/ 0, /*tp_as_buffer*/ - 0, /*tp_xxx4*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ md5type_doc, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + md5_methods, /*tp_methods*/ + 0, /*tp_members*/ + md5_getseters, /*tp_getset*/ }; @@ -247,7 +288,6 @@ static PyMethodDef md5_functions[] = { {"new", (PyCFunction)MD5_new, METH_VARARGS, new_doc}, - {"md5", (PyCFunction)MD5_new, METH_VARARGS, new_doc}, /* Backward compatibility */ {NULL, NULL} /* Sentinel */ }; @@ -255,12 +295,14 @@ /* Initialize this module. */ PyMODINIT_FUNC -initmd5(void) +init_md5(void) { PyObject *m, *d; MD5type.ob_type = &PyType_Type; - m = Py_InitModule3("md5", md5_functions, module_doc); + if (PyType_Ready(&MD5type) < 0) + return; + m = Py_InitModule3("_md5", md5_functions, module_doc); d = PyModule_GetDict(m); PyDict_SetItemString(d, "MD5Type", (PyObject *)&MD5type); PyModule_AddIntConstant(m, "digest_size", 16); Index: shamodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/shamodule.c,v retrieving revision 2.22 retrieving revision 2.23 diff -u -d -r2.22 -r2.23 --- shamodule.c 30 Oct 2002 21:08:32 -0000 2.22 +++ shamodule.c 21 Aug 2005 18:46:02 -0000 2.23 @@ -7,11 +7,16 @@ Andrew Kuchling (amk at amk.ca) Greg Stein (gstein at lyra.org) + + Copyright (C) 2005 Gregory P. Smith (greg at electricrain.com) + Licensed to PSF under a Contributor Agreement. + */ /* SHA objects */ #include "Python.h" +#include "structmember.h" /* Endianness testing and definitions */ @@ -453,26 +458,78 @@ }; static PyObject * -SHA_getattr(PyObject *self, char *name) +SHA_get_block_size(PyObject *self, void *closure) { - if (strcmp(name, "blocksize")==0) - return PyInt_FromLong(1); - if (strcmp(name, "digest_size")==0 || strcmp(name, "digestsize")==0) - return PyInt_FromLong(20); + return PyInt_FromLong(SHA_BLOCKSIZE); +} - return Py_FindMethod(SHA_methods, self, name); +static PyObject * +SHA_get_digest_size(PyObject *self, void *closure) +{ + return PyInt_FromLong(SHA_DIGESTSIZE); +} + +static PyObject * +SHA_get_name(PyObject *self, void *closure) +{ + return PyString_FromStringAndSize("SHA1", 4); } +static PyGetSetDef SHA_getseters[] = { + {"digest_size", + (getter)SHA_get_digest_size, NULL, + NULL, + NULL}, + {"block_size", + (getter)SHA_get_block_size, NULL, + NULL, + NULL}, + {"name", + (getter)SHA_get_name, NULL, + NULL, + NULL}, + /* the old md5 and sha modules support 'digest_size' as in PEP 247. + * the old sha module also supported 'digestsize'. ugh. */ + {"digestsize", + (getter)SHA_get_digest_size, NULL, + NULL, + NULL}, + {NULL} /* Sentinel */ +}; + static PyTypeObject SHAtype = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ - "sha.SHA", /*tp_name*/ + "_sha.sha", /*tp_name*/ sizeof(SHAobject), /*tp_size*/ 0, /*tp_itemsize*/ /* methods */ SHA_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ - SHA_getattr, /*tp_getattr*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT, /*tp_flags*/ + 0, /*tp_doc*/ + 0, /*tp_traverse*/ + 0, /*tp_clear*/ + 0, /*tp_richcompare*/ + 0, /*tp_weaklistoffset*/ + 0, /*tp_iter*/ + 0, /*tp_iternext*/ + SHA_methods, /* tp_methods */ + 0, /* tp_members */ + SHA_getseters, /* tp_getset */ }; @@ -516,7 +573,6 @@ static struct PyMethodDef SHA_functions[] = { {"new", (PyCFunction)SHA_new, METH_VARARGS|METH_KEYWORDS, SHA_new__doc__}, - {"sha", (PyCFunction)SHA_new, METH_VARARGS|METH_KEYWORDS, SHA_new__doc__}, {NULL, NULL} /* Sentinel */ }; @@ -526,12 +582,14 @@ #define insint(n,v) { PyModule_AddIntConstant(m,n,v); } PyMODINIT_FUNC -initsha(void) +init_sha(void) { PyObject *m; SHAtype.ob_type = &PyType_Type; - m = Py_InitModule("sha", SHA_functions); + if (PyType_Ready(&SHAtype) < 0) + return; + m = Py_InitModule("_sha", SHA_functions); /* Add some symbolic constants to the module */ insint("blocksize", 1); /* For future use, in case some hash From greg at users.sourceforge.net Sun Aug 21 20:46:39 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Sun, 21 Aug 2005 20:46:39 +0200 (CEST) Subject: [Python-checkins] python/dist/src setup.py,1.219,1.220 Message-ID: <20050821184639.EF8711E4006@bag.python.org> Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32064 Modified Files: setup.py Log Message: [ sf.net patch # 1121611 ] A new hashlib module to replace the md5 and sha modules. It adds support for additional secure hashes such as SHA-256 and SHA-512. The hashlib module uses OpenSSL for fast platform optimized implementations of algorithms when available. The old md5 and sha modules still exist as wrappers around hashlib to preserve backwards compatibility. Index: setup.py =================================================================== RCS file: /cvsroot/python/python/dist/src/setup.py,v retrieving revision 1.219 retrieving revision 1.220 diff -u -d -r1.219 -r1.220 --- setup.py 17 Jul 2005 02:37:00 -0000 1.219 +++ setup.py 21 Aug 2005 18:45:58 -0000 1.220 @@ -400,15 +400,6 @@ # select(2); not on ancient System V exts.append( Extension('select', ['selectmodule.c']) ) - # The md5 module implements the RSA Data Security, Inc. MD5 - # Message-Digest Algorithm, described in RFC 1321. The - # necessary files md5c.c and md5.h are included here. - exts.append( Extension('md5', ['md5module.c', 'md5c.c']) ) - - # The sha module implements the SHA checksum algorithm. - # (NIST's Secure Hash Algorithm.) - exts.append( Extension('sha', ['shamodule.c']) ) - # Helper module for various ascii-encoders exts.append( Extension('binascii', ['binascii.c']) ) @@ -506,6 +497,32 @@ libraries = ['ssl', 'crypto'], depends = ['socketmodule.h']), ) + if (ssl_incs is not None and + ssl_libs is not None): + # The _hashlib module wraps optimized implementations + # of hash functions from the OpenSSL library. + exts.append( Extension('_hashlib', ['_hashopenssl.c'], + include_dirs = ssl_incs, + library_dirs = ssl_libs, + libraries = ['ssl', 'crypto']) ) + else: + # The _sha module implements the SHA1 hash algorithm. + exts.append( Extension('_sha', ['shamodule.c']) ) + # The _md5 module implements the RSA Data Security, Inc. MD5 + # Message-Digest Algorithm, described in RFC 1321. The + # necessary files md5c.c and md5.h are included here. + exts.append( Extension('_md5', ['md5module.c', 'md5c.c']) ) + + # always compile these for now under the assumption that + # OpenSSL does not support them (it doesn't in common OpenSSL + # 0.9.7e installs at the time of this writing; OpenSSL 0.9.8 + # does). In the future we could make this conditional on + # OpenSSL version or support. The hashlib module uses the + # better implementation regardless. + exts.append( Extension('_sha256', ['sha256module.c']) ) + exts.append( Extension('_sha512', ['sha512module.c']) ) + + # Modules that provide persistent dictionary-like semantics. You will # probably want to arrange for at least one of them to be available on # your machine, though none are defined by default because of library From greg at users.sourceforge.net Sun Aug 21 20:46:41 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Sun, 21 Aug 2005 20:46:41 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc ACKS, 1.41, 1.42 Makefile.deps, 1.123, 1.124 Message-ID: <20050821184641.5D2011E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32064/Doc Modified Files: ACKS Makefile.deps Log Message: [ sf.net patch # 1121611 ] A new hashlib module to replace the md5 and sha modules. It adds support for additional secure hashes such as SHA-256 and SHA-512. The hashlib module uses OpenSSL for fast platform optimized implementations of algorithms when available. The old md5 and sha modules still exist as wrappers around hashlib to preserve backwards compatibility. Index: ACKS =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ACKS,v retrieving revision 1.41 retrieving revision 1.42 diff -u -d -r1.41 -r1.42 --- ACKS 24 Mar 2005 06:21:37 -0000 1.41 +++ ACKS 21 Aug 2005 18:45:59 -0000 1.42 @@ -164,6 +164,7 @@ Justin Sheehy Michael Simcich Ionel Simionescu +Gregory P. Smith Roy Smith Clay Spence Nicholas Spies Index: Makefile.deps =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/Makefile.deps,v retrieving revision 1.123 retrieving revision 1.124 diff -u -d -r1.123 -r1.124 --- Makefile.deps 23 Jan 2005 09:27:22 -0000 1.123 +++ Makefile.deps 21 Aug 2005 18:45:59 -0000 1.124 @@ -202,6 +202,7 @@ lib/librgbimg.tex \ lib/libossaudiodev.tex \ lib/libcrypto.tex \ + lib/libhashlib.tex \ lib/libmd5.tex \ lib/libsha.tex \ lib/libhmac.tex \ From greg at users.sourceforge.net Sun Aug 21 20:46:41 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Sun, 21 Aug 2005 20:46:41 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib lib.tex, 1.239, 1.240 libhmac.tex, 1.1, 1.2 libmd5.tex, 1.21, 1.22 libsha.tex, 1.12, 1.13 Message-ID: <20050821184641.9B1981E4050@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32064/Doc/lib Modified Files: lib.tex libhmac.tex libmd5.tex libsha.tex Log Message: [ sf.net patch # 1121611 ] A new hashlib module to replace the md5 and sha modules. It adds support for additional secure hashes such as SHA-256 and SHA-512. The hashlib module uses OpenSSL for fast platform optimized implementations of algorithms when available. The old md5 and sha modules still exist as wrappers around hashlib to preserve backwards compatibility. Index: lib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/lib.tex,v retrieving revision 1.239 retrieving revision 1.240 diff -u -d -r1.239 -r1.240 --- lib.tex 18 Jun 2005 20:06:15 -0000 1.239 +++ lib.tex 21 Aug 2005 18:45:59 -0000 1.240 @@ -303,6 +303,7 @@ \input{libcrypto} % Cryptographic Services \input{libhmac} +\input{libhashlib} \input{libmd5} \input{libsha} Index: libhmac.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libhmac.tex,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- libhmac.tex 11 Sep 2001 16:56:09 -0000 1.1 +++ libhmac.tex 21 Aug 2005 18:46:00 -0000 1.2 @@ -14,8 +14,10 @@ \begin{funcdesc}{new}{key\optional{, msg\optional{, digestmod}}} Return a new hmac object. If \var{msg} is present, the method call \code{update(\var{msg})} is made. \var{digestmod} is the digest - module for the HMAC object to use. It defaults to the - \refmodule{md5} module. + constructor or module for the HMAC object to use. It defaults to + the \code{\refmodule{hashlib}.md5} constructor. \note{The md5 hash + has known weaknesses but remains the default for backwards compatibility. + Choose a better one for your application.} \end{funcdesc} An HMAC object has the following methods: @@ -29,14 +31,14 @@ \begin{methoddesc}[hmac]{digest}{} Return the digest of the strings passed to the \method{update()} - method so far. This is a 16-byte string (for \refmodule{md5}) or a - 20-byte string (for \refmodule{sha}) which may contain non-\ASCII{} - characters, including NUL bytes. + method so far. This string will be the same length as the + \var{digest_size} of the digest given to the constructor. It + may contain non-\ASCII{} characters, including NUL bytes. \end{methoddesc} \begin{methoddesc}[hmac]{hexdigest}{} - Like \method{digest()} except the digest is returned as a string of - length 32 for \refmodule{md5} (40 for \refmodule{sha}), containing + Like \method{digest()} except the digest is returned as a string + twice the length containing only hexadecimal digits. This may be used to exchange the value safely in email or other non-binary environments. \end{methoddesc} @@ -46,3 +48,7 @@ efficiently compute the digests of strings that share a common initial substring. \end{methoddesc} + +\begin{seealso} + \seemodule{hashlib}{The python module providing secure hash functions.} +\end{seealso} Index: libmd5.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libmd5.tex,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- libmd5.tex 2 Nov 2001 21:44:09 -0000 1.21 +++ libmd5.tex 21 Aug 2005 18:46:00 -0000 1.22 @@ -4,6 +4,7 @@ \declaremodule{builtin}{md5} \modulesynopsis{RSA's MD5 message digest algorithm.} +\deprecated{2.5}{Use the \refmodule{hashlib} module instead.} This module implements the interface to RSA's MD5 message digest \index{message digest, MD5} Index: libsha.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libsha.tex,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- libsha.tex 29 Jun 2004 13:35:01 -0000 1.12 +++ libsha.tex 21 Aug 2005 18:46:00 -0000 1.13 @@ -5,6 +5,8 @@ \modulesynopsis{NIST's secure hash algorithm, SHA.} \sectionauthor{Fred L. Drake, Jr.}{fdrake at acm.org} +\deprecated{2.5}{Use the \refmodule{hashlib} module instead.} + This module implements the interface to NIST's\index{NIST} secure hash algorithm,\index{Secure Hash Algorithm} known as SHA-1. SHA-1 is an From gregorykjohnson at users.sourceforge.net Sun Aug 21 21:02:58 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Sun, 21 Aug 2005 21:02:58 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox libmailbox.tex, 1.12, 1.13 mailbox.py, 1.12, 1.13 Message-ID: <20050821190258.6158E1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3406 Modified Files: libmailbox.tex mailbox.py Log Message: * Add mailbox classes and add next() method to Maildir, for backward compatibility. * Document backward compatibility. * Add examples to documentation. * Remove unncessary len() check before string slicing (as pointed out by A.M. Kuchling). Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- libmailbox.tex 17 Aug 2005 20:32:36 -0000 1.12 +++ libmailbox.tex 21 Aug 2005 19:02:47 -0000 1.13 @@ -14,27 +14,6 @@ class with format-specific state and behavior. Supported mailbox formats are Maildir, mbox, MH, Babyl, and MMDF. -An example of using the module to sort mail: - -\begin{verbatim} ->>> import mailbox ->>> inbox = mailbox.Maildir('~/Maildir', None) ->>> python_box = mailbox.Maildir('~/email/python-list', None) ->>> len(inbox) # Number of messages. -13 ->>> len(python_box) -818 ->>> for key, message in inbox.iteritems(): -... if 'python-list' in message['list-id']: -... python_box.add(message) # Add the message to python_box -... del inbox[key] # and remove it from inbox. -... ->>> len(inbox) -2 ->>> len(python_box) -829 -\end{verbatim} - \begin{seealso} \seemodule{email}{Represent and manipulate messages.} \end{seealso} @@ -1185,8 +1164,192 @@ \lineii{A flag}{A flag} \end{tableii} -\subsection{Deprecated classes} -\label{mailbox-deprecated-classes} +\subsection{Deprecated classes and methods} +\label{mailbox-deprecated} + +Older versions of the \module{mailbox} module do not support modification of +mailboxes, such as adding or removing message, and do not provide classes to +represent format-specific message properties. For backward compatibility, the +older mailbox classes are still available, but the newer classes should be used +in preference to them. + +Older mailbox objects support only iteration and provide a single public +method: + +\begin{methoddesc}{next}{} +Return the next message in the mailbox, created with the optional \var{factory} +argument passed into the mailbox object's constructor. By default this is an +\class{rfc822.Message} object (see the \refmodule{rfc822} module). Depending +on the mailbox implementation the \var{fp} attribute of this object may be a +true file object or a class instance simulating a file object, taking care of +things like message boundaries if multiple mail messages are contained in a +single file, etc. If no more messages are available, this method returns +\code{None}. +\end{methoddesc} + +Most of the older mailbox classes have names that differ from the current +mailbox class names, except for \class{Maildir}. For this reason, the new +\class{Maildir} class defines a \method{next()} method and its constructor +differs slightly from those of the other new mailbox classes. + +The older mailbox classes whose names are not the same as their newer +counterparts are as follows: + +\begin{classdesc}{UnixMailbox}{fp\optional{, factory}} +Access to a classic \UNIX-style mailbox, where all messages are +contained in a single file and separated by \samp{From } +(a.k.a.\ \samp{From_}) lines. The file object \var{fp} points to the +mailbox file. The optional \var{factory} parameter is a callable that +should create new message objects. \var{factory} is called with one +argument, \var{fp} by the \method{next()} method of the mailbox +object. The default is the \class{rfc822.Message} class (see the +\refmodule{rfc822} module -- and the note below). + +\begin{notice} + For reasons of this module's internal implementation, you will + probably want to open the \var{fp} object in binary mode. This is + especially important on Windows. +\end{notice} + +For maximum portability, messages in a \UNIX-style mailbox are +separated by any line that begins exactly with the string \code{'From +'} (note the trailing space) if preceded by exactly two newlines. +Because of the wide-range of variations in practice, nothing else on +the From_ line should be considered. However, the current +implementation doesn't check for the leading two newlines. This is +usually fine for most applications. + +The \class{UnixMailbox} class implements a more strict version of +From_ line checking, using a regular expression that usually correctly +matched From_ delimiters. It considers delimiter line to be separated +by \samp{From \var{name} \var{time}} lines. For maximum portability, +use the \class{PortableUnixMailbox} class instead. This class is +identical to \class{UnixMailbox} except that individual messages are +separated by only \samp{From } lines. + +For more information, see +\citetitle[http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html]{Configuring +Netscape Mail on \UNIX: Why the Content-Length Format is Bad}. +\end{classdesc} + +\begin{classdesc}{PortableUnixMailbox}{fp\optional{, factory}} +A less-strict version of \class{UnixMailbox}, which considers only the +\samp{From } at the beginning of the line separating messages. The +``\var{name} \var{time}'' portion of the From line is ignored, to +protect against some variations that are observed in practice. This +works since lines in the message which begin with \code{'From '} are +quoted by mail handling software at delivery-time. +\end{classdesc} + +\begin{classdesc}{MmdfMailbox}{fp\optional{, factory}} +Access an MMDF-style mailbox, where all messages are contained +in a single file and separated by lines consisting of 4 control-A +characters. The file object \var{fp} points to the mailbox file. +Optional \var{factory} is as with the \class{UnixMailbox} class. +\end{classdesc} + +\begin{classdesc}{MHMailbox}{dirname\optional{, factory}} +Access an MH mailbox, a directory with each message in a separate +file with a numeric name. +The name of the mailbox directory is passed in \var{dirname}. +\var{factory} is as with the \class{UnixMailbox} class. +\end{classdesc} + +\begin{classdesc}{BabylMailbox}{fp\optional{, factory}} +Access a Babyl mailbox, which is similar to an MMDF mailbox. In +Babyl format, each message has two sets of headers, the +\emph{original} headers and the \emph{visible} headers. The original +headers appear before a line containing only \code{'*** EOOH ***'} +(End-Of-Original-Headers) and the visible headers appear after the +\code{EOOH} line. Babyl-compliant mail readers will show you only the +visible headers, and \class{BabylMailbox} objects will return messages +containing only the visible headers. You'll have to do your own +parsing of the mailbox file to get at the original headers. Mail +messages start with the EOOH line and end with a line containing only +\code{'\e{}037\e{}014'}. \var{factory} is as with the +\class{UnixMailbox} class. +\end{classdesc} + +If you wish to use the older mailbox classes with the \module{email} module +rather than the deprecated \module{rfc822} module, you can do so as follows: + +\begin{verbatim} +import email +import email.Errors +import mailbox + +def msgfactory(fp): + try: + return email.message_from_file(fp) + except email.Errors.MessageParseError: + # Don't return None since that will + # stop the mailbox iterator + return '' + +mbox = mailbox.UnixMailbox(fp, msgfactory) +\end{verbatim} + +Alternatively, if you know your mailbox contains only well-formed MIME +messages, you can simplify this to: + +\begin{verbatim} +import email +import mailbox + +mbox = mailbox.UnixMailbox(fp, email.message_from_file) +\end{verbatim} \subsection{Examples} \label{mailbox-examples} + +A simple example of printing the subjects of all messages in a mailbox that +seem interesting: + +\begin{verbatim} +import mailbox +for message in mailbox.mbox('~/mbox'): + subject = message['subject'] # Could possibly be None. + if subject and 'python' in subject.lower(): + print subject +\end{verbatim} + +A (surprisingly) simple example of copying all mail from a Babyl mailbox to an +MH mailbox, converting all of the format-specific information that can be +converted: + +\begin{verbatim} +import mailbox +destination = mailbox.MH('~/Mail') +for message in mailbox.Babyl('~/RMAIL'): + destination.add(MHMessage(message)) +\end{verbatim} + +An example of sorting mail from numerous mailing lists, being careful to avoid +mail corruption due to concurrent modification by other programs, mail loss due +to interruption of the program, or premature termination due to malformed +messages in the mailbox: + +\begin{verbatim} +import mailbox +import email.Errors +list_names = ('python-list', 'python-dev', 'python-bugs') +boxes = dict((name, mailbox.mbox('~/email/%s' % name)) for name in list_names) +inbox = mailbox.Maildir('~/Maildir', None) +for key in inbox.iterkeys(): + try: + message = inbox[key] + except email.Errors.MessageParseError: + continue # The message is malformed. Just leave it. + for name in list_names: + list_id = message['list-id'] + if list_id and name in list_id: + box = boxes[name] + box.lock() + box.add(message) + box.flush() # Write copy to disk before removing original. + box.unlock() + inbox.discard(key) + break # Found destination, so stop looking. +for box in boxes.itervalues(): + box.close() +\end{verbatim} Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- mailbox.py 19 Aug 2005 19:25:55 -0000 1.12 +++ mailbox.py 21 Aug 2005 19:02:47 -0000 1.13 @@ -21,7 +21,8 @@ __all__ = [ 'Mailbox', 'Maildir', 'mbox', 'MH', 'Babyl', 'MMDF', 'Message', 'MaildirMessage', 'mboxMessage', 'MHMessage', - 'BabylMessage', 'MMDFMessage' ] + 'BabylMessage', 'MMDFMessage', 'UnixMailbox', + 'PortableUnixMailbox', 'MmdfMailbox', 'MHMailbox', 'BabylMailbox' ] class Mailbox: @@ -447,6 +448,16 @@ except KeyError: raise KeyError('No message with key: %s' % key) + # This method is for backward compatibility only. + def next(self): + """Return the next message in a one-time iteration.""" + if not hasattr(self, '_onetime_iterator'): + self._onetime_iterator = self.itervalues() + try: + return self._onetime_iterator.next() + except StopIteration: + return None + class _singlefileMailbox(Mailbox): """A single-file mailbox.""" @@ -1310,7 +1321,7 @@ def get_flags(self): """Return as a string the flags that are set.""" - if len(self._info) > 2 and self._info.startswith('2,'): + if self._info.startswith('2,'): return self._info[2:] else: return '' @@ -1843,6 +1854,184 @@ socket.gethostname(), os.getpid())) + +## Start: classes from the original module (for backward compatibility). + +# Note that the Maildir class, whose name is unchanged, itself offers a next() +# method for backward compatibility. + +class _Mailbox: + + def __init__(self, fp, factory=rfc822.Message): + self.fp = fp + self.seekp = 0 + self.factory = factory + + def __iter__(self): + return iter(self.next, None) + + def next(self): + while 1: + self.fp.seek(self.seekp) + try: + self._search_start() + except EOFError: + self.seekp = self.fp.tell() + return None + start = self.fp.tell() + self._search_end() + self.seekp = stop = self.fp.tell() + if start != stop: + break + return self.factory(_PartialFile(self.fp, start, stop)) + +# Recommended to use PortableUnixMailbox instead! +class UnixMailbox(_Mailbox): + + def _search_start(self): + while 1: + pos = self.fp.tell() + line = self.fp.readline() + if not line: + raise EOFError + if line[:5] == 'From ' and self._isrealfromline(line): + self.fp.seek(pos) + return + + def _search_end(self): + self.fp.readline() # Throw away header line + while 1: + pos = self.fp.tell() + line = self.fp.readline() + if not line: + return + if line[:5] == 'From ' and self._isrealfromline(line): + self.fp.seek(pos) + return + + # An overridable mechanism to test for From-line-ness. You can either + # specify a different regular expression or define a whole new + # _isrealfromline() method. Note that this only gets called for lines + # starting with the 5 characters "From ". + # + # BAW: According to + #http://home.netscape.com/eng/mozilla/2.0/relnotes/demo/content-length.html + # the only portable, reliable way to find message delimiters in a BSD (i.e + # Unix mailbox) style folder is to search for "\n\nFrom .*\n", or at the + # beginning of the file, "^From .*\n". While _fromlinepattern below seems + # like a good idea, in practice, there are too many variations for more + # strict parsing of the line to be completely accurate. + # + # _strict_isrealfromline() is the old version which tries to do stricter + # parsing of the From_ line. _portable_isrealfromline() simply returns + # true, since it's never called if the line doesn't already start with + # "From ". + # + # This algorithm, and the way it interacts with _search_start() and + # _search_end() may not be completely correct, because it doesn't check + # that the two characters preceding "From " are \n\n or the beginning of + # the file. Fixing this would require a more extensive rewrite than is + # necessary. For convenience, we've added a PortableUnixMailbox class + # which uses the more lenient _fromlinepattern regular expression. + + _fromlinepattern = r"From \s*[^\s]+\s+\w\w\w\s+\w\w\w\s+\d?\d\s+" \ + r"\d?\d:\d\d(:\d\d)?(\s+[^\s]+)?\s+\d\d\d\d\s*$" + _regexp = None + + def _strict_isrealfromline(self, line): + if not self._regexp: + import re + self._regexp = re.compile(self._fromlinepattern) + return self._regexp.match(line) + + def _portable_isrealfromline(self, line): + return True + + _isrealfromline = _strict_isrealfromline + + +class PortableUnixMailbox(UnixMailbox): + _isrealfromline = UnixMailbox._portable_isrealfromline + + +class MmdfMailbox(_Mailbox): + + def _search_start(self): + while 1: + line = self.fp.readline() + if not line: + raise EOFError + if line[:5] == '\001\001\001\001\n': + return + + def _search_end(self): + while 1: + pos = self.fp.tell() + line = self.fp.readline() + if not line: + return + if line == '\001\001\001\001\n': + self.fp.seek(pos) + return + + +class MHMailbox: + + def __init__(self, dirname, factory=rfc822.Message): + import re + pat = re.compile('^[1-9][0-9]*$') + self.dirname = dirname + # the three following lines could be combined into: + # list = map(long, filter(pat.match, os.listdir(self.dirname))) + list = os.listdir(self.dirname) + list = filter(pat.match, list) + list = map(long, list) + list.sort() + # This only works in Python 1.6 or later; + # before that str() added 'L': + self.boxes = map(str, list) + self.boxes.reverse() + self.factory = factory + + def __iter__(self): + return iter(self.next, None) + + def next(self): + if not self.boxes: + return None + fn = self.boxes.pop() + fp = open(os.path.join(self.dirname, fn)) + msg = self.factory(fp) + try: + msg._mh_msgno = fn + except (AttributeError, TypeError): + pass + return msg + + +class BabylMailbox(_Mailbox): + + def _search_start(self): + while 1: + line = self.fp.readline() + if not line: + raise EOFError + if line == '*** EOOH ***\n': + return + + def _search_end(self): + while 1: + pos = self.fp.tell() + line = self.fp.readline() + if not line: + return + if line == '\037\014\n' or line == '\037': + self.fp.seek(pos) + return + +## End: classes from the original module (for backward compatibility). + + class Error(Exception): """Raised for module-specific errors.""" From gregorykjohnson at users.sourceforge.net Sun Aug 21 23:18:04 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Sun, 21 Aug 2005 23:18:04 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox mailbox.py, 1.13, 1.14 test_mailbox.py, 1.8, 1.9 Message-ID: <20050821211804.3A49D1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30110 Modified Files: mailbox.py test_mailbox.py Log Message: * Add tests for all methods that didn't have them yet. * Add tests from old mailbox module. * Make some small fixes. Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- mailbox.py 21 Aug 2005 19:02:47 -0000 1.13 +++ mailbox.py 21 Aug 2005 21:17:53 -0000 1.14 @@ -939,7 +939,7 @@ def add_folder(self, folder): """Create a folder and return an MH instance representing it.""" - return MH(os.path.join(self._path, '.' + folder)) + return MH(os.path.join(self._path, folder)) def remove_folder(self, folder): """Delete the named folder, which must be empty.""" @@ -971,6 +971,8 @@ keys.update(range(start, stop + 1)) results[name] = [key for key in sorted(keys) \ if key in all_keys] + if len(results[name]) == 0: + del results[name] except ValueError: raise FormatError('Invalid sequence specification: %s' % line.rstrip()) @@ -993,7 +995,7 @@ if key - 1 == prev: if not completing: completing = True - fw.write('-') + f.write('-') elif completing: completing = False f.write('%s %s' % (prev, key)) @@ -1055,7 +1057,7 @@ del key_list[key_list.index(key)] for sequence in pending_sequences: if sequence not in all_sequences: - all_sequences[sequence] = [new_key] + all_sequences[sequence] = [key] self.set_sequences(all_sequences) Index: test_mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- test_mailbox.py 16 Aug 2005 23:38:11 -0000 1.8 +++ test_mailbox.py 21 Aug 2005 21:17:53 -0000 1.9 @@ -378,6 +378,14 @@ # Write changes to disk self._test_flush_or_close(self._box.flush) + def test_lock_unlock(self): + # Lock and unlock the mailbox + self.assert_(not os.path.exists(self._get_lock_path())) + self._box.lock() + self.assert_(os.path.exists(self._get_lock_path())) + self._box.unlock() + self.assert_(not os.path.exists(self._get_lock_path())) + def test_close(self): # Close mailbox and flush changes to disk self._test_flush_or_close(self._box.close) @@ -405,9 +413,47 @@ self.assertRaises(TypeError, lambda: self._box._dump_message(None, output)) + def _get_lock_path(self): + # Return the path of the dot lock file. May be overridden. + return self._path + '.lock' + + +class TestMailboxSuperclass(TestBase): + + def test_notimplemented(self): + # Test that all Mailbox methods raise NotImplementedException. + box = mailbox.Mailbox('path') + self.assertRaises(NotImplementedError, lambda: box.add('')) + self.assertRaises(NotImplementedError, lambda: box.remove('')) + self.assertRaises(NotImplementedError, lambda: box.__delitem__('')) + self.assertRaises(NotImplementedError, lambda: box.discard('')) + self.assertRaises(NotImplementedError, lambda: box.__setitem__('', '')) + self.assertRaises(NotImplementedError, lambda: box.iterkeys()) + self.assertRaises(NotImplementedError, lambda: box.keys()) + self.assertRaises(NotImplementedError, lambda: box.itervalues().next()) + self.assertRaises(NotImplementedError, lambda: box.__iter__().next()) + self.assertRaises(NotImplementedError, lambda: box.values()) + self.assertRaises(NotImplementedError, lambda: box.iteritems().next()) + self.assertRaises(NotImplementedError, lambda: box.items()) + self.assertRaises(NotImplementedError, lambda: box.get('')) + self.assertRaises(NotImplementedError, lambda: box.__getitem__('')) + self.assertRaises(NotImplementedError, lambda: box.get_message('')) + self.assertRaises(NotImplementedError, lambda: box.get_string('')) + self.assertRaises(NotImplementedError, lambda: box.get_file('')) + self.assertRaises(NotImplementedError, lambda: box.has_key('')) + self.assertRaises(NotImplementedError, lambda: box.__contains__('')) + self.assertRaises(NotImplementedError, lambda: box.__len__()) + self.assertRaises(NotImplementedError, lambda: box.clear()) + self.assertRaises(NotImplementedError, lambda: box.pop('')) + self.assertRaises(NotImplementedError, lambda: box.popitem()) + self.assertRaises(NotImplementedError, lambda: box.update((('', ''),))) + self.assertRaises(NotImplementedError, lambda: box.flush()) + self.assertRaises(NotImplementedError, lambda: box.lock()) + self.assertRaises(NotImplementedError, lambda: box.unlock()) + self.assertRaises(NotImplementedError, lambda: box.close()) + class TestMaildir(TestMailbox): - # XXX: factor some of this out into superclasses _factory = lambda self, path, factory=None: mailbox.Maildir(path, factory) @@ -613,6 +659,11 @@ self.assertRaises(KeyError, lambda: self._box._lookup(key0)) self.assert_(self._box._toc == {}) + def test_lock_unlock(self): + # Lock and unlock the mailbox. For Maildir, this does nothing. + self._box.lock() + self._box.unlock() + class _TestMboxMMDF(TestMailbox): @@ -675,11 +726,119 @@ _factory = lambda self, path, factory=None: mailbox.MH(path, factory) + def test_list_folders(self): + # List folders + self._box.add_folder('one') + self._box.add_folder('two') + self._box.add_folder('three') + self.assert_(len(self._box.list_folders()) == 3) + self.assert_(set(self._box.list_folders()) == + set(('one', 'two', 'three'))) + + def test_get_folder(self): + # Open folders + self._box.add_folder('foo.bar') + folder0 = self._box.get_folder('foo.bar') + folder0.add(self._template % 'bar') + self.assert_(os.path.isdir(os.path.join(self._path, 'foo.bar'))) + folder1 = self._box.get_folder('foo.bar') + self.assert_(folder1.get_string(folder1.keys()[0]) == \ + self._template % 'bar') + + def test_add_and_remove_folders(self): + # Delete folders + self._box.add_folder('one') + self._box.add_folder('two') + self.assert_(len(self._box.list_folders()) == 2) + self.assert_(set(self._box.list_folders()) == set(('one', 'two'))) + self._box.remove_folder('one') + self.assert_(len(self._box.list_folders()) == 1) + self.assert_(set(self._box.list_folders()) == set(('two',))) + self._box.add_folder('three') + self.assert_(len(self._box.list_folders()) == 2) + self.assert_(set(self._box.list_folders()) == set(('two', 'three'))) + self._box.remove_folder('three') + self.assert_(len(self._box.list_folders()) == 1) + self.assert_(set(self._box.list_folders()) == set(('two',))) + self._box.remove_folder('two') + self.assert_(len(self._box.list_folders()) == 0) + self.assert_(self._box.list_folders() == []) + + def test_sequences(self): + # Get and set sequences + self.assert_(self._box.get_sequences() == {}) + msg0 = mailbox.MHMessage(self._template % 0) + msg0.add_sequence('foo') + key0 = self._box.add(msg0) + self.assert_(self._box.get_sequences() == {'foo':[key0]}) + msg1 = mailbox.MHMessage(self._template % 1) + msg1.set_sequences(['bar', 'replied', 'foo']) + key1 = self._box.add(msg1) + self.assert_(self._box.get_sequences() == + {'foo':[key0, key1], 'bar':[key1], 'replied':[key1]}) + msg0.set_sequences(['flagged']) + self._box[key0] = msg0 + self.assert_(self._box.get_sequences() == + {'foo':[key1], 'bar':[key1], 'replied':[key1], + 'flagged':[key0]}) + self._box.remove(key1) + self.assert_(self._box.get_sequences() == {'flagged':[key0]}) + + def test_pack(self): + # Pack the contents of the mailbox + msg0 = mailbox.MHMessage(self._template % 0) + msg1 = mailbox.MHMessage(self._template % 1) + msg2 = mailbox.MHMessage(self._template % 2) + msg3 = mailbox.MHMessage(self._template % 3) + msg0.set_sequences(['foo', 'unseen']) + msg1.set_sequences(['foo']) + msg2.set_sequences(['foo', 'flagged']) + msg3.set_sequences(['foo', 'bar', 'replied']) + key0 = self._box.add(msg0) + key1 = self._box.add(msg1) + key2 = self._box.add(msg2) + key3 = self._box.add(msg3) + self.assert_(self._box.get_sequences() == + {'foo':[key0,key1,key2,key3], 'unseen':[key0], + 'flagged':[key2], 'bar':[key3], 'replied':[key3]}) + self._box.remove(key2) + self.assert_(self._box.get_sequences() == + {'foo':[key0,key1,key3], 'unseen':[key0], 'bar':[key3], + 'replied':[key3]}) + self._box.pack() + self.assert_(self._box.keys() == [1, 2, 3]) + key0 = key0 + key1 = key0 + 1 + key2 = key1 + 1 + self.assert_(self._box.get_sequences() == + {'foo':[1, 2, 3], 'unseen':[1], 'bar':[3], 'replied':[3]}) + + def _get_lock_path(self): + return os.path.join(self._path, '.mh_sequences.lock') + class TestBabyl(TestMailbox): _factory = lambda self, path, factory=None: mailbox.Babyl(path, factory) + def test_labels(self): + # Get labels from the mailbox + self.assert_(self._box.get_labels() == []) + msg0 = mailbox.BabylMessage(self._template % 0) + msg0.add_label('foo') + key0 = self._box.add(msg0) + self.assert_(self._box.get_labels() == ['foo']) + msg1 = mailbox.BabylMessage(self._template % 1) + msg1.set_labels(['bar', 'answered', 'foo']) + key1 = self._box.add(msg1) + self.assert_(set(self._box.get_labels()) == set(['foo', 'bar'])) + msg0.set_labels(['blah', 'filed']) + self._box[key0] = msg0 + self.assert_(set(self._box.get_labels()) == + set(['foo', 'bar', 'blah'])) + self._box.remove(key1) + self.assert_(set(self._box.get_labels()) == set(['blah'])) + class TestMessage(TestBase): @@ -1395,6 +1554,109 @@ 6 + 3 * len(os.linesep))) +## Start: tests from the original module (for backward compatibility). + +FROM_ = "From some.body at dummy.domain Sat Jul 24 13:43:35 2004\n" +DUMMY_MESSAGE = """\ +From: some.body at dummy.domain +To: me at my.domain +Subject: Simple Test + +This is a dummy message. +""" + +class MaildirTestCase(unittest.TestCase): + + def setUp(self): + # create a new maildir mailbox to work with: + self._dir = test_support.TESTFN + os.mkdir(self._dir) + os.mkdir(os.path.join(self._dir, "cur")) + os.mkdir(os.path.join(self._dir, "tmp")) + os.mkdir(os.path.join(self._dir, "new")) + self._counter = 1 + self._msgfiles = [] + + def tearDown(self): + map(os.unlink, self._msgfiles) + os.rmdir(os.path.join(self._dir, "cur")) + os.rmdir(os.path.join(self._dir, "tmp")) + os.rmdir(os.path.join(self._dir, "new")) + os.rmdir(self._dir) + + def createMessage(self, dir, mbox=False): + t = int(time.time() % 1000000) + pid = self._counter + self._counter += 1 + filename = os.extsep.join((str(t), str(pid), "myhostname", "mydomain")) + tmpname = os.path.join(self._dir, "tmp", filename) + newname = os.path.join(self._dir, dir, filename) + fp = open(tmpname, "w") + self._msgfiles.append(tmpname) + if mbox: + fp.write(FROM_) + fp.write(DUMMY_MESSAGE) + fp.close() + if hasattr(os, "link"): + os.link(tmpname, newname) + else: + fp = open(newname, "w") + fp.write(DUMMY_MESSAGE) + fp.close() + self._msgfiles.append(newname) + return tmpname + + def test_empty_maildir(self): + """Test an empty maildir mailbox""" + # Test for regression on bug #117490: + # Make sure the boxes attribute actually gets set. + self.mbox = mailbox.Maildir(test_support.TESTFN) + #self.assert_(hasattr(self.mbox, "boxes")) + #self.assert_(len(self.mbox.boxes) == 0) + self.assert_(self.mbox.next() is None) + self.assert_(self.mbox.next() is None) + + def test_nonempty_maildir_cur(self): + self.createMessage("cur") + self.mbox = mailbox.Maildir(test_support.TESTFN) + #self.assert_(len(self.mbox.boxes) == 1) + self.assert_(self.mbox.next() is not None) + self.assert_(self.mbox.next() is None) + self.assert_(self.mbox.next() is None) + + def test_nonempty_maildir_new(self): + self.createMessage("new") + self.mbox = mailbox.Maildir(test_support.TESTFN) + #self.assert_(len(self.mbox.boxes) == 1) + self.assert_(self.mbox.next() is not None) + self.assert_(self.mbox.next() is None) + self.assert_(self.mbox.next() is None) + + def test_nonempty_maildir_both(self): + self.createMessage("cur") + self.createMessage("new") + self.mbox = mailbox.Maildir(test_support.TESTFN) + #self.assert_(len(self.mbox.boxes) == 2) + self.assert_(self.mbox.next() is not None) + self.assert_(self.mbox.next() is not None) + self.assert_(self.mbox.next() is None) + self.assert_(self.mbox.next() is None) + + def test_unix_mbox(self): + ### should be better! + import email.Parser + fname = self.createMessage("cur", True) + n = 0 + for msg in mailbox.PortableUnixMailbox(open(fname), + email.Parser.Parser().parse): + n += 1 + self.assertEqual(msg["subject"], "Simple Test") + self.assertEqual(len(str(msg)), len(FROM_)+len(DUMMY_MESSAGE)) + self.assertEqual(n, 1) + +## End: classes from the original module (for backward compatibility). + + _sample_message = """\ Return-Path: X-Original-To: gkj+person at localhost @@ -1478,10 +1740,11 @@ def test_main(): - tests = (TestMaildir, TestMbox, TestMMDF, TestMH, TestBabyl, TestMessage, - TestMaildirMessage, TestMboxMessage, TestMHMessage, - TestBabylMessage, TestMMDFMessage, TestMessageConversion, - TestProxyFile, TestPartialFile) + tests = (TestMailboxSuperclass, TestMaildir, TestMbox, TestMMDF, TestMH, + TestBabyl, TestMessage, TestMaildirMessage, TestMboxMessage, + TestMHMessage, TestBabylMessage, TestMMDFMessage, + TestMessageConversion, TestProxyFile, TestPartialFile, + MaildirTestCase) test_support.run_unittest(*tests) From pje at users.sourceforge.net Sun Aug 21 23:49:49 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Sun, 21 Aug 2005 23:49:49 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command egg_info.py, 1.12, 1.13 Message-ID: <20050821214949.7700F1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3737/setuptools/command Modified Files: egg_info.py Log Message: Parse .svn/entries directly instead of using 'svn info' to obtain a revision number. (Christopher Lenz reported that svn info's output is different in non-English locales.) Index: egg_info.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/egg_info.py,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- egg_info.py 13 Aug 2005 23:04:08 -0000 1.12 +++ egg_info.py 21 Aug 2005 21:49:39 -0000 1.13 @@ -3,7 +3,7 @@ Create a distribution's .egg-info directory and contents""" # This module should be kept compatible with Python 2.3 -import os +import os, re from setuptools import Command from distutils.errors import * from distutils import log @@ -141,26 +141,26 @@ return safe_version(version) def get_svn_revision(self): - stdin, stdout = os.popen4("svn info -R"); stdin.close() - result = stdout.read(); stdout.close() - import re - revisions = [ - int(match.group(1)) - for match in re.finditer(r'Last Changed Rev: (\d+)', result) - ] - if not revisions: - raise DistutilsError("svn info error: %s" % result.strip()) - return str(max(revisions)) - - - - - - - - - - + revision = 0 + urlre = re.compile('url="([^"]+)"') + revre = re.compile('committed-rev="(\d+)"') + for base,dirs,files in os.walk(os.curdir): + if '.svn' not in dirs: + dirs[:] = [] + continue # no sense walking uncontrolled subdirs + dirs.remove('.svn') + f = open(os.path.join(base,'.svn','entries')) + data = f.read() + f.close() + dirurl = urlre.search(data).group(1) # get repository URL + if base==os.curdir: + base_url = dirurl+'/' # save the root url + elif not dirurl.startswith(base_url): + dirs[:] = [] + continue # not part of the same svn tree, skip it + for match in revre.finditer(data): + revision = max(revision, int(match.group(1))) + return str(revision) def write_pkg_info(cmd, basename, filename): log.info("writing %s", filename) From pje at users.sourceforge.net Mon Aug 22 00:12:23 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 00:12:23 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.txt, 1.10, 1.11 Message-ID: <20050821221223.748081E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9532 Modified Files: pkg_resources.txt Log Message: Thanks to Richard Jones, we no longer need to fake out PyPI with a '.zip' extension for eggs. Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- pkg_resources.txt 14 Aug 2005 17:48:07 -0000 1.10 +++ pkg_resources.txt 21 Aug 2005 22:12:12 -0000 1.11 @@ -625,7 +625,7 @@ ``__str__()`` The string form of an ``EntryPoint`` is a string that could be passed to - ``EntryPoint.parse()`` to yield an equivalent ``EntryPoint``. + ``EntryPoint.parse()`` to produce an equivalent ``EntryPoint``. ``Distribution`` Objects From pje at users.sourceforge.net Mon Aug 22 00:12:24 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 00:12:24 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command upload.py, 1.2, 1.3 Message-ID: <20050821221224.0FE381E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9532/setuptools/command Modified Files: upload.py Log Message: Thanks to Richard Jones, we no longer need to fake out PyPI with a '.zip' extension for eggs. Index: upload.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/upload.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- upload.py 9 Jul 2005 04:26:21 -0000 1.2 +++ upload.py 21 Aug 2005 22:12:12 -0000 1.3 @@ -73,12 +73,9 @@ # Fill in the data content = open(filename,'rb').read() basename = os.path.basename(filename) - if basename.endswith('.egg'): - basename += '.zip' comment = '' - if command=='bdist_egg': - command='sdist' - comment='Binary egg for use with setuptools' + if command=='bdist_egg' and self.distribution.has_ext_modules(): + comment = "built on %s" % platform.platform(terse=1) data = { ':action':'file_upload', 'protcol_version':'1', From pje at users.sourceforge.net Mon Aug 22 01:00:08 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 01:00:08 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command build_ext.py, 1.2, 1.3 Message-ID: <20050821230008.3E6DA1E4009@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19257/setuptools/command Modified Files: build_ext.py Log Message: Make "build_ext --inplace" work sanely w/multiple Python versions and platforms, by ensuring that the in-place extensions are the right ones for the currently-running Python, even if they are newer than their sources. (This, like so many other setuptools fixes and enhancements, should probably be backported into the distutils as well, although it would have to be implemented a bit differently.) Index: build_ext.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/build_ext.py,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- build_ext.py 5 Apr 2004 19:54:44 -0000 1.2 +++ build_ext.py 21 Aug 2005 22:59:57 -0000 1.3 @@ -1,6 +1,41 @@ # Attempt to use Pyrex for building extensions, if available try: - from Pyrex.Distutils.build_ext import build_ext + from Pyrex.Distutils.build_ext import build_ext as _build_ext except ImportError: - from distutils.command.build_ext import build_ext + from distutils.command.build_ext import build_ext as _build_ext + +import os +from distutils.file_util import copy_file + +class build_ext(_build_ext): + + def run(self): + """Build extensions in build directory, then copy if --inplace""" + old_inplace, self.inplace = self.inplace, 0 + _build_ext.run(self) + self.inplace = old_inplace + if old_inplace: + self.copy_extensions_to_source() + + def copy_extensions_to_source(self): + build_py = self.get_finalized_command('build_py') + for ext in self.extensions: + fullname = ext.name + modpath = fullname.split('.') + package = '.'.join(modpath[:-1]) + base = modpath[-1] + package_dir = build_py.get_package_dir(package) + dest_filename = os.path.join(package_dir, + self.get_ext_filename(base)) + src_filename = os.path.join(self.build_lib, + self.get_ext_filename(fullname)) + + # Always copy, even if source is older than destination, to ensure + # that the right extensions for the current Python/platform are + # used. + copy_file( + src_filename, dest_filename, verbose=self.verbose, + dry_run=self.dry_run + ) + From pje at users.sourceforge.net Mon Aug 22 01:33:52 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 01:33:52 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command bdist_rpm.py, NONE, 1.1 __init__.py, 1.8, 1.9 egg_info.py, 1.13, 1.14 Message-ID: <20050821233352.621FD1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27590/setuptools/command Modified Files: __init__.py egg_info.py Added Files: bdist_rpm.py Log Message: Fix problem w/bdist_rpm and setuptools, reported by Walter Doerwald. I was trying to have setuptools fix distutils' broken filename handling that assumes people haven't put punctuation in their distribution names, including '-' (which prevents unambiguous parsing of distribution names). However, bdist_rpm's attempt to guess a source distribution's filename isn't compatible with this fix, without making other changes. I decided therefore to drop the fixes for the sake of backward compatibility, but monkeypatch bdist_rpm so that it runs "egg_info" first, to ensure that any --tag-svn-revision or other tagging options take effect. --- NEW FILE: bdist_rpm.py --- # This is just a kludge so that bdist_rpm doesn't guess wrong about the # distribution name and version, if the egg_info command is going to alter them from distutils.command.bdist_rpm import bdist_rpm as _bdist_rpm class bdist_rpm(_bdist_rpm): def run(self): self.run_command('egg_info') # ensure distro name is up-to-date _bdist_rpm.run(self) Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/__init__.py,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- __init__.py 6 Aug 2005 19:29:49 -0000 1.8 +++ __init__.py 21 Aug 2005 23:33:39 -0000 1.9 @@ -1,5 +1,5 @@ __all__ = [ - 'alias', 'bdist_egg', 'build_ext', 'build_py', 'develop', + 'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop', 'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts', 'sdist', 'setopt', 'test', 'upload', ] Index: egg_info.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/egg_info.py,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- egg_info.py 21 Aug 2005 21:49:39 -0000 1.13 +++ egg_info.py 21 Aug 2005 23:33:39 -0000 1.14 @@ -60,13 +60,13 @@ self.ensure_dirname('egg_base') self.egg_info = os.path.join(self.egg_base, self.egg_name+'.egg-info') - # Set package version and name for the benefit of dumber commands - # (e.g. sdist, bdist_wininst, etc.) We escape '-' so filenames will - # be more machine-parseable. + # Set package version for the benefit of dumber commands + # (e.g. sdist, bdist_wininst, etc.) # - metadata = self.distribution.metadata - metadata.version = self.egg_version.replace('-','_') - metadata.name = self.egg_name.replace('-','_') + self.distribution.metadata.version = self.egg_version + + + From pje at users.sourceforge.net Mon Aug 22 01:33:52 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 01:33:52 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools.egg-info entry_points.txt, 1.4, 1.5 Message-ID: <20050821233352.DCAB61E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27590/setuptools.egg-info Modified Files: entry_points.txt Log Message: Fix problem w/bdist_rpm and setuptools, reported by Walter Doerwald. I was trying to have setuptools fix distutils' broken filename handling that assumes people haven't put punctuation in their distribution names, including '-' (which prevents unambiguous parsing of distribution names). However, bdist_rpm's attempt to guess a source distribution's filename isn't compatible with this fix, without making other changes. I decided therefore to drop the fixes for the sake of backward compatibility, but monkeypatch bdist_rpm so that it runs "egg_info" first, to ensure that any --tag-svn-revision or other tagging options take effect. Index: entry_points.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info/entry_points.txt,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- entry_points.txt 6 Aug 2005 21:17:50 -0000 1.4 +++ entry_points.txt 21 Aug 2005 23:33:40 -0000 1.5 @@ -17,6 +17,7 @@ depends.txt = setuptools.command.egg_info:warn_depends_obsolete [distutils.commands] +bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm rotate = setuptools.command.rotate:rotate develop = setuptools.command.develop:develop setopt = setuptools.command.setopt:setopt From pje at users.sourceforge.net Mon Aug 22 01:56:05 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 01:56:05 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools ez_setup.py, 1.21, 1.22 Message-ID: <20050821235605.2AA3D1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31764 Modified Files: ez_setup.py Log Message: Display a download warning in ez_setup, so that people won't be caught off-guard by the setuptools download (which only occurs if setuptools isn't locally available, of course). Index: ez_setup.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/ez_setup.py,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- ez_setup.py 18 Jul 2005 02:06:15 -0000 1.21 +++ ez_setup.py 21 Aug 2005 23:55:54 -0000 1.22 @@ -40,18 +40,19 @@ def use_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir + version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, + download_delay=15 ): """Automatically find/download setuptools and make it available on sys.path `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where setuptools will be downloaded, if - it is not already available. - - If an older version of setuptools is installed, this will print a message - to ``sys.stderr`` and raise SystemExit in an attempt to abort the calling - script. + it is not already available. If `download_delay` is specified, it should + be the number of seconds that will be paused before initiating a download, + should one be required. If an older version of setuptools is installed, + this routine will print a message to ``sys.stderr`` and raise SystemExit in + an attempt to abort the calling script. """ try: import setuptools @@ -61,9 +62,8 @@ "remove it from your system entirely before rerunning this script." ) sys.exit(2) - except ImportError: - egg = download_setuptools(version, download_base, to_dir) + egg = download_setuptools(version, download_base, to_dir, dl_delay) sys.path.insert(0, egg) import setuptools; setuptools.bootstrap_install_from = egg @@ -81,46 +81,46 @@ sys.exit(2) def download_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir + version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, + delay = 15 ): """Download setuptools from a specified location and return its filename `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. + `delay` is the number of seconds to pause before an actual download attempt. """ import urllib2, shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) - url = download_base + egg_name + '.zip' # XXX + url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) src = dst = None - if not os.path.exists(saveto): # Avoid repeated downloads try: from distutils import log + if delay: + log.warn(""" +--------------------------------------------------------------------------- +This script requires setuptools version %s to run (even to display +help). I will attempt to download it for you from %s, but +you may need to enable firewall access for this script first. +I will start the download in %d seconds. +---------------------------------------------------------------------------""", + version, download_base, delay + ) + from time import sleep; sleep(delay) log.warn("Downloading %s", url) src = urllib2.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = src.read() - dst = open(saveto,"wb") - dst.write(data) + dst = open(saveto,"wb"); dst.write(data) finally: if src: src.close() if dst: dst.close() - return os.path.realpath(saveto) - - - - - - - - - - def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" From pje at users.sourceforge.net Mon Aug 22 02:32:59 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 02:32:59 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command build_ext.py, 1.3, 1.4 Message-ID: <20050822003259.372BC1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8139/setuptools/command Modified Files: build_ext.py Log Message: Fix a problem running build_ext -i w/no extensions. Index: build_ext.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/build_ext.py,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- build_ext.py 21 Aug 2005 22:59:57 -0000 1.3 +++ build_ext.py 22 Aug 2005 00:32:48 -0000 1.4 @@ -20,7 +20,7 @@ def copy_extensions_to_source(self): build_py = self.get_finalized_command('build_py') - for ext in self.extensions: + for ext in self.extensions or (): fullname = ext.name modpath = fullname.split('.') package = '.'.join(modpath[:-1]) From pje at users.sourceforge.net Mon Aug 22 02:35:58 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 02:35:58 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools ez_setup.py, 1.22, 1.23 Message-ID: <20050822003558.BABD31E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8313 Modified Files: ez_setup.py Log Message: Add hardcoded md5 checking to ez_setup. Also, don't delay and display banner if ez_setup is run as a command-line script, since its whole purpose in that case is to download setuptools. Running "ez_setup.py --md5update FILE [FILE...]" will update the internal md5 checksum dictionary with new or changed distributions. You should only do this if you are a setuptools maintainer, however! Index: ez_setup.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/ez_setup.py,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- ez_setup.py 21 Aug 2005 23:55:54 -0000 1.22 +++ ez_setup.py 22 Aug 2005 00:35:47 -0000 1.23 @@ -13,27 +13,27 @@ This file can also be run as a script to install or upgrade setuptools. """ - DEFAULT_VERSION = "0.6a0" DEFAULT_URL = "http://www.python.org/packages/source/s/setuptools/" -import sys, os - - - - - - - - - - - - - - +md5_data = { + 'setuptools-0.5a13-py2.3.egg': '85edcf0ef39bab66e130d3f38f578c86', + 'setuptools-0.5a13-py2.4.egg': 'ede4be600e3890e06d4ee5e0148e092a', +} +import sys, os +def _validate_md5(egg_name, data): + if egg_name in md5_data: + from md5 import md5 + digest = md5(data).hexdigest() + if digest != md5_data[egg_name]: + print >>sys.stderr, ( + "md5 validation of %s failed! (Possible download problem?)" + % egg_name + ) + sys.exit(2) + return data @@ -103,7 +103,8 @@ log.warn(""" --------------------------------------------------------------------------- This script requires setuptools version %s to run (even to display -help). I will attempt to download it for you from %s, but +help). I will attempt to download it for you (from +%s), but you may need to enable firewall access for this script first. I will start the download in %d seconds. ---------------------------------------------------------------------------""", @@ -114,7 +115,7 @@ src = urllib2.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. - data = src.read() + data = _validate_md5(egg_name, src.read()) dst = open(saveto,"wb"); dst.write(data) finally: if src: src.close() @@ -130,7 +131,7 @@ import tempfile, shutil tmpdir = tempfile.mkdtemp(prefix="easy_install-") try: - egg = download_setuptools(version, to_dir=tmpdir) + egg = download_setuptools(version, to_dir=tmpdir, delay=0) sys.path.insert(0,egg) from setuptools.command.easy_install import main main(list(argv)+[egg]) @@ -159,6 +160,47 @@ else: print "Setuptools version",version,"or greater has been installed." print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' + + + +def update_md5(filenames): + """Update our built-in md5 registry""" + + import re + from md5 import md5 + + for name in filenames: + base = os.path.basename(name) + f = open(name,'rb') + md5_data[base] = md5(f.read()).hexdigest() + f.close() + + data = [" %r: %r,\n" % it for it in md5_data.items()] + data.sort() + repl = "".join(data) + + import inspect + srcfile = inspect.getsourcefile(sys.modules[__name__]) + f = open(srcfile); src = f.read(); f.close() + + match = re.search("\nmd5_data = {\n([^}]+)}", src) + if not match: + print >>sys.stderr, "Internal error!" + sys.exit(2) + + src = src[:match.start(1)] + repl + src[match.end(1):] + f = open(srcfile,'w') + f.write(src) + f.close() + + if __name__=='__main__': - main(sys.argv[1:]) + if len(sys.argv)>2 and sys.argv[1]=='--md5update': + update_md5(sys.argv[2:]) + else: + main(sys.argv[1:]) + + + + From pje at users.sourceforge.net Mon Aug 22 03:13:24 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 03:13:24 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools package_index.py, 1.18, 1.19 Message-ID: <20050822011324.C581D1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16741/setuptools Modified Files: package_index.py Log Message: Implemented md5 validation for PyPI and for URLs with a "#md5=..." anchor. Index: package_index.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/package_index.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- package_index.py 14 Aug 2005 01:45:38 -0000 1.18 +++ package_index.py 22 Aug 2005 01:13:14 -0000 1.19 @@ -4,10 +4,16 @@ from pkg_resources import * from distutils import log from distutils.errors import DistutilsError +from md5 import md5 EGG_FRAGMENT = re.compile('^egg=(\\w+(-\\w+)?)$') HREF = re.compile("""href\\s*=\\s*['"]?([^'"> ]+)""", re.I) -# this is here to fix emacs' cruddy broken syntax highlighting: ' +# this is here to fix emacs' cruddy broken syntax highlighting + +PYPI_MD5 = re.compile( + '([^<]+)\n\s+\\(md5\\)' +) URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):',re.I).match EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split() @@ -33,18 +39,12 @@ return base,py_ver - - - - - - def distros_for_url(url, metadata=None): """Yield egg or source distribution objects that might be found at a URL""" scheme, server, path, parameters, query, fragment = urlparse.urlparse(url) base = urllib2.unquote(path.split('/')[-1]) - dists = distros_for_location(url, base, metadata) + dists = distros_for_location(url, base, metadata) if fragment and not dists: match = EGG_FRAGMENT.match(fragment) if match: @@ -59,7 +59,7 @@ if basename.endswith('.egg.zip'): basename = basename[:-4] # strip the .zip - if basename.endswith('.egg'): # only one, unambiguous interpretation + if basename.endswith('.egg'): # only one, unambiguous interpretation return [Distribution.from_location(location, basename, metadata)] if basename.endswith('.exe'): @@ -174,7 +174,7 @@ page = f.read() f.close() if url.startswith(self.index_url): - self.process_index(url, page) + page = self.process_index(url, page) for match in HREF.finditer(page): link = urlparse.urljoin(base, match.group(1)) @@ -234,9 +234,9 @@ # Process the found URL self.scan_url(urlparse.urljoin(url, match.group(1))) - - - + return PYPI_MD5.sub( + lambda m: '%s' % m.group(1,3,2), page + ) @@ -270,16 +270,16 @@ self.debug("%s does not match %s", requirement, dist) return super(PackageIndex, self).obtain(requirement,installer) - - - - - - - - - - + def check_md5(self, cs, info, filename, tfp): + if re.match('md5=[0-9a-f]{32}$', info): + self.debug("Validating md5 checksum for %s", filename) + if cs.hexdigest()<>info[4:]: + tfp.close() + os.unlink(filename) + raise DistutilsError( + "MD5 validation failed for "+os.path.basename(filename)+ + "; possible download problem?" + ) @@ -348,7 +348,7 @@ if dist in req and (dist.precedence<=SOURCE_DIST or not source): self.info("Best match: %s", dist) return self.download(dist.location, tmpdir) - + if force_scan: self.find_packages(requirement) dist = find(requirement) @@ -372,35 +372,35 @@ def _download_to(self, url, filename): self.info("Downloading %s", url) # Download the file - fp, tfp = None, None + fp, tfp, info = None, None, None try: - url = url.split('#', 1)[0] + if '#' in url: + url, info = url.split('#', 1) fp = self.open_url(url) if isinstance(fp, urllib2.HTTPError): raise DistutilsError( "Can't download %s: %s %s" % (url, fp.code,fp.msg) ) - + cs = md5() headers = fp.info() blocknum = 0 bs = self.dl_blocksize size = -1 - if "content-length" in headers: size = int(headers["Content-Length"]) self.reporthook(url, filename, blocknum, bs, size) - tfp = open(filename,'wb') while True: block = fp.read(bs) if block: + cs.update(block) tfp.write(block) blocknum += 1 self.reporthook(url, filename, blocknum, bs, size) else: break + if info: self.check_md5(cs, info, filename, tfp) return headers - finally: if fp: fp.close() if tfp: tfp.close() From pje at users.sourceforge.net Mon Aug 22 03:17:16 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 03:17:16 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.50, 1.51 Message-ID: <20050822011716.648C71E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17585 Modified Files: EasyInstall.txt Log Message: Add release note about the new MD5 validation feature. Index: EasyInstall.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v retrieving revision 1.50 retrieving revision 1.51 diff -u -d -r1.50 -r1.51 --- EasyInstall.txt 6 Aug 2005 17:54:55 -0000 1.50 +++ EasyInstall.txt 22 Aug 2005 01:17:05 -0000 1.51 @@ -678,6 +678,9 @@ rate don't expect it to work with all packages. 0.6a1 + * EasyInstall now does MD5 validation of downloads from PyPI, or from any link + that has an "#md5=..." trailer with a 32-digit lowercase hex md5 digest. + * Added support for handling MacOS platform information in ``.egg`` filenames, based on a contribution by Kevin Dangoor. You may wish to delete and reinstall any eggs whose filename includes "darwin" and "Power_Macintosh", From pje at users.sourceforge.net Mon Aug 22 05:15:08 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 05:15:08 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools.egg-info entry_points.txt, 1.5, 1.6 Message-ID: <20050822031508.EBD771E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4502/setuptools.egg-info Modified Files: entry_points.txt Log Message: Add detailed instructions for non-root installation using PYTHONHOME. Index: entry_points.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.egg-info/entry_points.txt,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- entry_points.txt 21 Aug 2005 23:33:40 -0000 1.5 +++ entry_points.txt 22 Aug 2005 03:14:58 -0000 1.6 @@ -21,7 +21,6 @@ rotate = setuptools.command.rotate:rotate develop = setuptools.command.develop:develop setopt = setuptools.command.setopt:setopt -build_py = setuptools.command.build_py:build_py saveopts = setuptools.command.saveopts:saveopts egg_info = setuptools.command.egg_info:egg_info upload = setuptools.command.upload:upload From pje at users.sourceforge.net Mon Aug 22 05:15:09 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 05:15:09 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.51, 1.52 Message-ID: <20050822031509.2F1801E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4502 Modified Files: EasyInstall.txt Log Message: Add detailed instructions for non-root installation using PYTHONHOME. Index: EasyInstall.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v retrieving revision 1.51 retrieving revision 1.52 diff -u -d -r1.51 -r1.52 --- EasyInstall.txt 22 Aug 2005 01:17:05 -0000 1.51 +++ EasyInstall.txt 22 Aug 2005 03:14:58 -0000 1.52 @@ -30,7 +30,9 @@ Download `ez_setup.py `_, and run it; this will download and install the appropriate ``setuptools`` egg for -your Python version. +your Python version. (Note: if you do not have write access to your computer's +``site-packages`` directory, please see the section below on `Non-Root +Installation`_ for more detailed instructions.) You may receive a message telling you about an obsolete version of setuptools being present; if so, you must be sure to delete it entirely, along @@ -660,6 +662,67 @@ Python packages via EasyInstall. +Non-Root Installation +--------------------- + +If you want to use EasyInstall on a computer where you do not have write access +to Python's main ``site-packages`` directory, you may need to set up an +alternate ``PYTHONHOME`` location, which allows Python to read a second +``site-packages`` directory. + +If you are on a Mac OS X machine, you should just use the +``~/Library/Python2.x/site-packages`` directory (replacing the ``x`` with the +appropriate number). Just make sure the directory exists, and use it as your +installation location for all packages (including EasyInstall itself). You +do not need to set up a ``PYTHONHOME``, so you can skip the rest of this +section, unless you want to be able to override system-installed packages. + +If you are on a Linux, BSD, Cygwin, or other similar Unix-like operating +system, you should create a ``~/lib/python2.x/site-packages`` directory +instead. You will need to know your Python version's ``sys.prefix`` and +``sys.exec_prefix``, which you can find out by running:: + + python -c "import sys; print sys.prefix; print sys.exec_prefix" + +(Replace "python" with the right path or version for your platform.) + +Assuming your ``sys.prefix`` is ``/usr/local``, and you are working with +Python 2.4, you need to then perform the following steps (possibly making +adjustments for the tools available on your platform):: + + cd /usr/local/lib/python2.4 + find . -name lib-dynload -prune -o -name site-packages -prune -o \ + -print >~/pyfiles + zip -r ~/lib/python24.zip . -i@$HOME/pyfiles + rm ~/pyfiles + mkdir -p ~/lib/python2.4/site-packages + ln -s /usr/local/lib/python2.4/lib-* ~/lib/python2.4/ + + echo "[install]" >>~/.pydistutils.cfg + echo "prefix=$HOME" >>~/.pydistutils.cfg + echo "exec_prefix=$HOME" >>~/.pydistutils.cfg + +Note that all of the paths above should be based on ``sys.prefix``, not +``sys.exec_prefix`` (unless they're the same). Once these one-time steps are +completed, you can set your ``PYTHONHOME`` with:: + + export PYTHONHOME=$HOME:/old_exec_prefix + +replacing ``/old_exec_prefix`` with the original value of ``sys.exec_prefix``. + +The downside to this setup is that it can take up as much as 10 megabytes of +disk space to store the zipped standard library. The upside, however, is that +Python usually starts much faster with a zipped standard library! And of +course, you'll effectively have complete control over your own Python +installation, without needing to convince a system administrator to install +packages for you. + +Note that if you were previously setting a ``PYTHONPATH`` and/or had other +special configuration options in your ``~/.pydistutils.cfg``, you may need to +remove these settings, after relocating any older installed modules to your +new ``~/lib/python2.x`` directory. + + Release Notes/Change History ============================ From pje at users.sourceforge.net Mon Aug 22 05:28:38 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 05:28:38 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.52, 1.53 ez_setup.py, 1.23, 1.24 pkg_resources.txt, 1.11, 1.12 setuptools.txt, 1.31, 1.32 Message-ID: <20050822032838.A807E1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6451 Modified Files: EasyInstall.txt ez_setup.py pkg_resources.txt setuptools.txt Log Message: More documentation enhancements. Index: EasyInstall.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v retrieving revision 1.52 retrieving revision 1.53 diff -u -d -r1.52 -r1.53 --- EasyInstall.txt 22 Aug 2005 03:14:58 -0000 1.52 +++ EasyInstall.txt 22 Aug 2005 03:28:27 -0000 1.53 @@ -28,11 +28,19 @@ Installing "Easy Install" ------------------------- +If you are behind an NTLM-based firewall that prevents Python programs from +accessing the net directly, you may wish to first install and use the `APS +proxy server `_, which lets you get past such firewalls +in the same way that your web browser(s) do. + +If you do not have write access to your computer's ``site-packages`` directory, +please also see the section below on `Non-Root Installation`_ for more detailed +instructions on pre-configuring your system for the best usability with +EasyInstall, then return here for the remaining steps. + Download `ez_setup.py `_, and run it; this will download and install the appropriate ``setuptools`` egg for -your Python version. (Note: if you do not have write access to your computer's -``site-packages`` directory, please see the section below on `Non-Root -Installation`_ for more detailed instructions.) +your Python version. You may receive a message telling you about an obsolete version of setuptools being present; if so, you must be sure to delete it entirely, along Index: ez_setup.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/ez_setup.py,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- ez_setup.py 22 Aug 2005 00:35:47 -0000 1.23 +++ ez_setup.py 22 Aug 2005 03:28:27 -0000 1.24 @@ -109,8 +109,7 @@ I will start the download in %d seconds. ---------------------------------------------------------------------------""", version, download_base, delay - ) - from time import sleep; sleep(delay) + ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) src = urllib2.urlopen(url) # Read/write all in one block, so we don't create a corrupt file Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- pkg_resources.txt 21 Aug 2005 22:12:12 -0000 1.11 +++ pkg_resources.txt 22 Aug 2005 03:28:27 -0000 1.12 @@ -18,7 +18,8 @@ Overview -------- -XXX TBD +This section isn't written yet. For now, please check out the extensive `API +Reference`_ below. ----------------- @@ -43,6 +44,8 @@ Extended Discovery and Installation Supporting Custom PEP 302 Implementations +For now, please check out the extensive `API Reference`_ below. + ------------- API Reference Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- setuptools.txt 14 Aug 2005 01:45:37 -0000 1.31 +++ setuptools.txt 22 Aug 2005 03:28:27 -0000 1.32 @@ -69,12 +69,21 @@ Installing ``setuptools`` ========================= -Download `ez_setup.py`_ and run it; this will download and install the -appropriate egg for your Python version. (Note: if you are behind -an NTLM-based firewall that prevents Python programs from accessing the net -directly, you may wish to install and use the `APS proxy server -`_, which lets you get past such firewalls in the same -way that your web browser(s) do.) +If you are behind an NTLM-based firewall that prevents Python programs from +accessing the net directly, you may wish to first install and use the `APS +proxy server `_, which lets you get past such firewalls +in the same way that your web browser(s) do. + +If you do not have write access to your computer's ``site-packages`` directory, +please also see the EasyInstall documentation on `Non-Root Installation`_ for +more detailed instructions on pre-configuring your system for the best +usability with setuptools and EasyInstall, then return here for the remaining +steps. + +.. _Non-Root Installation: http://peak.telecommunity.com/DevCenter/EasyInstall#non-root-installation + +To install setuptools, first download `ez_setup.py`_ and run it; this will +automatically download and install the appropriate egg for your Python version. .. _ez_setup.py: `bootstrap module`_ @@ -90,15 +99,18 @@ You can then install it using the usual "setup.py install" incantation. -Note that ``setuptools`` *must* be installed as an egg directory; it will not +(Note that ``setuptools`` *must* be installed as an egg directory; it will not operate correctly otherwise. If you are unable to install to a valid -``site-packages`` directory (e.g. a "non-root install"), you will therefore -need to manually add the setuptools egg to your ``PYTHONPATH``. (You won't -need to do this for every egg you install, because the ``pkg_resources`` module -can automatically find eggs and add them to ``sys.path`` at runtime. It's just -that the ``setuptools`` egg contains ``pkg_resources`` and therefore has to -be manually bootstrapped if you can't install it to a ``site-packages`` -directory.) +``site-packages`` directory (e.g. a "non-root install" that doesn't conform +to the `Non-Root Installation`_ procedure), you will therefore need to manually +add the setuptools egg to your ``PYTHONPATH``. You won't need to do this for +every egg you install, because the ``pkg_resources`` module can automatically +find eggs and add them to ``sys.path`` at runtime. It's just that the +``setuptools`` egg contains the ``pkg_resources`` runtime, and therefore has to +be manually bootstrapped if you can't install it to a valid ``site-packages`` +directory. However, if you are installing as root or you followed the +`Non-Root Installation`_ procedure, you shouldn't have to worry about any of +this.) Basic Use From pje at users.sourceforge.net Mon Aug 22 05:40:31 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 05:40:31 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools pkg_resources.txt, 1.12, 1.13 setuptools.txt, 1.32, 1.33 Message-ID: <20050822034031.9A0DE1E4004@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7825 Modified Files: pkg_resources.txt setuptools.txt Log Message: Give pkg_resources its own revision history; add some notes on today's fixes and enhancements. Index: pkg_resources.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/pkg_resources.txt,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- pkg_resources.txt 22 Aug 2005 03:28:27 -0000 1.12 +++ pkg_resources.txt 22 Aug 2005 03:40:20 -0000 1.13 @@ -1409,3 +1409,149 @@ reflect the platform's case-sensitivity, so there is always the possibility of two apparently-different paths being equal on such platforms. + +---------------------------- +Release Notes/Change History +---------------------------- + +0.6a1 + * Enhanced performance of ``require()`` and related operations when all + requirements are already in the working set, and enhanced performance of + directory scanning for distributions. + + * Fixed some problems using ``pkg_resources`` w/PEP 302 loaders other than + ``zipimport``, and the previously-broken "eager resource" support. + + * Fixed ``pkg_resources.resource_exists()`` not working correctly, along with + some other resource API bugs. + + * Many API changes and enhancements: + + * Added ``EntryPoint``, ``get_entry_map``, ``load_entry_point``, and + ``get_entry_info`` APIs for dynamic plugin discovery. + + * ``list_resources`` is now ``resource_listdir`` (and it actually works) + + * Resource API functions like ``resource_string()`` that accepted a package + name and resource name, will now also accept a ``Requirement`` object in + place of the package name (to allow access to non-package data files in + an egg). + + * ``get_provider()`` will now accept a ``Requirement`` instance or a module + name. If it is given a ``Requirement``, it will return a corresponding + ``Distribution`` (by calling ``require()`` if a suitable distribution + isn't already in the working set), rather than returning a metadata and + resource provider for a specific module. (The difference is in how + resource paths are interpreted; supplying a module name means resources + path will be module-relative, rather than relative to the distribution's + root.) + + * ``Distribution`` objects now implement the ``IResourceProvider`` and + ``IMetadataProvider`` interfaces, so you don't need to reference the (no + longer available) ``metadata`` attribute to get at these interfaces. + + * ``Distribution`` and ``Requirement`` both have a ``project_name`` + attribute for the project name they refer to. (Previously these were + ``name`` and ``distname`` attributes.) + + * The ``path`` attribute of ``Distribution`` objects is now ``location``, + because it isn't necessarily a filesystem path (and hasn't been for some + time now). The ``location`` of ``Distribution`` objects in the filesystem + should always be normalized using ``pkg_resources.normalize_path()``; all + of the setuptools and EasyInstall code that generates distributions from + the filesystem (including ``Distribution.from_filename()``) ensure this + invariant, but if you use a more generic API like ``Distribution()`` or + ``Distribution.from_location()`` you should take care that you don't + create a distribution with an un-normalized filesystem path. + + * ``Distribution`` objects now have an ``as_requirement()`` method that + returns a ``Requirement`` for the distribution's project name and version. + + * Distribution objects no longer have an ``installed_on()`` method, and the + ``install_on()`` method is now ``activate()`` (but may go away altogether + soon). The ``depends()`` method has also been renamed to ``requires()``, + and ``InvalidOption`` is now ``UnknownExtra``. + + * ``find_distributions()`` now takes an additional argument called ``only``, + that tells it to only yield distributions whose location is the passed-in + path. (It defaults to False, so that the default behavior is unchanged.) + + * ``AvailableDistributions`` is now called ``Environment``, and the + ``get()``, ``__len__()``, and ``__contains__()`` methods were removed, + because they weren't particularly useful. ``__getitem__()`` no longer + raises ``KeyError``; it just returns an empty list if there are no + distributions for the named project. + + * The ``resolve()`` method of ``Environment`` is now a method of + ``WorkingSet`` instead, and the ``best_match()`` method now uses a working + set instead of a path list as its second argument. + + * There is a new ``pkg_resources.add_activation_listener()`` API that lets + you register a callback for notifications about distributions added to + ``sys.path`` (including the distributions already on it). This is + basically a hook for extensible applications and frameworks to be able to + search for plugin metadata in distributions added at runtime. + +0.5a13 + * Fixed a bug in resource extraction from nested packages in a zipped egg. + +0.5a12 + * Updated extraction/cache mechanism for zipped resources to avoid inter- + process and inter-thread races during extraction. The default cache + location can now be set via the ``PYTHON_EGGS_CACHE`` environment variable, + and the default Windows cache is now a ``Python-Eggs`` subdirectory of the + current user's "Application Data" directory, if the ``PYTHON_EGGS_CACHE`` + variable isn't set. + +0.5a10 + * Fix a problem with ``pkg_resources`` being confused by non-existent eggs on + ``sys.path`` (e.g. if a user deletes an egg without removing it from the + ``easy-install.pth`` file). + + * Fix a problem with "basket" support in ``pkg_resources``, where egg-finding + never actually went inside ``.egg`` files. + + * Made ``pkg_resources`` import the module you request resources from, if it's + not already imported. + +0.5a4 + * ``pkg_resources.AvailableDistributions.resolve()`` and related methods now + accept an ``installer`` argument: a callable taking one argument, a + ``Requirement`` instance. The callable must return a ``Distribution`` + object, or ``None`` if no distribution is found. This feature is used by + EasyInstall to resolve dependencies by recursively invoking itself. + +0.4a4 + * Fix problems with ``resource_listdir()``, ``resource_isdir()`` and resource + directory extraction for zipped eggs. + +0.4a3 + * Fixed scripts not being able to see a ``__file__`` variable in ``__main__`` + + * Fixed a problem with ``resource_isdir()`` implementation that was introduced + in 0.4a2. + +0.4a1 + * Fixed a bug in requirements processing for exact versions (i.e. ``==`` and + ``!=``) when only one condition was included. + + * Added ``safe_name()`` and ``safe_version()`` APIs to clean up handling of + arbitrary distribution names and versions found on PyPI. + +0.3a4 + * ``pkg_resources`` now supports resource directories, not just the resources + in them. In particular, there are ``resource_listdir()`` and + ``resource_isdir()`` APIs. + + * ``pkg_resources`` now supports "egg baskets" -- .egg zipfiles which contain + multiple distributions in subdirectories whose names end with ``.egg``. + Having such a "basket" in a directory on ``sys.path`` is equivalent to + having the individual eggs in that directory, but the contained eggs can + be individually added (or not) to ``sys.path``. Currently, however, there + is no automated way to create baskets. + + * Namespace package manipulation is now protected by the Python import lock. + +0.3a1 + * Initial release. + Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- setuptools.txt 22 Aug 2005 03:28:27 -0000 1.32 +++ setuptools.txt 22 Aug 2005 03:40:20 -0000 1.33 @@ -1777,16 +1777,24 @@ ---------------------------- 0.6a1 + * The ``build_ext`` command now works better when using the ``--inplace`` + option and multiple Python versions. It now makes sure that all extensions + match the current Python version, even if newer copies were built for a + different Python version. + + * The ``upload`` command no longer attaches an extra ``.zip`` when uploading + eggs, as PyPI now supports egg uploads without trickery. + + * The ``ez_setup`` script/module now displays a warning before downloading + the setuptools egg, and attempts to check the downloaded egg against an + internal MD5 checksum table. + * Fixed the ``--tag-svn-revision`` option of ``egg_info`` not finding the latest revision number; it was using the revision number of the directory containing ``setup.py``, not the highest revision number in the project. * Added ``eager_resources`` setup argument - * Enhanced performance of ``require()`` and related operations when all - requirements are already in the working set, and enhanced performance of - directory scanning for distributions. - * The ``sdist`` command now recognizes Subversion "deleted file" entries and does not include them in source distributions. @@ -1794,12 +1802,6 @@ other distutils extensions (e.g. py2exe, py2app) will subclass setuptools' versions of things, rather than the native distutils ones. - * Fixed some problems using ``pkg_resources`` w/PEP 302 loaders other than - ``zipimport``, and the previously-broken "eager resource" support. - - * Fixed ``pkg_resources.resource_exists()`` not working correctly, along with - some other resource API bugs. - * Added ``entry_points`` and ``setup_requires`` arguments to ``setup()``; ``setup_requires`` allows you to automatically find and download packages that are needed in order to *build* your project (as opposed to running it). @@ -1812,104 +1814,16 @@ * The vestigial ``depends`` command has been removed. It was never finished or documented, and never would have worked without EasyInstall - which it pre-dated and was never compatible with. - - * Many ``pkg_resources`` API changes and enhancements: - - * Added ``EntryPoint``, ``get_entry_map``, ``load_entry_point``, and - ``get_entry_info`` APIs for dynamic plugin discovery. - - * ``list_resources`` is now ``resource_listdir`` (and it actually works) - - * Resource API functions like ``resource_string()`` that accepted a package - name and resource name, will now also accept a ``Requirement`` object in - place of the package name (to allow access to non-package data files in - an egg). - - * ``get_provider()`` will now accept a ``Requirement`` instance or a module - name. If it is given a ``Requirement``, it will return a corresponding - ``Distribution`` (by calling ``require()`` if a suitable distribution - isn't already in the working set), rather than returning a metadata and - resource provider for a specific module. (The difference is in how - resource paths are interpreted; supplying a module name means resources - path will be module-relative, rather than relative to the distribution's - root.) - - * ``Distribution`` objects now implement the ``IResourceProvider`` and - ``IMetadataProvider`` interfaces, so you don't need to reference the (no - longer available) ``metadata`` attribute to get at these interfaces. - - * ``Distribution`` and ``Requirement`` both have a ``project_name`` - attribute for the project name they refer to. (Previously these were - ``name`` and ``distname`` attributes.) - - * The ``path`` attribute of ``Distribution`` objects is now ``location``, - because it isn't necessarily a filesystem path (and hasn't been for some - time now). The ``location`` of ``Distribution`` objects in the filesystem - should always be normalized using ``pkg_resources.normalize_path()``; all - of the setuptools and EasyInstall code that generates distributions from - the filesystem (including ``Distribution.from_filename()``) ensure this - invariant, but if you use a more generic API like ``Distribution()`` or - ``Distribution.from_location()`` you should take care that you don't - create a distribution with an un-normalized filesystem path. - - * ``Distribution`` objects now have an ``as_requirement()`` method that - returns a ``Requirement`` for the distribution's project name and version. - - * Distribution objects no longer have an ``installed_on()`` method, and the - ``install_on()`` method is now ``activate()`` (but may go away altogether - soon). The ``depends()`` method has also been renamed to ``requires()``, - and ``InvalidOption`` is now ``UnknownExtra``. - - * ``find_distributions()`` now takes an additional argument called ``only``, - that tells it to only yield distributions whose location is the passed-in - path. (It defaults to False, so that the default behavior is unchanged.) - - * ``AvailableDistributions`` is now called ``Environment``, and the - ``get()``, ``__len__()``, and ``__contains__()`` methods were removed, - because they weren't particularly useful. ``__getitem__()`` no longer - raises ``KeyError``; it just returns an empty list if there are no - distributions for the named project. - - * The ``resolve()`` method of ``Environment`` is now a method of - ``WorkingSet`` instead, and the ``best_match()`` method now uses a working - set instead of a path list as its second argument. - - * There is a new ``pkg_resources.add_activation_listener()`` API that lets - you register a callback for notifications about distributions added to - ``sys.path`` (including the distributions already on it). This is - basically a hook for extensible applications and frameworks to be able to - search for plugin metadata in distributions added at runtime. -0.5a13 - * Fixed a bug in resource extraction from nested packages in a zipped egg. - 0.5a12 * The zip-safety scanner now checks for modules that might be used with ``python -m``, and marks them as unsafe for zipping, since Python 2.4 can't handle ``-m`` on zipped modules. - * Updated extraction/cache mechanism for zipped resources to avoid inter- - process and inter-thread races during extraction. The default cache - location can now be set via the ``PYTHON_EGGS_CACHE`` environment variable, - and the default Windows cache is now a ``Python-Eggs`` subdirectory of the - current user's "Application Data" directory, if the ``PYTHON_EGGS_CACHE`` - variable isn't set. - 0.5a11 * Fix breakage of the "develop" command that was caused by the addition of ``--always-unzip`` to the ``easy_install`` command. -0.5a10 - * Fix a problem with ``pkg_resources`` being confused by non-existent eggs on - ``sys.path`` (e.g. if a user deletes an egg without removing it from the - ``easy-install.pth`` file). - - * Fix a problem with "basket" support in ``pkg_resources``, where egg-finding - never actually went inside ``.egg`` files. - - * Made ``pkg_resources`` import the module you request resources from, if it's - not already imported. - 0.5a9 * Include ``svn:externals`` directories in source distributions as well as normal subversion-controlled files and directories. @@ -2026,12 +1940,6 @@ * Setup scripts using setuptools now always install using ``easy_install`` internally, for ease of uninstallation and upgrading. - * ``pkg_resources.AvailableDistributions.resolve()`` and related methods now - accept an ``installer`` argument: a callable taking one argument, a - ``Requirement`` instance. The callable must return a ``Distribution`` - object, or ``None`` if no distribution is found. This feature is used by - EasyInstall to resolve dependencies by recursively invoking itself. - 0.5a1 * Added support for "self-installation" bootstrapping. Packages can now include ``ez_setup.py`` in their source distribution, and add the following @@ -2044,16 +1952,6 @@ from setuptools import setup # etc... -0.4a4 - * Fix problems with ``resource_listdir()``, ``resource_isdir()`` and resource - directory extraction for zipped eggs. - -0.4a3 - * Fixed scripts not being able to see a ``__file__`` variable in ``__main__`` - - * Fixed a problem with ``resource_isdir()`` implementation that was introduced - in 0.4a2. - 0.4a2 * Added ``ez_setup.py`` installer/bootstrap script to make initial setuptools installation easier, and to allow distributions using setuptools to avoid @@ -2079,27 +1977,6 @@ their ``command_consumes_arguments`` attribute to ``True`` in order to receive an ``args`` option containing the rest of the command line. -0.4a1 - * Fixed a bug in requirements processing for exact versions (i.e. ``==`` and - ``!=``) when only one condition was included. - - * Added ``safe_name()`` and ``safe_version()`` APIs to clean up handling of - arbitrary distribution names and versions found on PyPI. - -0.3a4 - * ``pkg_resources`` now supports resource directories, not just the resources - in them. In particular, there are ``resource_listdir()`` and - ``resource_isdir()`` APIs. - - * ``pkg_resources`` now supports "egg baskets" -- .egg zipfiles which contain - multiple distributions in subdirectories whose names end with ``.egg``. - Having such a "basket" in a directory on ``sys.path`` is equivalent to - having the individual eggs in that directory, but the contained eggs can - be individually added (or not) to ``sys.path``. Currently, however, there - is no automated way to create baskets. - - * Namespace package manipulation is now protected by the Python import lock. - 0.3a2 * Added new options to ``bdist_egg`` to allow tagging the egg's version number with a subversion revision number, the current date, or an explicit tag From pje at users.sourceforge.net Mon Aug 22 05:50:29 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 05:50:29 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.53, 1.54 ez_setup.py, 1.24, 1.25 setup.py, 1.36, 1.37 Message-ID: <20050822035029.43D2A1E4006@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8938 Modified Files: EasyInstall.txt ez_setup.py setup.py Log Message: Bump release version to 0.6a1. Fix a minor cosmetic issue on certain ez_setup installs. Index: EasyInstall.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v retrieving revision 1.53 retrieving revision 1.54 diff -u -d -r1.53 -r1.54 --- EasyInstall.txt 22 Aug 2005 03:28:27 -0000 1.53 +++ EasyInstall.txt 22 Aug 2005 03:50:19 -0000 1.54 @@ -77,7 +77,7 @@ **Example 2**. Install or upgrade a package by name and version by finding links on a given "download page":: - easy_install -f http://peak.telecommunity.com/dist "setuptools>=0.6a0" + easy_install -f http://peak.telecommunity.com/dist "setuptools>=0.6a1" **Example 3**. Download a source distribution from a specified URL, automatically building and installing it:: Index: ez_setup.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/ez_setup.py,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- ez_setup.py 22 Aug 2005 03:28:27 -0000 1.24 +++ ez_setup.py 22 Aug 2005 03:50:19 -0000 1.25 @@ -13,7 +13,7 @@ This file can also be run as a script to install or upgrade setuptools. """ -DEFAULT_VERSION = "0.6a0" +DEFAULT_VERSION = "0.6a1" DEFAULT_URL = "http://www.python.org/packages/source/s/setuptools/" md5_data = { @@ -150,7 +150,7 @@ from setuptools.command.easy_install import main except ImportError: from easy_install import main - main(list(argv)+[download_setuptools()]) + main(list(argv)+[download_setuptools(delay=0)]) sys.exit(0) # try to force an exit else: if argv: Index: setup.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setup.py,v retrieving revision 1.36 retrieving revision 1.37 diff -u -d -r1.36 -r1.37 --- setup.py 6 Aug 2005 21:17:49 -0000 1.36 +++ setup.py 22 Aug 2005 03:50:19 -0000 1.37 @@ -15,7 +15,7 @@ f.close() return ''.join(lines) -VERSION = "0.6a0" +VERSION = "0.6a1" from setuptools import setup, find_packages import sys From pje at users.sourceforge.net Mon Aug 22 05:50:30 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 05:50:30 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools __init__.py, 1.22, 1.23 Message-ID: <20050822035030.61EA31E4006@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8938/setuptools Modified Files: __init__.py Log Message: Bump release version to 0.6a1. Fix a minor cosmetic issue on certain ez_setup installs. Index: __init__.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/__init__.py,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- __init__.py 6 Aug 2005 18:46:27 -0000 1.22 +++ __init__.py 22 Aug 2005 03:50:19 -0000 1.23 @@ -7,7 +7,7 @@ from distutils.util import convert_path import os.path -__version__ = '0.6a0' +__version__ = '0.6a1' __all__ = [ 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require', 'find_packages' From pje at users.sourceforge.net Mon Aug 22 05:53:52 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 05:53:52 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.54, 1.55 Message-ID: <20050822035352.D39E41E4006@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9449 Modified Files: EasyInstall.txt Log Message: Remove broken example. Index: EasyInstall.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v retrieving revision 1.54 retrieving revision 1.55 diff -u -d -r1.54 -r1.55 --- EasyInstall.txt 22 Aug 2005 03:50:19 -0000 1.54 +++ EasyInstall.txt 22 Aug 2005 03:53:42 -0000 1.55 @@ -77,7 +77,7 @@ **Example 2**. Install or upgrade a package by name and version by finding links on a given "download page":: - easy_install -f http://peak.telecommunity.com/dist "setuptools>=0.6a1" + easy_install -f http://pythonpaste.org/package_index.html SQLObject **Example 3**. Download a source distribution from a specified URL, automatically building and installing it:: @@ -107,8 +107,6 @@ easy_install --editable --build-directory ~/projects SQLObject -Note: - Easy Install accepts URLs, filenames, PyPI package names (i.e., ``distutils`` "distribution" names), and package+version specifiers. In each case, it will attempt to locate the latest available version that meets your criteria. From raymond.hettinger at verizon.net Mon Aug 22 14:46:27 2005 From: raymond.hettinger at verizon.net (Raymond Hettinger) Date: Mon, 22 Aug 2005 08:46:27 -0400 Subject: [Python-checkins] python/dist/src setup.py,1.219,1.220 In-Reply-To: <20050821184639.EF8711E4006@bag.python.org> Message-ID: <003101c5a717$83be4b60$3c23a044@oemcomputer> > A new hashlib module to replace the md5 and sha modules. It adds > support for additional secure hashes such as SHA-256 and SHA-512. The > hashlib module uses OpenSSL for fast platform optimized > implementations of algorithms when available. The old md5 and sha > modules still exist as wrappers around hashlib to preserve backwards > compatibility. I'm getting compilation errors: C:\py25\Modules\sha512module.c(146) : error C2059: syntax error : 'bad suffix on number' C:\py25\Modules\sha512module.c(146) : error C2146: syntax error : missing ')' before identifier 'L' C:\py25\Modules\sha512module.c(146) : error C2059: syntax error : 'bad suffix on number' C:\py25\Modules\sha512module.c(146) : error C2059: syntax error : 'bad suffix on number' C:\py25\Modules\sha512module.c(146) : error C2059: syntax error : 'bad suffix on number' C:\py25\Modules\sha512module.c(146) : error C2059: syntax error : 'bad suffix on number' C:\py25\Modules\sha512module.c(146) : error C2059: syntax error : 'bad suffix on number' C:\py25\Modules\sha512module.c(146) : fatal error C1013: compiler limit : too many open parentheses Also, there should be updating entries to Misc/NEWS, PC/VC6/pythoncore.dsp, and PC/config.c. Raymond From pje at users.sourceforge.net Mon Aug 22 15:40:23 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Mon, 22 Aug 2005 15:40:23 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command bdist_egg.py, 1.28, 1.29 easy_install.py, 1.22, 1.23 install.py, 1.4, 1.5 Message-ID: <20050822134023.0F3451E4005@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14566/setuptools/command Modified Files: bdist_egg.py easy_install.py install.py Log Message: Make easy_install --record strip the RPM root when building RPMs, and have bdist_egg ignore the RPM root when building an egg. This version now can actually run bdist_rpm to completion, although the resulting RPM will install an egg without a corresponding .pth file. Index: bdist_egg.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/bdist_egg.py,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- bdist_egg.py 14 Aug 2005 21:17:45 -0000 1.28 +++ bdist_egg.py 22 Aug 2005 13:40:10 -0000 1.29 @@ -170,7 +170,11 @@ # pull their data path from the install_lib command. log.info("installing library code to %s" % self.bdist_dir) + instcmd = self.get_finalized_command('install') + old_root = instcmd.root + instcmd.root = None cmd = self.call_command('install_lib', warn_dir=0) + instcmd.root = old_root ext_outputs = cmd._mutate_outputs( self.distribution.has_ext_modules(), 'build_ext', 'build_lib', '' Index: easy_install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/easy_install.py,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- easy_install.py 14 Aug 2005 20:46:49 -0000 1.22 +++ easy_install.py 22 Aug 2005 13:40:10 -0000 1.23 @@ -90,6 +90,7 @@ self.optimize = self.record = None self.upgrade = self.always_copy = self.multi_version = None self.editable = None + self.root = None # Options not specifiable via command line self.package_index = None @@ -120,7 +121,6 @@ - def finalize_options(self): # If a non-default installation directory was specified, default the # script directory to match it. @@ -224,9 +224,14 @@ for spec in self.args: self.easy_install(spec, True) if self.record: + outputs = self.outputs + if self.root: # strip any package prefix + root_len = len(self.root) + for counter in xrange(len(outputs)): + outputs[counter] = outputs[counter][root_len:] from distutils import file_util self.execute( - file_util.write_file, (self.record, self.outputs), + file_util.write_file, (self.record, outputs), "writing list of installed files to '%s'" % self.record ) @@ -239,11 +244,6 @@ - - - - - def add_output(self, path): if os.path.isdir(path): for base, dirs, files in os.walk(path): Index: install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/install.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- install.py 11 Aug 2005 14:58:54 -0000 1.4 +++ install.py 22 Aug 2005 13:40:10 -0000 1.5 @@ -23,7 +23,8 @@ from setuptools.command.easy_install import easy_install cmd = easy_install( - self.distribution, args="x", ignore_conflicts_at_my_risk=1 + self.distribution, args="x", ignore_conflicts_at_my_risk=1, + root=self.root ) cmd.ensure_finalized() # finalize before bdist_egg munges install cmd From birkenfeld at users.sourceforge.net Mon Aug 22 20:01:14 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 20:01:14 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib macpath.py, 1.51, 1.52 ntpath.py, 1.62, 1.63 os2emxpath.py, 1.14, 1.15 posixpath.py, 1.74, 1.75 Message-ID: <20050822180114.E31CC1E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10897/Lib Modified Files: macpath.py ntpath.py os2emxpath.py posixpath.py Log Message: Bug #1266283: lexists() is not exported from os.path Index: macpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/macpath.py,v retrieving revision 1.51 retrieving revision 1.52 diff -u -d -r1.51 -r1.52 --- macpath.py 3 Aug 2005 07:30:11 -0000 1.51 +++ macpath.py 22 Aug 2005 18:01:03 -0000 1.52 @@ -5,7 +5,7 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime", "islink","exists","isdir","isfile", + "getatime","getctime", "islink","exists","lexists","isdir","isfile", "walk","expanduser","expandvars","normpath","abspath", "curdir","pardir","sep","pathsep","defpath","altsep","extsep", "devnull","realpath","supports_unicode_filenames"] Index: ntpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/ntpath.py,v retrieving revision 1.62 retrieving revision 1.63 diff -u -d -r1.62 -r1.63 --- ntpath.py 3 Aug 2005 07:30:12 -0000 1.62 +++ ntpath.py 22 Aug 2005 18:01:03 -0000 1.63 @@ -11,10 +11,10 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime", "islink","exists","isdir","isfile","ismount", - "walk","expanduser","expandvars","normpath","abspath","splitunc", - "curdir","pardir","sep","pathsep","defpath","altsep","extsep", - "devnull","realpath","supports_unicode_filenames"] + "getatime","getctime", "islink","exists","lexists","isdir","isfile", + "ismount","walk","expanduser","expandvars","normpath","abspath", + "splitunc","curdir","pardir","sep","pathsep","defpath","altsep", + "extsep","devnull","realpath","supports_unicode_filenames"] # strings representing various path-related bits and pieces curdir = '.' Index: os2emxpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/os2emxpath.py,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- os2emxpath.py 3 Aug 2005 07:30:12 -0000 1.14 +++ os2emxpath.py 22 Aug 2005 18:01:03 -0000 1.15 @@ -10,10 +10,10 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime", "islink","exists","isdir","isfile","ismount", - "walk","expanduser","expandvars","normpath","abspath","splitunc", - "curdir","pardir","sep","pathsep","defpath","altsep","extsep", - "devnull","realpath","supports_unicode_filenames"] + "getatime","getctime", "islink","exists","lexists","isdir","isfile", + "ismount","walk","expanduser","expandvars","normpath","abspath", + "splitunc","curdir","pardir","sep","pathsep","defpath","altsep", + "extsep","devnull","realpath","supports_unicode_filenames"] # strings representing various path-related bits and pieces curdir = '.' Index: posixpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/posixpath.py,v retrieving revision 1.74 retrieving revision 1.75 diff -u -d -r1.74 -r1.75 --- posixpath.py 3 Jun 2005 14:24:43 -0000 1.74 +++ posixpath.py 22 Aug 2005 18:01:03 -0000 1.75 @@ -15,8 +15,8 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime","islink","exists","isdir","isfile","ismount", - "walk","expanduser","expandvars","normpath","abspath", + "getatime","getctime","islink","exists","lexists","isdir","isfile", + "ismount","walk","expanduser","expandvars","normpath","abspath", "samefile","sameopenfile","samestat", "curdir","pardir","sep","pathsep","defpath","altsep","extsep", "devnull","realpath","supports_unicode_filenames"] From birkenfeld at users.sourceforge.net Mon Aug 22 20:03:10 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 20:03:10 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1336,1.1337 Message-ID: <20050822180310.9A3851E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11240/Misc Modified Files: NEWS Log Message: Bug #1266283: lexists() is not exported from os.path Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1336 retrieving revision 1.1337 diff -u -d -r1.1336 -r1.1337 --- NEWS 21 Aug 2005 14:16:03 -0000 1.1336 +++ NEWS 22 Aug 2005 18:02:59 -0000 1.1337 @@ -1692,6 +1692,8 @@ Library ------- +- Bug #1266283: The new function "lexists" is now in os.path.__all__. + - 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. From birkenfeld at users.sourceforge.net Mon Aug 22 20:07:14 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 20:07:14 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.73, 1.1193.2.74 Message-ID: <20050822180714.9E7801E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12592/Misc Modified Files: Tag: release24-maint NEWS Log Message: backport bug #1266283: add lexists to os.path.__all__ Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.73 retrieving revision 1.1193.2.74 diff -u -d -r1.1193.2.73 -r1.1193.2.74 --- NEWS 15 Aug 2005 17:35:43 -0000 1.1193.2.73 +++ NEWS 22 Aug 2005 18:07:04 -0000 1.1193.2.74 @@ -63,6 +63,8 @@ Library ------- +- Bug #1266283: "lexists" is now in os.path.__all__. + - The sets module can now properly compute s-=s and s^=s as an empty set. - Patch #827386: Support absolute source paths in msvccompiler.py. From birkenfeld at users.sourceforge.net Mon Aug 22 20:07:14 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 20:07:14 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib os2emxpath.py, 1.13, 1.13.2.1 ntpath.py, 1.61, 1.61.2.1 macpath.py, 1.50, 1.50.2.1 posixpath.py, 1.73.2.1, 1.73.2.2 Message-ID: <20050822180714.E4F6A1E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12592/Lib Modified Files: Tag: release24-maint os2emxpath.py ntpath.py macpath.py posixpath.py Log Message: backport bug #1266283: add lexists to os.path.__all__ Index: os2emxpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/os2emxpath.py,v retrieving revision 1.13 retrieving revision 1.13.2.1 diff -u -d -r1.13 -r1.13.2.1 --- os2emxpath.py 30 Aug 2004 10:19:55 -0000 1.13 +++ os2emxpath.py 22 Aug 2005 18:07:04 -0000 1.13.2.1 @@ -10,10 +10,10 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime", "islink","exists","isdir","isfile","ismount", - "walk","expanduser","expandvars","normpath","abspath","splitunc", - "curdir","pardir","sep","pathsep","defpath","altsep","extsep", - "devnull","realpath","supports_unicode_filenames"] + "getatime","getctime", "islink","exists","lexists","isdir","isfile", + "ismount","walk","expanduser","expandvars","normpath","abspath", + "splitunc","curdir","pardir","sep","pathsep","defpath","altsep", + "extsep","devnull","realpath","supports_unicode_filenames"] # strings representing various path-related bits and pieces curdir = '.' Index: ntpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/ntpath.py,v retrieving revision 1.61 retrieving revision 1.61.2.1 diff -u -d -r1.61 -r1.61.2.1 --- ntpath.py 30 Aug 2004 10:19:55 -0000 1.61 +++ ntpath.py 22 Aug 2005 18:07:04 -0000 1.61.2.1 @@ -11,10 +11,10 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime", "islink","exists","isdir","isfile","ismount", - "walk","expanduser","expandvars","normpath","abspath","splitunc", - "curdir","pardir","sep","pathsep","defpath","altsep","extsep", - "devnull","realpath","supports_unicode_filenames"] + "getatime","getctime", "islink","exists","lexists","isdir","isfile", + "ismount","walk","expanduser","expandvars","normpath","abspath", + "splitunc","curdir","pardir","sep","pathsep","defpath","altsep", + "extsep","devnull","realpath","supports_unicode_filenames"] # strings representing various path-related bits and pieces curdir = '.' Index: macpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/macpath.py,v retrieving revision 1.50 retrieving revision 1.50.2.1 diff -u -d -r1.50 -r1.50.2.1 --- macpath.py 30 Aug 2004 13:39:50 -0000 1.50 +++ macpath.py 22 Aug 2005 18:07:04 -0000 1.50.2.1 @@ -5,7 +5,7 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime", "islink","exists","isdir","isfile", + "getatime","getctime", "islink","exists","lexists","isdir","isfile", "walk","expanduser","expandvars","normpath","abspath", "curdir","pardir","sep","pathsep","defpath","altsep","extsep", "devnull","realpath","supports_unicode_filenames"] Index: posixpath.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/posixpath.py,v retrieving revision 1.73.2.1 retrieving revision 1.73.2.2 diff -u -d -r1.73.2.1 -r1.73.2.2 --- posixpath.py 3 Jun 2005 14:31:48 -0000 1.73.2.1 +++ posixpath.py 22 Aug 2005 18:07:04 -0000 1.73.2.2 @@ -15,8 +15,8 @@ __all__ = ["normcase","isabs","join","splitdrive","split","splitext", "basename","dirname","commonprefix","getsize","getmtime", - "getatime","getctime","islink","exists","isdir","isfile","ismount", - "walk","expanduser","expandvars","normpath","abspath", + "getatime","getctime","islink","exists","lexists","isdir","isfile", + "ismount","walk","expanduser","expandvars","normpath","abspath", "samefile","sameopenfile","samestat", "curdir","pardir","sep","pathsep","defpath","altsep","extsep", "devnull","realpath","supports_unicode_filenames"] From greg at users.sourceforge.net Mon Aug 22 20:31:53 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Mon, 22 Aug 2005 20:31:53 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libhashlib.tex,NONE,1.1 Message-ID: <20050822183153.84A8C1E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17991/Doc/lib Added Files: libhashlib.tex Log Message: whoops, missed adding this last night in my hashlib commit --- NEW FILE: libhashlib.tex --- \section{\module{hashlib} --- Secure hashes and message digests} \declaremodule{builtin}{hashlib} \modulesynopsis{Secure hash and message digest algorithms.} \moduleauthor{Gregory P. Smith}{greg at users.sourceforge.net} \sectionauthor{Gregory P. Smith}{greg at users.sourceforge.net} \versionadded{2.5} \index{message digest, MD5} \index{secure hash algorithm, SHA1, SHA224, SHA256, SHA384, SHA512} This module implements a common interface to many different secure hash and message digest algorithms. Included are the FIPS secure hash algorithms SHA1, SHA224, SHA256, SHA384, and SHA512 (defined in FIPS 180-2) as well as RSA's MD5 algorithm (defined in Internet \rfc{1321}). The terms secure hash and message digest are interchangable. Older algorithms were called message digests. The modern term is secure hash. \warning{Some algorithms have known hash collision weaknesses, see the FAQ at the end.} There is one constructor method named for each type of \dfn{hash}. All return a hash object with the same simple interface. For example: use \function{sha1()} to create a SHA1 hash object. You can now feed this object with arbitrary strings using the \method{update()} method. At any point you can ask it for the \dfn{digest} of the concatenation of the strings fed to it so far using the \method{digest()} or \method{hexdigest()} methods. Constructors for hash algorithms that are always present in this module are \function{md5()}, \function{sha1()}, \function{sha224()}, \function{sha256()}, \function{sha384()}, and \function{sha512()}. Additional algorithms may also be available depending upon the OpenSSL library python uses on your platform. \index{OpenSSL} For example, to obtain the digest of the string \code{'Nobody inspects the spammish repetition'}: \begin{verbatim} >>> import hashlib >>> m = hashlib.md5() >>> m.update("Nobody inspects") >>> m.update(" the spammish repetition") >>> m.digest() '\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9' \end{verbatim} More condensed: \begin{verbatim} >>> hashlib.sha224("Nobody inspects the spammish repetition").hexdigest() 'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2' \end{verbatim} A generic \function{new()} constructor that takes the string name of the desired algorithm as its first parameter also exists to allow access to the above listed hashes as well as any other algorithms that your OpenSSL library may offer. The named constructors are much faster than \function{new()} and should be preferred. Using \function{new()} with an algorithm provided by OpenSSL: \begin{verbatim} >>> h = hashlib.new('ripemd160') >>> h.update("Nobody inspects the spammish repetition") >>> h.hexdigest() 'cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc' \end{verbatim} The following values are provided as constant attributes of the hash objects returned by the constructors: \begin{datadesc}{digest_size} The size of the resulting digest in bytes. \end{datadesc} A hash object has the following methods: \begin{methoddesc}[hash]{update}{arg} Update the hash object with the string \var{arg}. Repeated calls are equivalent to a single call with the concatenation of all the arguments: \code{m.update(a); m.update(b)} is equivalent to \code{m.update(a+b)}. \end{methoddesc} \begin{methoddesc}[hash]{digest}{} Return the digest of the strings passed to the \method{update()} method so far. This is a 16-byte string which may contain non-\ASCII{} characters, including null bytes. \end{methoddesc} \begin{methoddesc}[hash]{hexdigest}{} Like \method{digest()} except the digest is returned as a string of double length, containing only hexadecimal digits. This may be used to exchange the value safely in email or other non-binary environments. \end{methoddesc} \begin{methoddesc}[hash]{copy}{} Return a copy (``clone'') of the hash object. This can be used to efficiently compute the digests of strings that share a common initial substring. \end{methoddesc} \begin{seealso} \seemodule{hmac}{A module to generate message authentication codes using hashes.} \seemodule{base64}{Another way to encode binary hashes for non-binary environments.} \seeurl{http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf} {The FIPS 180-2 publication on Secure Hash Algorithms.} \seeurl{http://www.cryptography.com/cnews/hash.html} {Hash Collision FAQ with information on which algorithms have known issues and what that means regarding their use.} \end{seealso} From birkenfeld at users.sourceforge.net Mon Aug 22 21:35:28 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 21:35:28 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libdecimal.tex, 1.28, 1.29 Message-ID: <20050822193528.494FC1E407F@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5118/Doc/lib Modified Files: libdecimal.tex Log Message: bug [ 1266296 ] Mistakes in decimal.Context.subtract documentation Index: libdecimal.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libdecimal.tex,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- libdecimal.tex 1 Jul 2005 16:54:12 -0000 1.28 +++ libdecimal.tex 22 Aug 2005 19:35:17 -0000 1.29 @@ -693,7 +693,7 @@ Return the square root to full precision. \end{methoddesc} -\begin{methoddesc}{substract}{x, y} +\begin{methoddesc}{subtract}{x, y} Return the difference between \var{x} and \var{y}. \end{methoddesc} From birkenfeld at users.sourceforge.net Mon Aug 22 21:35:29 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 21:35:29 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc cheatsheet,1.10,1.11 Message-ID: <20050822193529.7C7881E40E7@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5118/Misc Modified Files: cheatsheet Log Message: bug [ 1266296 ] Mistakes in decimal.Context.subtract documentation Index: cheatsheet =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/cheatsheet,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- cheatsheet 10 Sep 2004 12:59:25 -0000 1.10 +++ cheatsheet 22 Aug 2005 19:35:18 -0000 1.11 @@ -209,7 +209,7 @@ +x, -x, ~x Unary operators x**y Power x*y x/y x%y x//y mult, division, modulo, floor division - x+y x-y addition, substraction + x+y x-y addition, subtraction x<>y Bit shifting x&y Bitwise and x^y Bitwise exclusive or From birkenfeld at users.sourceforge.net Mon Aug 22 21:35:29 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 21:35:29 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib decimal.py,1.38,1.39 Message-ID: <20050822193529.C01651E40A9@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5118/Lib Modified Files: decimal.py Log Message: bug [ 1266296 ] Mistakes in decimal.Context.subtract documentation Index: decimal.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/decimal.py,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- decimal.py 20 Jun 2005 09:49:42 -0000 1.38 +++ decimal.py 22 Aug 2005 19:35:17 -0000 1.39 @@ -2755,7 +2755,7 @@ return a.sqrt(context=self) def subtract(self, a, b): - """Return the sum of the two operands. + """Return the difference between the two operands. >>> ExtendedContext.subtract(Decimal('1.3'), Decimal('1.07')) Decimal("0.23") From birkenfeld at users.sourceforge.net Mon Aug 22 21:35:35 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 21:35:35 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libdecimal.tex, 1.24.2.3, 1.24.2.4 Message-ID: <20050822193535.D48781E4099@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5243/Doc/lib Modified Files: Tag: release24-maint libdecimal.tex Log Message: backport bug [ 1266296 ] Mistakes in decimal.Context.subtract documentation Index: libdecimal.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libdecimal.tex,v retrieving revision 1.24.2.3 retrieving revision 1.24.2.4 diff -u -d -r1.24.2.3 -r1.24.2.4 --- libdecimal.tex 1 Jul 2005 16:56:53 -0000 1.24.2.3 +++ libdecimal.tex 22 Aug 2005 19:35:24 -0000 1.24.2.4 @@ -693,7 +693,7 @@ Return the square root to full precision. \end{methoddesc} -\begin{methoddesc}{substract}{x, y} +\begin{methoddesc}{subtract}{x, y} Return the difference between \var{x} and \var{y}. \end{methoddesc} From birkenfeld at users.sourceforge.net Mon Aug 22 21:35:36 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 21:35:36 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib decimal.py, 1.31.2.4, 1.31.2.5 Message-ID: <20050822193536.188031E4151@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5243/Lib Modified Files: Tag: release24-maint decimal.py Log Message: backport bug [ 1266296 ] Mistakes in decimal.Context.subtract documentation Index: decimal.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/decimal.py,v retrieving revision 1.31.2.4 retrieving revision 1.31.2.5 diff -u -d -r1.31.2.4 -r1.31.2.5 --- decimal.py 12 Jun 2005 18:23:01 -0000 1.31.2.4 +++ decimal.py 22 Aug 2005 19:35:24 -0000 1.31.2.5 @@ -2754,7 +2754,7 @@ return a.sqrt(context=self) def subtract(self, a, b): - """Return the sum of the two operands. + """Return the difference between the two operands. >>> ExtendedContext.subtract(Decimal('1.3'), Decimal('1.07')) Decimal("0.23") From birkenfeld at users.sourceforge.net Mon Aug 22 21:35:36 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Mon, 22 Aug 2005 21:35:36 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc cheatsheet,1.10,1.10.2.1 Message-ID: <20050822193536.217E71E4153@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5243/Misc Modified Files: Tag: release24-maint cheatsheet Log Message: backport bug [ 1266296 ] Mistakes in decimal.Context.subtract documentation Index: cheatsheet =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/cheatsheet,v retrieving revision 1.10 retrieving revision 1.10.2.1 diff -u -d -r1.10 -r1.10.2.1 --- cheatsheet 10 Sep 2004 12:59:25 -0000 1.10 +++ cheatsheet 22 Aug 2005 19:35:24 -0000 1.10.2.1 @@ -209,7 +209,7 @@ +x, -x, ~x Unary operators x**y Power x*y x/y x%y x//y mult, division, modulo, floor division - x+y x-y addition, substraction + x+y x-y addition, subtraction x<>y Bit shifting x&y Bitwise and x^y Bitwise exclusive or From gregorykjohnson at users.sourceforge.net Mon Aug 22 22:19:39 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Mon, 22 Aug 2005 22:19:39 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox libmailbox.tex, 1.13, 1.14 mailbox.py, 1.14, 1.15 test_mailbox.py, 1.9, 1.10 Message-ID: <20050822201939.C29AA1E4191@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15538 Modified Files: libmailbox.tex mailbox.py test_mailbox.py Log Message: * Fix various things detected by pychecker. * Fix various things detected by testing on Windows. * Tests pass on Windows, but there are still some line-ending issues. Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- libmailbox.tex 21 Aug 2005 19:02:47 -0000 1.13 +++ libmailbox.tex 22 Aug 2005 20:19:27 -0000 1.14 @@ -261,6 +261,19 @@ nesting is indicated using \character{.} to delimit levels, e.g., "Archived.2005.07". +\begin{notice} +The Maildir specification requires the use of a colon (\character{:}) in +certain message file names. Some operating systems do not permit this character +in file names, however. If you wish to use a Maildir-like format on such an +operating system, you should specify another character to use instead. The +exclamation point (\character{!}) is a popular choice. For example: +\begin{verbatim} +import mailbox +mailbox.Maildir.colon = '!' +\end{verbatim} +The \member{colon} attribute may also be set on a per-instance basis. +\end{notice} + \class{Maildir} instances have all of the methods of \class{Mailbox} in addition to the following: Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- mailbox.py 21 Aug 2005 21:17:53 -0000 1.14 +++ mailbox.py 22 Aug 2005 20:19:28 -0000 1.15 @@ -7,7 +7,6 @@ import calendar import socket import errno -import stat import copy import email import email.Message @@ -64,7 +63,7 @@ def __getitem__(self, key): """Return the keyed message; raise KeyError if it doesn't exist.""" - if self._factory is None: + if not self._factory: return self.get_message(key) else: return self._factory(self.get_file(key)) @@ -175,7 +174,7 @@ """Lock the mailbox.""" raise NotImplementedError('Method must be implemented by subclass') - def unlock(self, f=None): + def unlock(self): """Unlock the mailbox if it is locked.""" raise NotImplementedError('Method must be implemented by subclass') @@ -190,7 +189,8 @@ generator.flatten(message) elif isinstance(message, str): if mangle_from_: - message = message.replace('\nFrom ', '\n>From ') + message = message.replace(os.linesep + 'From ', + os.linesep + '>From ') target.write(message) elif hasattr(message, 'read'): if mangle_from_: @@ -214,6 +214,8 @@ class Maildir(Mailbox): """A qmail-style Maildir mailbox.""" + colon = ':' + def __init__(self, dirname, factory=rfc822.Message, create=True): """Initialize a Maildir instance.""" Mailbox.__init__(self, dirname, factory, create) @@ -236,13 +238,13 @@ tmp_file.close() if isinstance(message, MaildirMessage): subdir = message.get_subdir() - suffix = ':' + message.get_info() - if suffix == ':': + suffix = self.colon + message.get_info() + if suffix == self.colon: suffix = '' else: subdir = 'new' suffix = '' - uniq = os.path.basename(tmp_file.name).split(':')[0] + uniq = os.path.basename(tmp_file.name).split(self.colon)[0] dest = os.path.join(self._path, subdir, uniq + suffix) os.rename(tmp_file.name, dest) if isinstance(message, MaildirMessage): @@ -261,7 +263,7 @@ except KeyError: pass except OSError, e: - if errno == errno.ENOENT: + if e.errno == errno.ENOENT: pass else: raise @@ -278,8 +280,8 @@ # temp's subdir and suffix were defaults from add(). dominant_subpath = old_subpath subdir = os.path.dirname(dominant_subpath) - if ':' in dominant_subpath: - suffix = ':' + dominant_subpath.split(':')[-1] + if self.colon in dominant_subpath: + suffix = self.colon + dominant_subpath.split(self.colon)[-1] else: suffix = '' self.discard(key) @@ -292,21 +294,21 @@ def get_message(self, key): """Return a Message representation or raise a KeyError.""" subpath = self._lookup(key) - f = file(os.path.join(self._path, subpath), 'r') + f = file(os.path.join(self._path, subpath), 'rb') try: msg = MaildirMessage(f) finally: f.close() subdir, name = os.path.split(subpath) msg.set_subdir(subdir) - if ':' in name: - msg.set_info(name.split(':')[-1]) + if self.colon in name: + msg.set_info(name.split(self.colon)[-1]) msg.set_date(os.path.getmtime(os.path.join(self._path, subpath))) return msg def get_string(self, key): """Return a string representation or raise a KeyError.""" - f = file(os.path.join(self._path, self._lookup(key)), 'r') + f = file(os.path.join(self._path, self._lookup(key)), 'rb') try: return f.read() finally: @@ -314,7 +316,7 @@ def get_file(self, key): """Return a file-like representation or raise a KeyError.""" - f = file(os.path.join(self._path, self._lookup(key)), 'r') + f = file(os.path.join(self._path, self._lookup(key)), 'rb') return _ProxyFile(f) def iterkeys(self): @@ -413,14 +415,14 @@ if ':' in hostname: hostname = hostname.replace(':', r'\072') uniq = "%s.M%sP%sQ%s.%s" % (int(now), int(now % 1 * 1e6), os.getpid(), - self._count, hostname) + Maildir._count, hostname) path = os.path.join(self._path, 'tmp', uniq) try: os.stat(path) except OSError, e: if e.errno == errno.ENOENT: - self._count += 1 - return file(path, 'w+') + Maildir._count += 1 + return file(path, 'wb+') else: raise else: @@ -432,7 +434,7 @@ self._toc = {} for subdir in ('new', 'cur'): for entry in os.listdir(os.path.join(self._path, subdir)): - uniq = entry.split(':')[0] + uniq = entry.split(self.colon)[0] self._toc[uniq] = os.path.join(subdir, entry) def _lookup(self, key): @@ -451,12 +453,15 @@ # This method is for backward compatibility only. def next(self): """Return the next message in a one-time iteration.""" - if not hasattr(self, '_onetime_iterator'): - self._onetime_iterator = self.itervalues() - try: - return self._onetime_iterator.next() - except StopIteration: - return None + if not hasattr(self, '_onetime_keys'): + self._onetime_keys = self.iterkeys() + while True: + try: + return self[self._onetime_keys.next()] + except StopIteration: + return None + except KeyError: + continue class _singlefileMailbox(Mailbox): @@ -466,15 +471,15 @@ """Initialize a single-file mailbox.""" Mailbox.__init__(self, path, factory, create) try: - f = file(self._path, 'r+') + f = file(self._path, 'rb+') except IOError, e: if e.errno == errno.ENOENT: if create: - f = file(self._path, 'w+') + f = file(self._path, 'wb+') else: raise NoSuchMailboxError(self._path) elif e.errno == errno.EACCES: - f = file(self._path, 'r') + f = file(self._path, 'rb') else: raise self._file = f @@ -525,7 +530,7 @@ _lock_file(self._file) self._locked = True - def unlock(self, f=None): + def unlock(self): """Unlock the mailbox if it is locked.""" if self._locked: _unlock_file(self._file) @@ -567,7 +572,7 @@ os.rename(new_file.name, self._path) else: raise - self._file = file(self._path, 'r+') + self._file = file(self._path, 'rb+') self._toc = new_toc self._pending = False if self._locked: @@ -624,7 +629,7 @@ self._file.seek(start) from_line = self._file.readline() msg = self._message_factory(self._file.read(stop - self._file.tell())) - msg.set_from(from_line[5:-1]) + msg.set_from(from_line[5:-len(os.linesep)]) return msg def get_string(self, key, from_=False): @@ -661,7 +666,7 @@ if from_line is None: from_line = 'From MAILER-DAEMON %s' % time.asctime(time.gmtime()) start = self._file.tell() - self._file.write('%s%s' % (from_line, os.linesep)) + self._file.write(from_line + os.linesep) self._dump_message(message, self._file, self._mangle_from_) stop = self._file.tell() return (start, stop) @@ -710,11 +715,11 @@ def _pre_message_hook(self, f): """Called before writing each message to file f.""" - f.write('\001\001\001\001\n') + f.write('\001\001\001\001' + os.linesep) def _post_message_hook(self, f): """Called after writing each message to file f.""" - f.write('\n\001\001\001\001\n') + f.write(os.linesep + '\001\001\001\001' + os.linesep) def _generate_toc(self): """Generate key-to-(start, stop) table of contents.""" @@ -785,7 +790,7 @@ """Remove the keyed message; raise KeyError if it doesn't exist.""" path = os.path.join(self._path, str(key)) try: - f = file(path, 'r+') + f = file(path, 'rb+') except IOError, e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -807,7 +812,7 @@ """Replace the keyed message; raise KeyError if it doesn't exist.""" path = os.path.join(self._path, str(key)) try: - f = file(path, 'r+') + f = file(path, 'rb+') except IOError, e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -831,9 +836,9 @@ """Return a Message representation or raise a KeyError.""" try: if self._locked: - f = file(os.path.join(self._path, str(key)), 'r+') + f = file(os.path.join(self._path, str(key)), 'rb+') else: - f = file(os.path.join(self._path, str(key)), 'r') + f = file(os.path.join(self._path, str(key)), 'rb') except IOError, e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -858,9 +863,9 @@ """Return a string representation or raise a KeyError.""" try: if self._locked: - f = file(os.path.join(self._path, str(key)), 'r+') + f = file(os.path.join(self._path, str(key)), 'rb+') else: - f = file(os.path.join(self._path, str(key)), 'r') + f = file(os.path.join(self._path, str(key)), 'rb') except IOError, e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -873,14 +878,14 @@ return f.read() finally: if self._locked: - _unlock_file() + _unlock_file(f) finally: f.close() def get_file(self, key): """Return a file-like representation or raise a KeyError.""" try: - f = file(os.path.join(self._path, str(key)), 'r') + f = file(os.path.join(self._path, str(key)), 'rb') except IOError, e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -904,11 +909,11 @@ def lock(self): """Lock the mailbox.""" if not self._locked: - self._file = file(os.path.join(self._path, '.mh_sequences'), 'r+') + self._file = file(os.path.join(self._path, '.mh_sequences'), 'rb+') _lock_file(self._file) self._locked = True - def unlock(self, f=None): + def unlock(self): """Unlock the mailbox if it is locked.""" if self._locked: _unlock_file(self._file) @@ -956,7 +961,7 @@ def get_sequences(self): """Return a name-to-key-list dictionary to define each sequence.""" results = {} - f = file(os.path.join(self._path, '.mh_sequences'), 'r') + f = file(os.path.join(self._path, '.mh_sequences'), 'rb') try: all_keys = set(self.keys()) for line in f: @@ -982,7 +987,7 @@ def set_sequences(self, sequences): """Set sequences using the given name-to-key-list dictionary.""" - f = file(os.path.join(self._path, '.mh_sequences'), 'r+') + f = file(os.path.join(self._path, '.mh_sequences'), 'rb+') try: os.close(os.open(f.name, os.O_WRONLY | os.O_TRUNC)) for name, keys in sequences.iteritems(): @@ -1003,7 +1008,7 @@ f.write(' %s' % key) prev = key if completing: - f.write('%s%s' % (prev, os.linesep)) + f.write(str(prev) + os.linesep) else: f.write(os.linesep) finally: @@ -1017,7 +1022,7 @@ for key in self.iterkeys(): if key - 1 != prev: changes.append((key, prev + 1)) - f = file(os.path.join(self._path, str(key)), 'r+') + f = file(os.path.join(self._path, str(key)), 'rb+') try: if self._locked: _lock_file(f) @@ -1039,7 +1044,6 @@ self._next_key = prev + 1 if len(changes) == 0: return - keys = self.keys() for name, key_list in sequences.items(): for old, new in changes: if old in key_list: @@ -1176,16 +1180,17 @@ def _pre_mailbox_hook(self, f): """Called before writing the mailbox to file f.""" - f.write('BABYL OPTIONS:\nVersion: 5\nLabels:%s\n\037' % - ','.join(self.get_labels())) + f.write('BABYL OPTIONS:%sVersion: 5%sLabels:%s%s\037' % + (os.linesep, os.linesep, ','.join(self.get_labels()), + os.linesep)) def _pre_message_hook(self, f): """Called before writing each message to file f.""" - f.write('\014\n') + f.write('\014' + os.linesep) def _post_message_hook(self, f): """Called after writing each message to file f.""" - f.write('\n\037') + f.write(os.linesep + '\037') def _install_message(self, message): """Write message contents and return (start, stop).""" @@ -1204,9 +1209,9 @@ self._file.write(',,') for label in labels: self._file.write(' ' + label + ',') - self._file.write('\n') + self._file.write(os.linesep) else: - self._file.write('1,,\n') + self._file.write('1,,' + os.linesep) if isinstance(message, email.Message.Message): pseudofile = StringIO.StringIO() ps_generator = email.Generator.Generator(pseudofile, False, 0) @@ -1242,7 +1247,7 @@ self._file.write(message[:body_start]) self._file.write(message[body_start:]) else: - self._file.write('*** EOOH ***%s%s' % (os.linesep, os.linesep)) + self._file.write('*** EOOH ***' + os.linesep + os.linesep) self._file.write(message) elif hasattr(message, 'readline'): original_pos = message.tell() @@ -1486,7 +1491,7 @@ try: message.set_date(calendar.timegm(time.strptime(maybe_date, '%a %b %d %H:%M:%S %Y'))) - except ValueError, OverflowError: + except (ValueError, OverflowError): pass elif isinstance(message, _mboxMMDFMessage): message.set_flags(self.get_flags()) @@ -1807,7 +1812,7 @@ pre_lock = _create_temporary(f.name + '.lock') pre_lock.close() except IOError, e: - if e.errno == errno.EACCESS: + if e.errno == errno.EACCES: return # Without write access, just skip dotlocking. else: raise @@ -1846,7 +1851,7 @@ """Create a file if it doesn't exist and open for reading and writing.""" fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR) try: - return file(path, 'r+') + return file(path, 'rb+') finally: os.close(fd) Index: test_mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- test_mailbox.py 21 Aug 2005 21:17:53 -0000 1.9 +++ test_mailbox.py 22 Aug 2005 20:19:28 -0000 1.10 @@ -49,7 +49,7 @@ class TestMailbox(TestBase): _factory = None # Overridden by subclasses to reuse tests - _template = 'From: foo%s%s' % (os.linesep, os.linesep) + '%s' + _template = 'From: foo' + os.linesep + os.linesep + '%s' def setUp(self): self._path = test_support.TESTFN @@ -457,14 +457,19 @@ _factory = lambda self, path, factory=None: mailbox.Maildir(path, factory) + def setUp(self): + TestMailbox.setUp(self) + if os.name == 'nt': + self._box.colon = '!' + def test_add_MM(self): # Add a MaildirMessage instance msg = mailbox.MaildirMessage(self._template % 0) msg.set_subdir('cur') msg.set_info('foo') key = self._box.add(msg) - self.assert_(os.path.exists(os.path.join(self._path, 'cur', - "%s:foo" % key))) + self.assert_(os.path.exists(os.path.join(self._path, 'cur', '%s%sfoo' % + (key, self._box.colon)))) def test_get_MM(self): # Get a MaildirMessage instance @@ -504,10 +509,10 @@ # Initialize a non-existent mailbox self.tearDown() self._box = mailbox.Maildir(self._path) - self._check_basics(factory=rfc822.Message, perms=True) + self._check_basics(factory=rfc822.Message) self._delete_recursively(self._path) self._box = self._factory(self._path, factory=None) - self._check_basics(perms=True) + self._check_basics() def test_initialize_existing(self): # Initialize an existing mailbox @@ -519,7 +524,7 @@ self._box = mailbox.Maildir(self._path, factory=None) self._check_basics() - def _check_basics(self, factory=None, perms=False): + def _check_basics(self, factory=None): # (Used by test_open_new() and test_open_existing().) self.assertEqual(self._box._path, os.path.abspath(self._path)) self.assertEqual(self._box._factory, factory) @@ -527,9 +532,6 @@ path = os.path.join(self._path, subdir) mode = os.stat(path)[stat.ST_MODE] self.assert_(stat.S_ISDIR(mode), "Not a directory: '%s'" % path) - if perms: - self.assert_(stat.S_IMODE(mode) ^ 0700 == 0, - "Accessible by group or other: '%s'" % path) def test_list_folders(self): # List folders @@ -668,20 +670,23 @@ class _TestMboxMMDF(TestMailbox): def tearDown(self): + self._box.close() self._delete_recursively(self._path) for lock_remnant in glob.glob(self._path + '.*'): os.remove(lock_remnant) def test_add_from_string(self): # Add a string starting with 'From ' to the mailbox - key = self._box.add('From foo at bar blah\nFrom: foo\n\n0') + key = self._box.add('From foo at bar blah%sFrom: foo%s%s0' % + (os.linesep, os.linesep, os.linesep)) self.assert_(self._box[key].get_from() == 'foo at bar blah') self.assert_(self._box[key].get_payload() == '0') def test_add_mbox_or_mmdf_message(self): # Add an mboxMessage or MMDFMessage for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage): - msg = class_('From foo at bar blah\nFrom: foo\n\n0') + msg = class_('From foo at bar blah%sFrom: foo%s%s0' % + (os.linesep, os.linesep, os.linesep)) key = self._box.add(msg) def test_open_close_open(self): @@ -708,7 +713,7 @@ self._box._file.seek(0) contents = self._box._file.read() self._box.close() - self.assert_(contents == file(self._path, 'r').read()) + self.assert_(contents == file(self._path, 'rb').read()) self._box = self._factory(self._path) @@ -821,6 +826,12 @@ _factory = lambda self, path, factory=None: mailbox.Babyl(path, factory) + def tearDown(self): + self._box.close() + self._delete_recursively(self._path) + for lock_remnant in glob.glob(self._path + '.*'): + os.remove(lock_remnant) + def test_labels(self): # Get labels from the mailbox self.assert_(self._box.get_labels() == []) @@ -1414,12 +1425,12 @@ proxy.seek(0) self.assert_(proxy.readlines() == ['foo' + os.linesep, 'bar' + os.linesep, - 'fred' + os.linesep, 'bob']) + 'fred' + os.linesep, 'bob']) proxy.seek(0) self.assert_(proxy.readlines(2) == ['foo' + os.linesep]) proxy.seek(3 + len(os.linesep)) - self.assert_(proxy.readlines(5) == ['bar' + os.linesep, - 'fred' + os.linesep]) + self.assert_(proxy.readlines(4 + len(os.linesep)) == + ['bar' + os.linesep, 'fred' + os.linesep]) proxy.seek(3) self.assert_(proxy.readlines(1000) == [os.linesep, 'bar' + os.linesep, 'fred' + os.linesep, 'bob']) @@ -1458,7 +1469,7 @@ def setUp(self): self._path = test_support.TESTFN - self._file = file(self._path, 'w+') + self._file = file(self._path, 'wb+') def tearDown(self): self._file.close() @@ -1507,7 +1518,7 @@ def setUp(self): self._path = test_support.TESTFN - self._file = file(self._path, 'w+') + self._file = file(self._path, 'wb+') def tearDown(self): self._file.close() @@ -1546,7 +1557,7 @@ def test_seek_and_tell(self): self._file.write('(((foo%sbar%s$$$' % (os.linesep, os.linesep)) self._test_seek_and_tell(mailbox._PartialFile(self._file, 3, - 8 + 3 * len(os.linesep))) + 9 + 2 * len(os.linesep))) def test_close(self): self._file.write('&foo%sbar%s^' % (os.linesep, os.linesep)) From nascheme at users.sourceforge.net Mon Aug 22 23:12:20 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Mon, 22 Aug 2005 23:12:20 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0000.txt, 1.341, 1.342 pep-0349.txt, 1.2, 1.3 Message-ID: <20050822211220.256031E4008@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27113 Modified Files: pep-0000.txt pep-0349.txt Log Message: New version of PEP 349. Propose that str() be changed rather than adding a new built-in function. Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.341 retrieving revision 1.342 diff -u -d -r1.341 -r1.342 --- pep-0000.txt 13 Aug 2005 12:37:53 -0000 1.341 +++ pep-0000.txt 22 Aug 2005 21:12:08 -0000 1.342 @@ -105,7 +105,7 @@ S 345 Metadata for Python Software Packages 1.2 Jones P 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon - S 349 Generalized String Coercion Schemenauer + S 349 Allow str() to return unicode strings Schemenauer S 754 IEEE 754 Floating Point Special Values Warnes Finished PEPs (done, implemented in CVS) @@ -393,7 +393,7 @@ SR 346 User Defined ("with") Statements Coghlan P 347 Migrating the Python CVS to Subversion von Lwis S 348 Exception Reorganization for Python 3.0 Cannon - S 349 Generalized String Coercion Schemenauer + S 349 Allow str() to return unicode strings Schemenauer SR 666 Reject Foolish Indentation Creighton S 754 IEEE 754 Floating Point Special Values Warnes I 3000 Python 3.0 Plans Kuchling, Cannon Index: pep-0349.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0349.txt,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- pep-0349.txt 6 Aug 2005 04:05:48 -0000 1.2 +++ pep-0349.txt 22 Aug 2005 21:12:08 -0000 1.3 @@ -1,5 +1,5 @@ PEP: 349 -Title: Generalised String Coercion +Title: Allow str() to return unicode strings Version: $Revision$ Last-Modified: $Date$ Author: Neil Schemenauer @@ -7,20 +7,18 @@ Type: Standards Track Content-Type: text/plain Created: 02-Aug-2005 -Post-History: +Post-History: 06-Aug-2005 Python-Version: 2.5 Abstract - This PEP proposes the introduction of a new built-in function, - text(), that provides a way of generating a string representation - of an object without forcing the result to be a particular string - type. In addition, the behavior %s format specifier would be - changed to call text() on the argument. These two changes would - make it easier to write library code that can be used by - applications that use only the str type and by others that also use - the unicode type. + This PEP proposes to change the str() built-in function so that it + can return unicode strings. This change would make it easier to + write code that works with either string type and would also make + some existing code handle unicode strings. The C function + PyObject_Str() would remain unchanged and the function + PyString_New() would be added instead. Rationale @@ -64,51 +62,35 @@ object; an operation traditionally accomplished by using the str() built-in function. - Using str() makes the code not Unicode-safe. Replacing a str() - call with a unicode() call makes the code not str-stable. Using a - string format almost accomplishes the goal but not quite. - Consider the following code: - - def text(obj): - return '%s' % obj - - It behaves as desired except if 'obj' is not a basestring instance - and needs to return a Unicode representation of itself. In that - case, the string format will attempt to coerce the result of - __str__ to a str instance. Defining a __unicode__ method does not - help since it will only be called if the right-hand operand is a - unicode instance. Using a unicode instance for the right-hand - operand does not work because the function is no longer str-stable - (i.e. it will coerce everything to unicode). + Using the current str() function makes the code not Unicode-safe. + Replacing a str() call with a unicode() call makes the code not + str-stable. Changing str() so that it could return unicode + instances would solve this problem. As a further benefit, some code + that is currently not Unicode-safe because it uses str() would + become Unicode-safe. Specification - A Python implementation of the text() built-in follows: + A Python implementation of the str() built-in follows: - def text(s): + def str(s): """Return a nice string representation of the object. The - return value is a basestring instance. + return value is a str or unicode instance. """ - if isinstance(s, basestring): + if type(s) is str or type(s) is unicode: return s r = s.__str__() - if not isinstance(r, basestring): + if not isinstance(r, (str, unicode)): raise TypeError('__str__ returned non-string') return r - Note that it is currently possible, although not very useful, to - write __str__ methods that return unicode instances. - - The %s format specifier for str objects would be changed to call - text() on the argument. Currently it calls str() unless the - argument is a unicode instance (in which case the object is - substituted as is and the % operation returns a unicode instance). - The following function would be added to the C API and would be the - equivalent of the text() function: + equivalent to the str() built-in (ideally it be called PyObject_Str, + but changing that function could cause a massive number of + compatibility problems): - PyObject *PyObject_Text(PyObject *o); + PyObject *PyString_New(PyObject *); A reference implementation is available on Sourceforge [1] as a patch. @@ -116,52 +98,36 @@ Backwards Compatibility - The change to the %s format specifier would result in some % - operations returning a unicode instance rather than raising a - UnicodeDecodeError exception. It seems unlikely that the change - would break currently working code. - + Some code may require that str() returns a str instance. In the + standard library, only one such case has been found so far. The + function email.header_decode() requires a str instance and the + email.Header.decode_header() function tries to ensure this by + calling str() on its argument. The code was fixed by changing + the line "header = str(header)" to: -Alternative Solutions + if isinstance(header, unicode): + header = header.encode('ascii') - Rather than adding the text() built-in, if PEP 246 were - implemented then adapt(s, basestring) could be equivalent to - text(s). The advantage would be one less built-in function. The - problem is that PEP 246 is not implemented. + Whether this is truly a bug is questionable since decode_header() + really operates on byte strings, not character strings. Code that + passes it a unicode instance could itself be considered buggy. - Fredrik Lundh has suggested [2] that perhaps a new slot should be - added (e.g. __text__), that could return any kind of string that's - compatible with Python's text model. That seems like an - attractive idea but many details would still need to be worked - out. - Instead of providing the text() built-in, the %s format specifier - could be changed and a string format could be used instead of - calling text(). However, it seems like the operation is important - enough to justify a built-in. +Alternative Solutions - Instead of providing the text() built-in, the basestring type - could be changed to provide the same functionality. That would - possibly be confusing behaviour for an abstract base type. + A new built-in function could be added instead of changing str(). + Doing so would introduce virtually no backwards compatibility + problems. However, since the compatibility problems are expected to + rare, changing str() seems preferable to adding a new built-in. - Some people have suggested [3] that an easier migration path would - be to change the default encoding to be UTF-8. Code that is not - Unicode safe would then encode Unicode strings as UTF-8 and - operate on them as str instances, rather than raising a - UnicodeDecodeError exception. Other code would assume that str - instances were encoded using UTF-8 and decode them if necessary. - While that solution may work for some applications, it seems - unsuitable as a general solution. For example, some applications - get string data from many different sources and assuming that all - str instances were encoded using UTF-8 could easily introduce - subtle bugs. + The basestring type could be changed to have the proposed behaviour, + rather than changing str(). However, that would be confusing + behaviour for an abstract base type. References - [1] http://www.python.org/sf/1159501 - [2] http://mail.python.org/pipermail/python-dev/2004-September/048755.html - [3] http://blog.ianbicking.org/illusive-setdefaultencoding.html + [1] http://www.python.org/sf/1266570 Copyright From akuchling at users.sourceforge.net Tue Aug 23 02:56:17 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue, 23 Aug 2005 02:56:17 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew25.tex, 1.17, 1.18 Message-ID: <20050823005617.6D0901E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12839 Modified Files: whatsnew25.tex Log Message: Note various items; write some shorter sections Index: whatsnew25.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew25.tex,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- whatsnew25.tex 21 Aug 2005 18:46:00 -0000 1.17 +++ whatsnew25.tex 23 Aug 2005 00:56:06 -0000 1.18 @@ -114,6 +114,29 @@ %====================================================================== \section{PEP 342: New Generator Features} +As introduced in Python 2.3, generators only produce output; once a +generator's code was invoked to create an iterator, there's no way to +pass new parameters into the function when its execution is resumed. +(Well, you could make the generator's code look at a global +variable and modify the global value, but this is an unreliable hack +that doesn't work if you have multiple instances of the same generator +alive at the same time.) + +Python 2.5 adds the ability to pass values \emph{into} a generator. + +To refresh your memory of basic generators, here's a simple example: + +\begin{verbatim} +def counter (maximum): + i = 0 + while i < maximum: + yield i + i += 1 +\end{verbatim} + +On executing the \ +When you call \code{counter(10)}, the result is an + XXX write this section \begin{seealso} @@ -151,6 +174,16 @@ (Contributed by Steven Bethard and Raymond Hettinger.) +\item Two new built-in functions, \function{any()} and +\function{all()}, evaluate whether an iterator contains any true or +false values. \function{any()} returns \constant{True} if any value +returned by the iterator is true; otherwise it will return +\constant{False}. \function{all()} returns \constant{True} only if +all of the values returned by the iterator evaluate as being true. + +% XXX who added? + + \item The list of base classes in a class definition can now be empty. As an example, this is now legal: @@ -168,7 +201,12 @@ \begin{itemize} -\item Optimizations should be described here. +\item When they were introduced +in Python 2.4, the built-in \class{set} and \class{frozenset} types +were built on top of Python's dictionary type. +In 2.5 the internal data structure has been customized for implementing sets, +and as a result sets will use a third less memory and are somewhat faster. +(Implemented by Raymond Hettinger.) \end{itemize} @@ -188,6 +226,8 @@ \begin{itemize} +% collections.deque now has .remove() + % the cPickle module no longer accepts the deprecated None option in the % args tuple returned by __reduce__(). @@ -196,6 +236,14 @@ % datetime.datetime() now has a strptime class method which can be used to % create datetime object using a string and format. +\item A new \module{hashlib} module has been added to replace the +\module{md5} and \module{sha} modules. \module{hashlib} adds support +for additional secure hashes (SHA-224, SHA-256, SHA-384, and SHA-512). +When available, the module uses OpenSSL for fast platform optimized +implementations of algorithms. The old \module{md5} and \module{sha} +modules still exist as wrappers around hashlib to preserve backwards +compatibility. (Contributed by Gregory P. Smith.) + \item The \function{nsmallest()} and \function{nlargest()} functions in the \module{heapq} module now support a \code{key} keyword argument similar to the one @@ -226,9 +274,16 @@ (Contributed by Raymond Hettinger.) -\item New module: \module{spwd} provides functions for accessing the -shadow password database on systems that support it. -% XXX give example +\item The \module{operator} module's \function{itemgetter()} +and \function{attrgetter()} functions now support multiple fields. +A call such as \code{operator.attrgetter('a', 'b')} +will return a function +that retrieves the \member{a} and \member{b} attributes. Combining +this new feature with the \method{sort()} method's \code{key} parameter +lets you easily sort lists using multiple fields. + +% XXX who added? + \item The \module{os} module underwent a number of changes. The \member{stat_float_times} variable now defaults to true, meaning that @@ -237,24 +292,38 @@ that are precise to fractions of a second; not all systems support such precision.) -Also, constants named \member{os.SEEK_SET}, \member{os.SEEK_CUR}, and +Constants named \member{os.SEEK_SET}, \member{os.SEEK_CUR}, and \member{os.SEEK_END} have been added; these are the parameters to the -\function{os.lseek()} function. +\function{os.lseek()} function. Two new constants for locking are +\member{os.O_SHLOCK} and \member{os.O_EXLOCK}. + +On FreeBSD, the \function{os.stat()} function now returns +times with nanosecond resolution, and the returned object +now has \member{st_gen} and \member{st_birthtime}. +The \member{st_flags} member is also available, if the platform supports it. +% XXX patch 1180695, 1212117 + +\item New module: \module{spwd} provides functions for accessing the +shadow password database on systems that support it. +% XXX give example \item The \class{TarFile} class in the \module{tarfile} module now has an \method{extractall()} method that extracts all members from the archive into the current working directory. It's also possible to set a different directory as the extraction target, and to unpack only a -subset of the archive's members. (Contributed by Lars Gust\"abel.) +subset of the archive's members. -\item A new \module{hashlib} module has been added to replace the -\module{md5} and \module{sha} modules and adds support for additional -secure hashes such as SHA-256 and SHA-512. The \module{hashlib} module -uses OpenSSL for fast platform optimized implementations of algorithms -when available. The old \module{md5} and \module{sha} modules still -exist as wrappers around hashlib to preserve backwards compatibility. +A tarfile's compression can be autodetected by +using the mode \code{'r|*'}. +% patch 918101 +(Contributed by Lars Gust\"abel.) + +\item The \module{xmlrpclib} module now supports returning + \class{datetime} objects for the XML-RPC date type. Supply + \code{use_datetime=True} to the \function{loads()} function + or the \class{Unmarshaller} class to enable this feature. +% XXX patch 1120353 -(Contributed by Gregory P. Smith.) \end{itemize} @@ -263,6 +332,10 @@ %====================================================================== % whole new modules get described in \subsections here +% XXX new distutils features: upload + + + % ====================================================================== \section{Build and C API Changes} @@ -271,8 +344,15 @@ \begin{itemize} -\item The \cfunction{PyRange_New()} function was removed. It was never documented, -never used in the core code, and had dangerously lax error checking. +\item The built-in set types now have an official C API. Call +\cfunction{PySet_New()} and \cfunction{PyFrozenSet_New()} to create a +new set, \cfunction{PySet_Add()} and \cfunction{PySet_Discard()} to +add and remove elements, and \cfunction{PySet_Contains} and +\cfunction{PySet_Size} to examine the set's state. + +\item The \cfunction{PyRange_New()} function was removed. It was +never documented, never used in the core code, and had dangerously lax +error checking. \end{itemize} From akuchling at users.sourceforge.net Tue Aug 23 02:57:17 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue, 23 Aug 2005 02:57:17 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1337,1.1338 Message-ID: <20050823005717.48B1B1E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12938 Modified Files: NEWS Log Message: Typo fixes Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1337 retrieving revision 1.1338 diff -u -d -r1.1337 -r1.1338 --- NEWS 22 Aug 2005 18:02:59 -0000 1.1337 +++ NEWS 23 Aug 2005 00:57:07 -0000 1.1338 @@ -136,7 +136,7 @@ for large or negative values. - Bug #1234979: For the argument of thread.Lock.acquire, the Windows - implemented treated all integer values except 1 as false. + implementation treated all integer values except 1 as false. - Bug #1194181: bz2.BZ2File didn't handle mode 'U' correctly. @@ -203,7 +203,7 @@ - Bug #1238170: threading.Thread.__init__ no longer has "kwargs={}" as a parameter, but uses the usual "kwargs=None". -- textwrap now processes text chucks at O(n) speed instead of O(n**2). +- textwrap now processes text chunks at O(n) speed instead of O(n**2). Patch #1209527 (Contributed by Connelly). - urllib2 has now an attribute 'httpresponses' mapping from HTTP status code @@ -213,7 +213,7 @@ as this can cause problems with apps closing all file descriptors. - Bug #839151: Fix an attempt to access sys.argv in the warnings module - though this can be missing in embedded interpreters + it can be missing in embedded interpreters - Bug #1155638: Fix a bug which affected HTTP 0.9 responses in httplib. @@ -351,7 +351,7 @@ - locale.py now uses an updated locale alias table (built using Tools/i18n/makelocalealias.py, a tool to parse the X11 locale alias file); the encoding lookup was enhanced to use Python's - encoding alias table + encoding alias table. - moved deprecated modules to Lib/lib-old: whrandom, tzparse, statcache. From kbk at users.sourceforge.net Tue Aug 23 04:27:33 2005 From: kbk at users.sourceforge.net (kbk@users.sourceforge.net) Date: Tue, 23 Aug 2005 04:27:33 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/idlelib NEWS.txt, 1.61, 1.62 ScriptBinding.py, 1.30, 1.31 Message-ID: <20050823022733.6C1C41E4002@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/idlelib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30659 Modified Files: NEWS.txt ScriptBinding.py Log Message: 1. Mac line endings were incorrect when pasting code from some browsers when using X11 and the Fink distribution. Python Bug 1263656. 2. Eliminate duplicated code in ScriptBinding.run_module_event() Modified Files: NEWS.txt ScriptBinding.py Index: NEWS.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/NEWS.txt,v retrieving revision 1.61 retrieving revision 1.62 diff -u -d -r1.61 -r1.62 --- NEWS.txt 19 Jun 2005 18:56:15 -0000 1.61 +++ NEWS.txt 23 Aug 2005 02:27:23 -0000 1.62 @@ -3,6 +3,9 @@ *Release date: XX-XXX-2005* +- Mac line endings were incorrect when pasting code from some browsers + when using X11 and the Fink distribution. Python Bug 1263656. + - when cursor is on a previous command retrieves that command. Instead of replacing the input line, the previous command is now appended to the input line. Indentation is preserved, and undo is enabled. Index: ScriptBinding.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/ScriptBinding.py,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- ScriptBinding.py 12 Jun 2005 05:19:23 -0000 1.30 +++ ScriptBinding.py 23 Aug 2005 02:27:23 -0000 1.31 @@ -53,7 +53,7 @@ self.flist = self.editwin.flist self.root = self.flist.root - def check_module_event(self, event): + def check_module_event(self, event=None): filename = self.getfilename() if not filename: return @@ -87,6 +87,7 @@ f.close() if '\r' in source: source = re.sub(r"\r\n", "\n", source) + source = re.sub(r"\r", "\n", source) if source and source[-1] != '\n': source = source + '\n' text = self.editwin.text @@ -132,12 +133,7 @@ add that directory to its sys.path if not already included. """ - filename = self.getfilename() - if not filename: - return - if not self.tabnanny(filename): - return - code = self.checksyntax(filename) + code = self.check_module_event(event) if not code: return shell = self.shell From kbk at users.sourceforge.net Tue Aug 23 05:25:48 2005 From: kbk at users.sourceforge.net (kbk@users.sourceforge.net) Date: Tue, 23 Aug 2005 05:25:48 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/idlelib ScriptBinding.py, 1.31, 1.32 Message-ID: <20050823032548.67F1E1E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/idlelib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8689 Modified Files: ScriptBinding.py Log Message: Revert previous code elimination, 'filename' is needed. Index: ScriptBinding.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/ScriptBinding.py,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- ScriptBinding.py 23 Aug 2005 02:27:23 -0000 1.31 +++ ScriptBinding.py 23 Aug 2005 03:25:38 -0000 1.32 @@ -53,7 +53,7 @@ self.flist = self.editwin.flist self.root = self.flist.root - def check_module_event(self, event=None): + def check_module_event(self, event): filename = self.getfilename() if not filename: return @@ -133,7 +133,12 @@ add that directory to its sys.path if not already included. """ - code = self.check_module_event(event) + filename = self.getfilename() + if not filename: + return + if not self.tabnanny(filename): + return + code = self.checksyntax(filename) if not code: return shell = self.shell From gregorykjohnson at users.sourceforge.net Tue Aug 23 05:43:21 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Tue, 23 Aug 2005 05:43:21 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox libmailbox.tex, 1.14, 1.15 mailbox.py, 1.15, 1.16 test_mailbox.py, 1.10, 1.11 Message-ID: <20050823034321.DD9D31E4008@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9944 Modified Files: libmailbox.tex mailbox.py test_mailbox.py Log Message: * Overhaul handling of line endings to play more nicely with the email and smtplib modules and to be less surprising: * Message instances and strings use C-style '\n' line endings, and files passed to add() or __setitem__() should be text-mode. * When written to disk, messages use native line endings. * As in the older module, file-like objects supplied to a message factory (or returned by get_file()) are still binary-mode-like. Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- libmailbox.tex 22 Aug 2005 20:19:27 -0000 1.14 +++ libmailbox.tex 23 Aug 2005 03:43:11 -0000 1.15 @@ -62,11 +62,12 @@ it. Parameter \var{message} may be a \class{Message} instance, an -\class{email.Message.Message} instance, a string, or a file-like object. If -\var{message} is an instance of the appropriate format-specific -\class{Message} subclass (e.g., if it's an \class{mboxMessage} instance and -this is an \class{mbox} instance), its format-specific information is used. -Otherwise, reasonable defaults for format-specific information are used. +\class{email.Message.Message} instance, a string, or a file-like object (which +should be open in text mode). If \var{message} is an instance of the +appropriate format-specific \class{Message} subclass (e.g., if it's an +\class{mboxMessage} instance and this is an \class{mbox} instance), its +format-specific information is used. Otherwise, reasonable defaults for +format-specific information are used. \end{methoddesc} \begin{methoddesc}{remove}{key} @@ -87,11 +88,11 @@ As with \method{add()}, parameter \var{message} may be a \class{Message} instance, an \class{email.Message.Message} instance, a string, or a file-like -object. If \var{message} is an instance of the appropriate format-specific -\class{Message} subclass (e.g., if it's an \class{mboxMessage} instance and -this is an \class{mbox} instance), its format-specific information is used. -Otherwise, the format-specific information of the message that currently -corresponds to \var{key} is left unchanged. +object (which should be open in text mode). If \var{message} is an instance of +the appropriate format-specific \class{Message} subclass (e.g., if it's an +\class{mboxMessage} instance and this is an \class{mbox} instance), its +format-specific information is used. Otherwise, the format-specific information +of the message that currently corresponds to \var{key} is left unchanged. \end{methoddesc} \begin{methoddesc}{iterkeys}{} @@ -146,8 +147,9 @@ \begin{methoddesc}{get_file}{key} Return a file-like representation of the message corresponding to \var{key}, -or raise a \exception{KeyError} exception if no such message exists. This file -should be closed once it is no longer needed. +or raise a \exception{KeyError} exception if no such message exists. The +file-like object behaves as if open in binary mode. This file should be closed +once it is no longer needed. \note{Unlike other representations of messages, file-like representations are not necessarily independent of the \class{Mailbox} instance that created them @@ -228,10 +230,10 @@ create=True}}} A subclass of \class{Mailbox} for mailboxes in Maildir format. Parameter \var{factory} is a callable object that accepts a file-like message -representation and returns a custom representation. If \var{factory} is -\code{None}, \class{MaildirMessage} is used as the default message -representation. If \var{create} is \code{True}, the mailbox is created if it -does not exist. +representation (which behaves as if open in binary mode) and returns a custom +representation. If \var{factory} is \code{None}, \class{MaildirMessage} is used +as the default message representation. If \var{create} is \code{True}, the +mailbox is created if it does not exist. It is for historical reasons that \var{factory} defaults to \class{rfc822.Message} and that \var{dirname} is named as such rather than @@ -353,9 +355,10 @@ \begin{classdesc}{mbox}{path\optional{, factory=None\optional{, create=True}}} A subclass of \class{Mailbox} for mailboxes in mbox format. Parameter \var{factory} is a callable object that accepts a file-like message -representation and returns a custom representation. If \var{factory} is -\code{None}, \class{mboxMessage} is used as the default message representation. -If \var{create} is \code{True}, the mailbox is created if it does not exist. +representation (which behaves as if open in binary mode) and returns a custom +representation. If \var{factory} is \code{None}, \class{mboxMessage} is used as +the default message representation. If \var{create} is \code{True}, the mailbox +is created if it does not exist. \end{classdesc} The mbox format is the classic format for storing mail on \UNIX{} systems. All @@ -405,9 +408,10 @@ \begin{classdesc}{MH}{path\optional{, factory=None\optional{, create=True}}} A subclass of \class{Mailbox} for mailboxes in MH format. Parameter \var{factory} is a callable object that accepts a file-like message -representation and returns a custom representation. If \var{factory} is -\code{None}, \class{MHMessage} is used as the default message representation. -If \var{create} is \code{True}, the mailbox is created if it does not exist. +representation (which behaves as if open in binary mode) and returns a custom +representation. If \var{factory} is \code{None}, \class{MHMessage} is used as +the default message representation. If \var{create} is \code{True}, the mailbox +is created if it does not exist. \end{classdesc} MH is a directory-based mailbox format invented for the MH Message Handling @@ -511,10 +515,10 @@ \begin{classdesc}{Babyl}{path\optional{, factory=None\optional{, create=True}}} A subclass of \class{Mailbox} for mailboxes in Babyl format. Parameter \var{factory} is a callable object that accepts a file-like message -representation and returns a custom representation. If \var{factory} is -\code{None}, \class{BabylMessage} is used as the default message -representation. If \var{create} is \code{True}, the mailbox is created if it -does not exist. +representation (which behaves as if open in binary mode) and returns a custom +representation. If \var{factory} is \code{None}, \class{BabylMessage} is used +as the default message representation. If \var{create} is \code{True}, the +mailbox is created if it does not exist. \end{classdesc} Babyl is a single-file mailbox format invented for the Rmail mail user agent @@ -574,9 +578,10 @@ \begin{classdesc}{MMDF}{path\optional{, factory=None\optional{, create=True}}} A subclass of \class{Mailbox} for mailboxes in MMDF format. Parameter \var{factory} is a callable object that accepts a file-like message -representation and returns a custom representation. If \var{factory} is -\code{None}, \class{MMDFMessage} is used as the default message representation. -If \var{create} is \code{True}, the mailbox is created if it does not exist. +representation (which behaves as if open in binary mode) and returns a custom +representation. If \var{factory} is \code{None}, \class{MMDFMessage} is used as +the default message representation. If \var{create} is \code{True}, the mailbox +is created if it does not exist. \end{classdesc} MMDF is a single-file mailbox format invented for the Multichannel Memorandum @@ -1010,7 +1015,8 @@ \begin{methoddesc}{set_visible}{visible} Set the message's visible headers to be the same as the headers in \var{message}. Parameter \var{visible} should be a \class{Message} instance, an -\class{email.Message.Message} instance, a string, or a file-like object. +\class{email.Message.Message} instance, a string, or a file-like object (which +should be open in text mode). \end{methoddesc} \begin{methoddesc}{update_visible}{} Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- mailbox.py 22 Aug 2005 20:19:28 -0000 1.15 +++ mailbox.py 23 Aug 2005 03:43:11 -0000 1.16 @@ -183,30 +183,30 @@ raise NotImplementedError('Method must be implemented by subclass') def _dump_message(self, message, target, mangle_from_=False): + # Most files are opened in binary mode to allow predictable seeking. + # To get native line endings on disk, the user-friendly \n line endings + # used in strings and by email.Message are translated here. """Dump message contents to target file.""" if isinstance(message, email.Message.Message): - generator = email.Generator.Generator(target, mangle_from_, 0) - generator.flatten(message) + buffer = StringIO.StringIO() + gen = email.Generator.Generator(buffer, mangle_from_, 0) + gen.flatten(message) + buffer.seek(0) + target.write(buffer.read().replace('\n', os.linesep)) elif isinstance(message, str): if mangle_from_: - message = message.replace(os.linesep + 'From ', - os.linesep + '>From ') + message = message.replace('\nFrom ', '\n>From ') + message = message.replace('\n', os.linesep) target.write(message) elif hasattr(message, 'read'): - if mangle_from_: - while True: - line = message.readline() - if line == '': - break - if line.startswith('From '): - line = '>From ' + line[5:] - target.write(line) - else: - while True: - buffer = message.read(4096) # Buffer size is arbitrary. - if buffer == '': - break - target.write(buffer) + while True: + line = message.readline() + if line == '': + break + if mangle_from_ and line.startswith('From '): + line = '>From ' + line[5:] + line = line.replace('\n', os.linesep) + target.write(line) else: raise TypeError('Invalid message type: %s' % type(message)) @@ -294,7 +294,7 @@ def get_message(self, key): """Return a Message representation or raise a KeyError.""" subpath = self._lookup(key) - f = file(os.path.join(self._path, subpath), 'rb') + f = file(os.path.join(self._path, subpath), 'r') try: msg = MaildirMessage(f) finally: @@ -308,7 +308,7 @@ def get_string(self, key): """Return a string representation or raise a KeyError.""" - f = file(os.path.join(self._path, self._lookup(key)), 'rb') + f = file(os.path.join(self._path, self._lookup(key)), 'r') try: return f.read() finally: @@ -627,9 +627,10 @@ """Return a Message representation or raise a KeyError.""" start, stop = self._lookup(key) self._file.seek(start) - from_line = self._file.readline() - msg = self._message_factory(self._file.read(stop - self._file.tell())) - msg.set_from(from_line[5:-len(os.linesep)]) + from_line = self._file.readline().replace(os.linesep, '') + string = self._file.read(stop - self._file.tell()) + msg = self._message_factory(string.replace(os.linesep, '\n')) + msg.set_from(from_line[5:]) return msg def get_string(self, key, from_=False): @@ -638,7 +639,8 @@ self._file.seek(start) if not from_: self._file.readline() - return self._file.read(stop - self._file.tell()) + string = self._file.read(stop - self._file.tell()) + return string.replace(os.linesep, '\n') def get_file(self, key, from_=False): """Return a file-like representation or raise a KeyError.""" @@ -652,10 +654,10 @@ """Format a message and blindly write to self._file.""" from_line = None if isinstance(message, str) and message.startswith('From '): - newline = message.find(os.linesep) + newline = message.find('\n') if newline != -1: from_line = message[:newline] - message = message[newline + len(os.linesep):] + message = message[newline + 1:] else: from_line = message message = '' @@ -836,9 +838,9 @@ """Return a Message representation or raise a KeyError.""" try: if self._locked: - f = file(os.path.join(self._path, str(key)), 'rb+') + f = file(os.path.join(self._path, str(key)), 'r+') else: - f = file(os.path.join(self._path, str(key)), 'rb') + f = file(os.path.join(self._path, str(key)), 'r') except IOError, e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -863,9 +865,9 @@ """Return a string representation or raise a KeyError.""" try: if self._locked: - f = file(os.path.join(self._path, str(key)), 'rb+') + f = file(os.path.join(self._path, str(key)), 'r+') else: - f = file(os.path.join(self._path, str(key)), 'rb') + f = file(os.path.join(self._path, str(key)), 'r') except IOError, e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -961,7 +963,7 @@ def get_sequences(self): """Return a name-to-key-list dictionary to define each sequence.""" results = {} - f = file(os.path.join(self._path, '.mh_sequences'), 'rb') + f = file(os.path.join(self._path, '.mh_sequences'), 'r') try: all_keys = set(self.keys()) for line in f: @@ -987,7 +989,7 @@ def set_sequences(self, sequences): """Set sequences using the given name-to-key-list dictionary.""" - f = file(os.path.join(self._path, '.mh_sequences'), 'rb+') + f = file(os.path.join(self._path, '.mh_sequences'), 'r+') try: os.close(os.open(f.name, os.O_WRONLY | os.O_TRUNC)) for name, keys in sequences.iteritems(): @@ -1008,9 +1010,9 @@ f.write(' %s' % key) prev = key if completing: - f.write(str(prev) + os.linesep) + f.write(str(prev) + '\n') else: - f.write(os.linesep) + f.write('\n') finally: f.close() @@ -1022,7 +1024,7 @@ for key in self.iterkeys(): if key - 1 != prev: changes.append((key, prev + 1)) - f = file(os.path.join(self._path, str(key)), 'rb+') + f = file(os.path.join(self._path, str(key)), 'r+') try: if self._locked: _lock_file(f) @@ -1105,14 +1107,15 @@ line = self._file.readline() if line == '*** EOOH ***' + os.linesep or line == '': break - original_headers.write(line) + original_headers.write(line.replace(os.linesep, '\n')) visible_headers = StringIO.StringIO() while True: line = self._file.readline() if line == os.linesep or line == '': break - visible_headers.write(line) - body = self._file.read(stop - self._file.tell()) + visible_headers.write(line.replace(os.linesep, '\n')) + body = self._file.read(stop - self._file.tell()).replace(os.linesep, + '\n') msg = BabylMessage(original_headers.getvalue() + body) msg.set_visible(visible_headers.getvalue()) if key in self._labels: @@ -1129,13 +1132,14 @@ line = self._file.readline() if line == '*** EOOH ***' + os.linesep or line == '': break - original_headers.write(line) + original_headers.write(line.replace(os.linesep, '\n')) while True: line = self._file.readline() if line == os.linesep or line == '': break return original_headers.getvalue() + \ - self._file.read(stop - self._file.tell()) + self._file.read(stop - self._file.tell()).replace(os.linesep, + '\n') def get_file(self, key): """Return a file-like representation or raise a KeyError.""" @@ -1213,49 +1217,57 @@ else: self._file.write('1,,' + os.linesep) if isinstance(message, email.Message.Message): - pseudofile = StringIO.StringIO() - ps_generator = email.Generator.Generator(pseudofile, False, 0) - ps_generator.flatten(message) - pseudofile.seek(0) + orig_buffer = StringIO.StringIO() + orig_generator = email.Generator.Generator(orig_buffer, False, 0) + orig_generator.flatten(message) + orig_buffer.seek(0) while True: - line = pseudofile.readline() - self._file.write(line) - if line == os.linesep or line == '': + line = orig_buffer.readline() + self._file.write(line.replace('\n', os.linesep)) + if line == '\n' or line == '': break self._file.write('*** EOOH ***' + os.linesep) if isinstance(message, BabylMessage): - generator = email.Generator.Generator(self._file, False, 0) - generator.flatten(message.get_visible()) + vis_buffer = StringIO.StringIO() + vis_generator = email.Generator.Generator(vis_buffer, False, 0) + vis_generator.flatten(message.get_visible()) + while True: + line = vis_buffer.readline() + self._file.write(line.replace('\n', os.linesep)) + if line == '\n' or line == '': + break else: - pseudofile.seek(0) + orig_buffer.seek(0) while True: - line = pseudofile.readline() - self._file.write(line) - if line == os.linesep or line == '': + line = orig_buffer.readline() + self._file.write(line.replace('\n', os.linesep)) + if line == '\n' or line == '': break while True: - buffer = pseudofile.read(4096) # Buffer size is arbitrary. + buffer = orig_buffer.read(4096) # Buffer size is arbitrary. if buffer == '': break - self._file.write(buffer) + self._file.write(buffer.replace('\n', os.linesep)) elif isinstance(message, str): - body_start = message.find(os.linesep + os.linesep) + \ - 2 * len(os.linesep) - if body_start - 2 * len(os.linesep) != -1: - self._file.write(message[:body_start]) + body_start = message.find('\n\n') + 2 + if body_start - 2 != -1: + self._file.write(message[:body_start].replace('\n', + os.linesep)) self._file.write('*** EOOH ***' + os.linesep) - self._file.write(message[:body_start]) - self._file.write(message[body_start:]) + self._file.write(message[:body_start].replace('\n', + os.linesep)) + self._file.write(message[body_start:].replace('\n', + os.linesep)) else: self._file.write('*** EOOH ***' + os.linesep + os.linesep) - self._file.write(message) + self._file.write(message.replace('\n', os.linesep)) elif hasattr(message, 'readline'): original_pos = message.tell() first_pass = True while True: line = message.readline() - self._file.write(line) - if line == os.linesep or line == '': + self._file.write(line.replace('\n', os.linesep)) + if line == '\n' or line == '': self._file.write('*** EOOH ***' + os.linesep) if first_pass: first_pass = False @@ -1266,7 +1278,7 @@ buffer = message.read(4096) # Buffer size is arbitrary. if buffer == '': break - self._file.write(buffer) + self._file.write(buffer.replace('\n', os.linesep)) else: raise TypeError('Invalid message type: %s' % type(message)) stop = self._file.tell() Index: test_mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/test_mailbox.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- test_mailbox.py 22 Aug 2005 20:19:28 -0000 1.10 +++ test_mailbox.py 23 Aug 2005 03:43:11 -0000 1.11 @@ -49,7 +49,7 @@ class TestMailbox(TestBase): _factory = None # Overridden by subclasses to reuse tests - _template = 'From: foo' + os.linesep + os.linesep + '%s' + _template = 'From: foo\n\n%s' def setUp(self): self._path = test_support.TESTFN @@ -72,8 +72,7 @@ self.assert_(len(self._box) == 4) keys.append(self._box.add(_sample_message)) self.assert_(len(self._box) == 5) - self.assert_(self._box.get_string(keys[0]) == self._template % 0, - self._box.get_string(keys[0])) + self.assert_(self._box.get_string(keys[0]) == self._template % 0) for i in (1, 2, 3, 4): self._check_sample(self._box[keys[i]]) @@ -167,8 +166,10 @@ # Get file representations of messages key0 = self._box.add(self._template % 0) key1 = self._box.add(_sample_message) - self.assert_(self._box.get_file(key0).read() == self._template % 0) - self.assert_(self._box.get_file(key1).read() == _sample_message) + self.assert_(self._box.get_file(key0).read().replace(os.linesep, '\n') + == self._template % 0) + self.assert_(self._box.get_file(key1).read().replace(os.linesep, '\n') + == _sample_message) def test_iterkeys(self): # Get keys using iterkeys() @@ -408,7 +409,8 @@ _sample_message, StringIO.StringIO(_sample_message)): output = StringIO.StringIO() self._box._dump_message(input, output) - self.assert_(output.getvalue() == _sample_message) + self.assert_(output.getvalue() == + _sample_message.replace('\n', os.linesep)) output = StringIO.StringIO() self.assertRaises(TypeError, lambda: self._box._dump_message(None, output)) @@ -677,16 +679,14 @@ def test_add_from_string(self): # Add a string starting with 'From ' to the mailbox - key = self._box.add('From foo at bar blah%sFrom: foo%s%s0' % - (os.linesep, os.linesep, os.linesep)) + key = self._box.add('From foo at bar blah\nFrom: foo\n\n0') self.assert_(self._box[key].get_from() == 'foo at bar blah') self.assert_(self._box[key].get_payload() == '0') def test_add_mbox_or_mmdf_message(self): # Add an mboxMessage or MMDFMessage for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage): - msg = class_('From foo at bar blah%sFrom: foo%s%s0' % - (os.linesep, os.linesep, os.linesep)) + msg = class_('From foo at bar blah\nFrom: foo\n\n0') key = self._box.add(msg) def test_open_close_open(self): From fdrake at users.sourceforge.net Tue Aug 23 06:06:58 2005 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Tue, 23 Aug 2005 06:06:58 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib markupbase.py,1.10,1.11 Message-ID: <20050823040658.AC7911E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17382/Lib Modified Files: markupbase.py Log Message: add note about "markupbase" not being intended for direct use (closes SF bug #736659, patch #901369) Index: markupbase.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/markupbase.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- markupbase.py 10 Jul 2004 21:49:45 -0000 1.10 +++ markupbase.py 23 Aug 2005 04:06:46 -0000 1.11 @@ -1,4 +1,10 @@ -"""Shared support for scanning document type declarations in HTML and XHTML.""" +"""Shared support for scanning document type declarations in HTML and XHTML. + +This module is used as a foundation for the HTMLParser and sgmllib +modules (indirectly, for htmllib as well). It has no documented +public API and should not be used directly. + +""" import re From fdrake at users.sourceforge.net Tue Aug 23 06:08:22 2005 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Tue, 23 Aug 2005 06:08:22 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib markupbase.py,1.10,1.10.4.1 Message-ID: <20050823040822.966411E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17990/Lib Modified Files: Tag: release24-maint markupbase.py Log Message: add note about "markupbase" not being intended for direct use (closes SF bug #736659, patch #901369; backport of Lib/markupbase.py 1.11) Index: markupbase.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/markupbase.py,v retrieving revision 1.10 retrieving revision 1.10.4.1 diff -u -d -r1.10 -r1.10.4.1 --- markupbase.py 10 Jul 2004 21:49:45 -0000 1.10 +++ markupbase.py 23 Aug 2005 04:08:12 -0000 1.10.4.1 @@ -1,4 +1,10 @@ -"""Shared support for scanning document type declarations in HTML and XHTML.""" +"""Shared support for scanning document type declarations in HTML and XHTML. + +This module is used as a foundation for the HTMLParser and sgmllib +modules (indirectly, for htmllib as well). It has no documented +public API and should not be used directly. + +""" import re From fdrake at users.sourceforge.net Tue Aug 23 06:33:40 2005 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Tue, 23 Aug 2005 06:33:40 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libfuncs.tex, 1.187, 1.188 Message-ID: <20050823043340.A7C281E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21725/lib Modified Files: libfuncs.tex Log Message: ord() documentation update; this is what remains applicable from SF patch #1057588; other changes make the rest of the patch out of date or otherwise unnecessary Index: libfuncs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libfuncs.tex,v retrieving revision 1.187 retrieving revision 1.188 diff -u -d -r1.187 -r1.188 --- libfuncs.tex 21 Aug 2005 11:58:06 -0000 1.187 +++ libfuncs.tex 23 Aug 2005 04:33:29 -0000 1.188 @@ -716,11 +716,16 @@ \end{funcdesc} \begin{funcdesc}{ord}{c} - Return the \ASCII{} value of a string of one character or a Unicode - character. E.g., \code{ord('a')} returns the integer \code{97}, + Given a string of length one, return an integer representing the + Unicode code point of the character when the argument is a unicode object, + or the value of the byte when the argument is an 8-bit string. + For example, \code{ord('a')} returns the integer \code{97}, \code{ord(u'\e u2020')} returns \code{8224}. This is the inverse of - \function{chr()} for strings and of \function{unichr()} for Unicode - characters. + \function{chr()} for 8-bit strings and of \function{unichr()} for unicode + objects. If a unicode argument is given and Python was built with + UCS2 Unicode, then the character's code point must be in the range + [0..65535] inclusive; otherwise the string length is two, and a + \exception{TypeError} will be raised. \end{funcdesc} \begin{funcdesc}{pow}{x, y\optional{, z}} From fdrake at users.sourceforge.net Tue Aug 23 06:35:32 2005 From: fdrake at users.sourceforge.net (fdrake@users.sourceforge.net) Date: Tue, 23 Aug 2005 06:35:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libfuncs.tex, 1.175.2.7, 1.175.2.8 Message-ID: <20050823043532.667511E4008@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21972/lib Modified Files: Tag: release24-maint libfuncs.tex Log Message: ord() documentation update; this is what remains applicable from SF patch #1057588; other changes make the rest of the patch out of date or otherwise unnecessary (backported from trunk revision 1.188) Index: libfuncs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libfuncs.tex,v retrieving revision 1.175.2.7 retrieving revision 1.175.2.8 diff -u -d -r1.175.2.7 -r1.175.2.8 --- libfuncs.tex 21 Aug 2005 11:59:04 -0000 1.175.2.7 +++ libfuncs.tex 23 Aug 2005 04:35:22 -0000 1.175.2.8 @@ -678,11 +678,16 @@ \end{funcdesc} \begin{funcdesc}{ord}{c} - Return the \ASCII{} value of a string of one character or a Unicode - character. E.g., \code{ord('a')} returns the integer \code{97}, + Given a string of length one, return an integer representing the + Unicode code point of the character when the argument is a unicode object, + or the value of the byte when the argument is an 8-bit string. + For example, \code{ord('a')} returns the integer \code{97}, \code{ord(u'\e u2020')} returns \code{8224}. This is the inverse of - \function{chr()} for strings and of \function{unichr()} for Unicode - characters. + \function{chr()} for 8-bit strings and of \function{unichr()} for unicode + objects. If a unicode argument is given and Python was built with + UCS2 Unicode, then the character's code point must be in the range + [0..65535] inclusive; otherwise the string length is two, and a + \exception{TypeError} will be raised. \end{funcdesc} \begin{funcdesc}{pow}{x, y\optional{, z}} From pje at users.sourceforge.net Tue Aug 23 15:24:52 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Tue, 23 Aug 2005 15:24:52 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command bdist_egg.py, 1.29, 1.30 easy_install.py, 1.23, 1.24 Message-ID: <20050823132452.A21E11E400B@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28556/setuptools/command Modified Files: bdist_egg.py easy_install.py Log Message: Simplify non-root install process and improve Mac OS docs for it. Support .pth files and legacy packages possibly being symlinks, and ensure that overwrites don't follow the symlink. Index: bdist_egg.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/bdist_egg.py,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- bdist_egg.py 22 Aug 2005 13:40:10 -0000 1.29 +++ bdist_egg.py 23 Aug 2005 13:24:42 -0000 1.30 @@ -168,14 +168,11 @@ # We run install_lib before install_data, because some data hacks # pull their data path from the install_lib command. - log.info("installing library code to %s" % self.bdist_dir) instcmd = self.get_finalized_command('install') - old_root = instcmd.root - instcmd.root = None + old_root = instcmd.root; instcmd.root = None cmd = self.call_command('install_lib', warn_dir=0) instcmd.root = old_root - ext_outputs = cmd._mutate_outputs( self.distribution.has_ext_modules(), 'build_ext', 'build_lib', '' ) @@ -201,7 +198,6 @@ archive_root = self.bdist_dir egg_info = os.path.join(archive_root,'EGG-INFO') self.mkpath(egg_info) - if self.distribution.scripts: script_dir = os.path.join(egg_info, 'scripts') log.info("installing scripts to %s" % script_dir) Index: easy_install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/easy_install.py,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- easy_install.py 22 Aug 2005 13:40:10 -0000 1.23 +++ easy_install.py 23 Aug 2005 13:24:42 -0000 1.24 @@ -104,8 +104,10 @@ for filename in blockers: log.info("Deleting %s", filename) if not self.dry_run: - if os.path.isdir(filename): - shutil.rmtree(filename) + if hasattr(os.path,'islink') and os.path.islink(filename): + os.unlink(filename) + elif os.path.isdir(filename): + shutil.rmtree(filename) else: os.unlink(filename) @@ -119,8 +121,6 @@ - - def finalize_options(self): # If a non-default installation directory was specified, default the # script directory to match it. @@ -846,7 +846,9 @@ if dist.key=='setuptools': # Ensure that setuptools itself never becomes unavailable! # XXX should this check for latest version? - f = open(os.path.join(self.install_dir,'setuptools.pth'), 'wt') + filename = os.path.join(self.install_dir,'setuptools.pth') + unlink_if_symlink(filename) + f = open(filename, 'wt') f.write(dist.location+'\n') f.close() @@ -857,8 +859,6 @@ return dst # only unpack-and-compile skips files for dry run - - def unpack_and_compile(self, egg_path, destination): to_compile = [] @@ -1017,9 +1017,9 @@ f.close() - - - +def unlink_if_symlink(filename): + if hasattr(os.path,'islink') and os.path.islink(filename): + os.unlink(filename) @@ -1100,11 +1100,11 @@ if self.dirty: log.debug("Saving %s", self.filename) data = '\n'.join(self.paths+['']) + unlink_if_symlink(self.filename) f = open(self.filename,'wt'); f.write(data); f.close() self.dirty = False - def add(self,dist): """Add `dist` to the distribution map""" if dist.location not in self.paths: From pje at users.sourceforge.net Tue Aug 23 15:24:52 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Tue, 23 Aug 2005 15:24:52 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.55, 1.56 setuptools.txt, 1.33, 1.34 Message-ID: <20050823132452.CDCE51E400B@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv28556 Modified Files: EasyInstall.txt setuptools.txt Log Message: Simplify non-root install process and improve Mac OS docs for it. Support .pth files and legacy packages possibly being symlinks, and ensure that overwrites don't follow the symlink. Index: EasyInstall.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v retrieving revision 1.55 retrieving revision 1.56 diff -u -d -r1.55 -r1.56 --- EasyInstall.txt 22 Aug 2005 03:53:42 -0000 1.55 +++ EasyInstall.txt 23 Aug 2005 13:24:39 -0000 1.56 @@ -673,15 +673,22 @@ If you want to use EasyInstall on a computer where you do not have write access to Python's main ``site-packages`` directory, you may need to set up an -alternate ``PYTHONHOME`` location, which allows Python to read a second -``site-packages`` directory. +alternate "home" location for Python, so that it uses a personal +``site-packages`` directory instead of the system-wide ``site-packages``. If you are on a Mac OS X machine, you should just use the ``~/Library/Python2.x/site-packages`` directory (replacing the ``x`` with the appropriate number). Just make sure the directory exists, and use it as your -installation location for all packages (including EasyInstall itself). You -do not need to set up a ``PYTHONHOME``, so you can skip the rest of this -section, unless you want to be able to override system-installed packages. +installation location for all packages (including EasyInstall itself). To +make the distutils install to this personal ``site-packages`` directory by +default, you should create a ``~/.pydistutils.cfg`` file with the following +contents:: + + [install] + install_lib = ~/Library/Python$py_version_short/site-packages + +This will tell the distutils (and EasyInstall) to always install packages in +the appropriate personal ``site-packages`` directory. If you are on a Linux, BSD, Cygwin, or other similar Unix-like operating system, you should create a ``~/lib/python2.x/site-packages`` directory @@ -694,39 +701,40 @@ Assuming your ``sys.prefix`` is ``/usr/local``, and you are working with Python 2.4, you need to then perform the following steps (possibly making -adjustments for the tools available on your platform):: +adjustments for the tools available on your platform). First, you need +to set up the local library directories, by symlinking to the system Python's +libraries:: - cd /usr/local/lib/python2.4 - find . -name lib-dynload -prune -o -name site-packages -prune -o \ - -print >~/pyfiles - zip -r ~/lib/python24.zip . -i@$HOME/pyfiles - rm ~/pyfiles - mkdir -p ~/lib/python2.4/site-packages - ln -s /usr/local/lib/python2.4/lib-* ~/lib/python2.4/ + mkdir -p ~/lib/python2.4 + ln -s /usr/local/lib/python2.4/* ~/lib/python2.4/ + rm ~/lib/python2.4/site-packages + mkdir ~/lib/python2.4/site-packages + ln -s /usr/local/lib/python2.4/site-packages/* ~/lib/python2.4/site-packages - echo "[install]" >>~/.pydistutils.cfg - echo "prefix=$HOME" >>~/.pydistutils.cfg - echo "exec_prefix=$HOME" >>~/.pydistutils.cfg +If your ``sys.exec_prefix`` was different from your ``sys.prefix``, you will +also need to do this:: -Note that all of the paths above should be based on ``sys.prefix``, not -``sys.exec_prefix`` (unless they're the same). Once these one-time steps are -completed, you can set your ``PYTHONHOME`` with:: + ln -s /execprefix/lib/python2.4/* ~/lib/python2.4/ - export PYTHONHOME=$HOME:/old_exec_prefix +replacing ``execprefix`` in the above with the value of ``sys.exec_prefix``. -replacing ``/old_exec_prefix`` with the original value of ``sys.exec_prefix``. +Finally, you will also need a private ``python`` executable, e.g.:: -The downside to this setup is that it can take up as much as 10 megabytes of -disk space to store the zipped standard library. The upside, however, is that -Python usually starts much faster with a zipped standard library! And of -course, you'll effectively have complete control over your own Python -installation, without needing to convince a system administrator to install -packages for you. + mkdir -p ~/bin + ln /usr/local/bin/python2.4 ~/bin/python + +Note that if hardlinking as shown doesn't work (e.g. because the system Python +is on a different filesystem), you should use ``copy -p`` instead of ``ln``. +Do NOT use a symlink; the Python binary must be copied or hardlinked, otherwise +it will use the system ``site-packages`` directory and not yours. Note that if you were previously setting a ``PYTHONPATH`` and/or had other special configuration options in your ``~/.pydistutils.cfg``, you may need to remove these settings, after relocating any older installed modules to your -new ``~/lib/python2.x`` directory. +new ``~/lib/python2.x/site-packages`` directory. Also note that you must now +make sure to use the ``~/bin/python`` executable instead of the system Python, +and ideally you should put ``~/bin`` first on your ``PATH`` as well, because +that is where EasyInstall will install new Python scripts. Release Notes/Change History Index: setuptools.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools.txt,v retrieving revision 1.33 retrieving revision 1.34 diff -u -d -r1.33 -r1.34 --- setuptools.txt 22 Aug 2005 03:40:20 -0000 1.33 +++ setuptools.txt 23 Aug 2005 13:24:40 -0000 1.34 @@ -10,7 +10,7 @@ ordinary Python packages based on the ``distutils``. Your users don't need to install or even know about setuptools in order to use them, and you don't have to include the entire setuptools package in your distributions. By -including just a single `bootstrap module`_ (a 5K .py file), your package will +including just a single `bootstrap module`_ (a 7K .py file), your package will automatically download and install ``setuptools`` if the user is building your package from source and doesn't have a suitable version already installed. From pje at users.sourceforge.net Tue Aug 23 15:35:04 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Tue, 23 Aug 2005 15:35:04 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools/setuptools/command easy_install.py, 1.24, 1.25 Message-ID: <20050823133504.95E7F1E400E@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31447/setuptools/command Modified Files: easy_install.py Log Message: D'oh! os.path.islink is available on all platforms. Also, ensure that we do directory tree removals only if isdir() and not islink(), and use unlink() in all other cases. Index: easy_install.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/setuptools/command/easy_install.py,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- easy_install.py 23 Aug 2005 13:24:42 -0000 1.24 +++ easy_install.py 23 Aug 2005 13:34:52 -0000 1.25 @@ -104,10 +104,8 @@ for filename in blockers: log.info("Deleting %s", filename) if not self.dry_run: - if hasattr(os.path,'islink') and os.path.islink(filename): - os.unlink(filename) - elif os.path.isdir(filename): - shutil.rmtree(filename) + if os.path.isdir(filename) and not os.path.islink(filename): + shutil.rmtree(filename) else: os.unlink(filename) @@ -121,6 +119,8 @@ + + def finalize_options(self): # If a non-default installation directory was specified, default the # script directory to match it. @@ -547,9 +547,9 @@ dist = self.egg_distribution(egg_path) self.check_conflicts(dist) if not samefile(egg_path, destination): - if os.path.isdir(destination): + if os.path.isdir(destination) and not os.path.islink(destination): dir_util.remove_tree(destination, dry_run=self.dry_run) - elif os.path.isfile(destination): + elif os.path.exists(destination): self.execute(os.unlink,(destination,),"Removing "+destination) if os.path.isdir(egg_path): @@ -841,24 +841,24 @@ if dist.location not in self.shadow_path: self.shadow_path.append(dist.location) - self.pth_file.save() + if not self.dry_run: - if dist.key=='setuptools': - # Ensure that setuptools itself never becomes unavailable! - # XXX should this check for latest version? - filename = os.path.join(self.install_dir,'setuptools.pth') - unlink_if_symlink(filename) - f = open(filename, 'wt') - f.write(dist.location+'\n') - f.close() + self.pth_file.save() + if dist.key=='setuptools': + # Ensure that setuptools itself never becomes unavailable! + # XXX should this check for latest version? + filename = os.path.join(self.install_dir,'setuptools.pth') + if os.path.islink(filename): unlink(filename) + f = open(filename, 'wt') + f.write(dist.location+'\n') + f.close() def unpack_progress(self, src, dst): # Progress filter for unpacking log.debug("Unpacking %s to %s", src, dst) return dst # only unpack-and-compile skips files for dry run - def unpack_and_compile(self, egg_path, destination): to_compile = [] @@ -1017,9 +1017,9 @@ f.close() -def unlink_if_symlink(filename): - if hasattr(os.path,'islink') and os.path.islink(filename): - os.unlink(filename) + + + @@ -1100,11 +1100,11 @@ if self.dirty: log.debug("Saving %s", self.filename) data = '\n'.join(self.paths+['']) - unlink_if_symlink(self.filename) + if os.path.islink(self.filename): + os.unlink(self.filename) f = open(self.filename,'wt'); f.write(data); f.close() self.dirty = False - def add(self,dist): """Add `dist` to the distribution map""" if dist.location not in self.paths: From pje at users.sourceforge.net Tue Aug 23 15:42:30 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Tue, 23 Aug 2005 15:42:30 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.56, 1.57 Message-ID: <20050823134230.5C4751E4003@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1255 Modified Files: EasyInstall.txt Log Message: Minor doc tweaks, and add release note about symlink support. Index: EasyInstall.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v retrieving revision 1.56 retrieving revision 1.57 diff -u -d -r1.56 -r1.57 --- EasyInstall.txt 23 Aug 2005 13:24:39 -0000 1.56 +++ EasyInstall.txt 23 Aug 2005 13:42:20 -0000 1.57 @@ -688,7 +688,11 @@ install_lib = ~/Library/Python$py_version_short/site-packages This will tell the distutils (and EasyInstall) to always install packages in -the appropriate personal ``site-packages`` directory. +the appropriate personal ``site-packages`` directory. (Note: do *not* replace +``$py_version_short`` with an actual Python version in the configuration file! +The distutils will substitute the correct value at runtime, so that the above +configuration file will work correctly no matter what Python version you use, +now or in the future.) If you are on a Linux, BSD, Cygwin, or other similar Unix-like operating system, you should create a ``~/lib/python2.x/site-packages`` directory @@ -725,16 +729,16 @@ Note that if hardlinking as shown doesn't work (e.g. because the system Python is on a different filesystem), you should use ``copy -p`` instead of ``ln``. -Do NOT use a symlink; the Python binary must be copied or hardlinked, otherwise -it will use the system ``site-packages`` directory and not yours. +Do NOT use a symlink! The Python binary must be copied or hardlinked, +otherwise it will use the system ``site-packages`` directory and not yours. Note that if you were previously setting a ``PYTHONPATH`` and/or had other special configuration options in your ``~/.pydistutils.cfg``, you may need to -remove these settings, after relocating any older installed modules to your +remove these settings and relocate any older installed modules to your new ``~/lib/python2.x/site-packages`` directory. Also note that you must now make sure to use the ``~/bin/python`` executable instead of the system Python, -and ideally you should put ``~/bin`` first on your ``PATH`` as well, because -that is where EasyInstall will install new Python scripts. +and ideally you should put the ``~/bin`` directory first on your ``PATH`` as +well, because that is where EasyInstall will install new Python scripts. Release Notes/Change History @@ -758,6 +762,11 @@ * EasyInstall now does MD5 validation of downloads from PyPI, or from any link that has an "#md5=..." trailer with a 32-digit lowercase hex md5 digest. + * EasyInstall now handles symlinks in target directories by removing the link, + rather than attempting to overwrite the link's destination. This makes it + easier to set up an alternate Python "home" directory (as described above in + the `Non-Root Installation`_ section). + * Added support for handling MacOS platform information in ``.egg`` filenames, based on a contribution by Kevin Dangoor. You may wish to delete and reinstall any eggs whose filename includes "darwin" and "Power_Macintosh", From pje at users.sourceforge.net Tue Aug 23 15:46:00 2005 From: pje at users.sourceforge.net (pje@users.sourceforge.net) Date: Tue, 23 Aug 2005 15:46:00 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/setuptools EasyInstall.txt, 1.57, 1.58 Message-ID: <20050823134600.D36431E4003@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/setuptools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2053 Modified Files: EasyInstall.txt Log Message: More minor doc tweaks. Index: EasyInstall.txt =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/setuptools/EasyInstall.txt,v retrieving revision 1.57 retrieving revision 1.58 diff -u -d -r1.57 -r1.58 --- EasyInstall.txt 23 Aug 2005 13:42:20 -0000 1.57 +++ EasyInstall.txt 23 Aug 2005 13:45:50 -0000 1.58 @@ -784,7 +784,7 @@ * Added ``--site-dirs`` option to allow adding custom "site" directories. Made ``easy-install.pth`` work in platform-specific alternate site - directories (e.g. ``~/Library/Python/2.x/site-packages``). + directories (e.g. ``~/Library/Python/2.x/site-packages`` on Mac OS X). * If you manually delete the current version of a package, the next run of EasyInstall against the target directory will now remove the stray entry @@ -794,8 +794,7 @@ as pointing to the named project's source checkout. Such URLs have a lower match precedence than any other kind of distribution, so they'll only be used if they have a higher version number than any other available - distribution. (Future versions may allow you to specify that you want to - use source checkouts instead of other kinds of distributions.) The ``#egg`` + distribution, or if you use the ``--editable`` option. The ``#egg`` fragment can contain a version if it's formatted as ``#egg=proj-ver``, where ``proj`` is the project name, and ``ver`` is the version number. You *must* use the format for these values that the ``bdist_egg`` command uses; From akuchling at users.sourceforge.net Tue Aug 23 15:48:32 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue, 23 Aug 2005 15:48:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/tut tut.tex,1.275,1.276 Message-ID: <20050823134832.254751E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2644 Modified Files: tut.tex Log Message: In an e-mail to the webmaster alias, some suggested adding this text. Windows users, please correct/expand as necessary. Index: tut.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/tut.tex,v retrieving revision 1.275 retrieving revision 1.276 diff -u -d -r1.275 -r1.276 --- tut.tex 8 Jul 2005 21:36:36 -0000 1.275 +++ tut.tex 23 Aug 2005 13:48:21 -0000 1.276 @@ -175,6 +175,16 @@ your local Python guru or system administrator. (E.g., \file{/usr/local/python} is a popular alternative location.) +On Windows machines, the Python installation is usually placed in +\file{C:\e Python24}, though you can change this when you're running +the installer. To add this directory to your path, +you can type the following command into the command prompt in a DOS box: + +\begin{verbatim} +set path=%path%;C:\python24 +\end{verbatim} + + Typing an end-of-file character (\kbd{Control-D} on \UNIX, \kbd{Control-Z} on Windows) at the primary prompt causes the interpreter to exit with a zero exit status. If that doesn't work, From raymond.hettinger at verizon.net Tue Aug 23 16:11:56 2005 From: raymond.hettinger at verizon.net (Raymond Hettinger) Date: Tue, 23 Aug 2005 10:11:56 -0400 Subject: [Python-checkins] python/dist/src/Modules _hashopenssl.c, NONE, 2.1 sha256module.c, NONE, 2.1 sha512module.c, NONE, 2.1 md5module.c, 2.35, 2.36 shamodule.c, 2.22, 2.23 In-Reply-To: <20050821184613.A45C11E4288@bag.python.org> Message-ID: <000601c5a7ec$9f614680$8901a044@oemcomputer> This patch should be reverted or fixed so that the Py2.5 build works again. It contains a disasterous search and replace error that prevents it from compiling. Hence, it couldn't have passed the test suite before being checked in. Also, all of the project and config files need to be updated for the new modules. > -----Original Message----- > From: python-checkins-bounces at python.org [mailto:python-checkins- > bounces at python.org] On Behalf Of greg at users.sourceforge.net > Sent: Sunday, August 21, 2005 2:46 PM > To: python-checkins at python.org > Subject: [Python-checkins] python/dist/src/Modules _hashopenssl.c, > NONE,2.1 sha256module.c, NONE, 2.1 sha512module.c, NONE,2.1 md5module.c, > 2.35, 2.36 shamodule.c, 2.22, 2.23 > > Update of /cvsroot/python/python/dist/src/Modules > In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32064/Modules > > Modified Files: > md5module.c shamodule.c > Added Files: > _hashopenssl.c sha256module.c sha512module.c > Log Message: > [ sf.net patch # 1121611 ] > > A new hashlib module to replace the md5 and sha modules. It adds > support for additional secure hashes such as SHA-256 and SHA-512. The > hashlib module uses OpenSSL for fast platform optimized > implementations of algorithms when available. The old md5 and sha > modules still exist as wrappers around hashlib to preserve backwards > compatibility. From rhettinger at users.sourceforge.net Tue Aug 23 17:00:57 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 23 Aug 2005 17:00:57 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/tut tut.tex,1.276,1.277 Message-ID: <20050823150057.057C91E400B@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21513 Modified Files: tut.tex Log Message: SF bug #1168135: Python 2.5a0 Tutorial errors and observations (Contributed by Michael R Bax.) Index: tut.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/tut.tex,v retrieving revision 1.276 retrieving revision 1.277 diff -u -d -r1.276 -r1.277 --- tut.tex 23 Aug 2005 13:48:21 -0000 1.276 +++ tut.tex 23 Aug 2005 15:00:45 -0000 1.277 @@ -100,7 +100,7 @@ \emph{Awk} or even \emph{Perl}, yet many things are at least as easy in Python as in those languages. -Python allows you to split up your program in modules that can be +Python allows you to split your program in modules that can be reused in other Python programs. It comes with a large collection of standard modules that you can use as the basis of your programs --- or as examples to start learning to program in Python. Some of these @@ -114,7 +114,7 @@ programs, or to test functions during bottom-up program development. It is also a handy desk calculator. -Python allows writing very compact and readable programs. Programs +Python enables programs to written compactly and readably. Programs written in Python are typically much shorter than equivalent C or \Cpp{} programs, for several reasons: \begin{itemize} @@ -145,7 +145,7 @@ Now that you are all excited about Python, you'll want to examine it in some more detail. Since the best way to learn a language is -using it, you are invited to do so with this tutorial. +to use it, you are invited to do so with this tutorial. In the next chapter, the mechanics of using the interpreter are explained. This is rather mundane information, but essential for @@ -293,7 +293,7 @@ unconditionally fatal and cause an exit with a nonzero exit; this applies to internal inconsistencies and some cases of running out of memory. All error messages are written to the standard error stream; -normal output from the executed commands is written to standard +normal output from executed commands is written to standard output. Typing the interrupt character (usually Control-C or DEL) to the @@ -1227,7 +1227,7 @@ \end{verbatim} The given end point is never part of the generated list; -\code{range(10)} generates a list of 10 values, exactly the legal +\code{range(10)} generates a list of 10 values, the legal indices for items of a sequence of length 10. It is possible to let the range start at another number, or to specify a different increment (even negative; sometimes this is called the `step'): @@ -1426,7 +1426,7 @@ same name without causing ambiguity. (It is possible to define your own object types and methods, using \emph{classes}, as discussed later in this tutorial.) -The method \method{append()} shown in the example, is defined for +The method \method{append()} shown in the example is defined for list objects; it adds a new element at the end of the list. In this example it is equivalent to \samp{result = result + [b]}, but more efficient. @@ -1521,7 +1521,7 @@ \begin{verbatim} def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print "-- This parrot wouldn't", action, - print "if you put", voltage, "Volts through it." + print "if you put", voltage, "volts through it." print "-- Lovely plumage, the", type print "-- It's", state, "!" \end{verbatim} @@ -1646,7 +1646,7 @@ \subsection{Lambda Forms \label{lambda}} By popular demand, a few features commonly found in functional -programming languages and Lisp have been added to Python. With the +programming languages like Lisp have been added to Python. With the \keyword{lambda} keyword, small anonymous functions can be created. Here's a function that returns the sum of its two arguments: \samp{lambda a, b: a+b}. Lambda forms can be used wherever function @@ -1753,8 +1753,8 @@ \begin{methoddesc}[list]{pop}{\optional{i}} Remove the item at the given position in the list, and return it. If -no index is specified, \code{a.pop()} returns the last item in the -list. The item is also removed from the list. (The square brackets +no index is specified, \code{a.pop()} removes and returns the last item +in the list. The item is also removed from the list. (The square brackets around the \var{i} in the method signature denote that the parameter is optional, not that you should type square brackets at that position. You will see this notation frequently in the @@ -1857,10 +1857,12 @@ There are three built-in functions that are very useful when used with lists: \function{filter()}, \function{map()}, and \function{reduce()}. -\samp{filter(\var{function}, \var{sequence})} returns a sequence (of -the same type, if possible) consisting of those items from the -sequence for which \code{\var{function}(\var{item})} is true. For -example, to compute some primes: +\samp{filter(\var{function}, \var{sequence})} returns a sequence +consisting of those items from the +sequence for which \code{\var{function}(\var{item})} is true. +If \var{sequence} is a \class{string} or \class{tuple}, the result will +be of the same type; otherwise, it is always a \class{list}. +For example, to compute some primes: \begin{verbatim} >>> def f(x): return x % 2 != 0 and x % 3 != 0 @@ -1974,7 +1976,7 @@ \end{verbatim} List comprehensions are much more flexible than \function{map()} and can be -applied to functions with more than one argument and to nested functions: +applied to complex expressions and nested functions: \begin{verbatim} >>> [str(round(355/113.0, i)) for i in range(1,6)] @@ -1985,7 +1987,9 @@ \section{The \keyword{del} statement \label{del}} There is a way to remove an item from a list given its index instead -of its value: the \keyword{del} statement. This can also be used to +of its value: the \keyword{del} statement. Unlike the \method{pop()}) +method which returns a value, the \keyword{del} keyword is a statement +and can also be used to remove slices from a list (which we did earlier by assignment of an empty list to the slice). For example: @@ -2074,7 +2078,7 @@ \end{verbatim} This is called, appropriately enough, \emph{sequence unpacking}. -Sequence unpacking requires that the list of variables on the left +Sequence unpacking requires the list of variables on the left to have the same number of elements as the length of the sequence. Note that multiple assignment is really just a combination of tuple packing and sequence unpacking! @@ -2097,12 +2101,12 @@ \begin{verbatim} >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] ->>> fruits = set(basket) # create a set without duplicates ->>> fruits +>>> fruit = set(basket) # create a set without duplicates +>>> fruit set(['orange', 'pear', 'apple', 'banana']) ->>> 'orange' in fruits # fast membership testing +>>> 'orange' in fruit # fast membership testing True ->>> 'crabgrass' in fruits +>>> 'crabgrass' in fruit False >>> # Demonstrate set operations on unique letters from two words @@ -2133,8 +2137,8 @@ keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can't use -lists as keys, since lists can be modified in place using their -\method{append()} and \method{extend()} methods, as well as slice and +lists as keys, since lists can be modified in place using methods like +\method{append()} and \method{extend()} or modified with slice and indexed assignments. It is best to think of a dictionary as an unordered set of @@ -2291,7 +2295,7 @@ whether \code{a} is less than \code{b} and moreover \code{b} equals \code{c}. -Comparisons may be combined by the Boolean operators \code{and} and +Comparisons may be combined using the Boolean operators \code{and} and \code{or}, and the outcome of a comparison (or of any other Boolean expression) may be negated with \code{not}. These have lower priorities than comparison operators; between them, \code{not} has @@ -2304,9 +2308,9 @@ left to right, and evaluation stops as soon as the outcome is determined. For example, if \code{A} and \code{C} are true but \code{B} is false, \code{A and B and C} does not evaluate the -expression \code{C}. In general, the return value of a short-circuit -operator, when used as a general value and not as a Boolean, is the -last evaluated argument. +expression \code{C}. When used as a general value and not as a +Boolean, the return value of a short-circuit operator is the last +evaluated argument. It is possible to assign the result of a comparison or other Boolean expression to a variable. For example, @@ -2337,8 +2341,8 @@ equal. If one sequence is an initial sub-sequence of the other, the shorter sequence is the smaller (lesser) one. Lexicographical ordering for strings uses the \ASCII{} ordering for individual -characters. Some examples of comparisons between sequences with the -same types: +characters. Some examples of comparisons between sequences of the +same type: \begin{verbatim} (1, 2, 3) < (1, 2, 4) @@ -2619,7 +2623,7 @@ These two variables are only defined if the interpreter is in interactive mode. -The variable \code{sys.path} is a list of strings that determine the +The variable \code{sys.path} is a list of strings that determines the interpreter's search path for modules. It is initialized to a default path taken from the environment variable \envvar{PYTHONPATH}, or from a built-in default if \envvar{PYTHONPATH} is not set. You can modify @@ -2946,8 +2950,9 @@ One question remains, of course: how do you convert values to strings? Luckily, Python has ways to convert any value to a string: pass it to the \function{repr()} or \function{str()} functions. Reverse quotes -(\code{``}) are equivalent to \function{repr()}, but their use is -discouraged. +(\code{``}) are equivalent to \function{repr()}, but they are no +longer used in modern Python code and will likely not be in future +versions of the language. The \function{str()} function is meant to return representations of values which are fairly human-readable, while \function{repr()} is @@ -3035,7 +3040,7 @@ unchanged; this will mess up your column lay-out but that's usually better than the alternative, which would be lying about a value. (If you really want truncation you can always add a slice operation, as in -\samp{x.ljust(~n)[:n]}.) +\samp{x.ljust(n)[:n]}.) There is another method, \method{zfill()}, which pads a numeric string on the left with zeros. It understands about plus and @@ -3123,8 +3128,8 @@ distinction between text and binary files; the end-of-line characters in text files are automatically altered slightly when data is read or written. This behind-the-scenes modification to file data is fine for -\ASCII{} text files, but it'll corrupt binary data like that in JPEGs or -\file{.EXE} files. Be very careful to use binary mode when reading and +\ASCII{} text files, but it'll corrupt binary data like that in \file{JPEG} or +\file{EXE} files. Be very careful to use binary mode when reading and writing such files. \subsection{Methods of File Objects \label{fileMethods}} @@ -3367,8 +3372,8 @@ and what caused it. The preceding part of the error message shows the context where the -exception happened, in the form of a stack backtrace. -In general it contains a stack backtrace listing source lines; however, +exception happened, in the form of a stack traceback. +In general it contains a stack traceback listing source lines; however, it will not display lines read from standard input. The \citetitle[../lib/module-exceptions.html]{Python Library @@ -3390,7 +3395,7 @@ ... x = int(raw_input("Please enter a number: ")) ... break ... except ValueError: -... print "Oops! That was no valid number. Try again..." +... print "Oops! That was no valid number. Try again..." ... \end{verbatim} @@ -3424,7 +3429,7 @@ be executed. Handlers only handle exceptions that occur in the corresponding try clause, not in other handlers of the same \keyword{try} statement. An except clause may name multiple exceptions -as a parenthesized list, for example: +as a parenthesized tuple, for example: \begin{verbatim} ... except (RuntimeError, TypeError, NameError): @@ -3479,7 +3484,7 @@ the exception's \emph{argument}. The presence and type of the argument depend on the exception type. -The except clause may specify a variable after the exception name (or list). +The except clause may specify a variable after the exception name (or tuple). The variable is bound to an exception instance with the arguments stored in \code{instance.args}. For convenience, the exception instance defines \method{__getitem__} and \method{__str__} so the arguments can @@ -3667,11 +3672,11 @@ The code in the finally clause is useful for releasing external resources (such as files or network connections), regardless of -whether or not the use of the resource was successful. +whether the use of the resource was successful. A \keyword{try} statement must either have one or more except clauses or one finally clause, but not both (because it would be unclear which -clause should be executed). +clause should be executed first). \chapter{Classes \label{classes}} @@ -3684,7 +3689,7 @@ definition.'' The most important features of classes are retained with full power, however: the class inheritance mechanism allows multiple base classes, a derived class can override any methods of its -base class or classes, a method can call the method of a base class with the +base class or classes, and a method can call the method of a base class with the same name. Objects can contain an arbitrary amount of private data. In \Cpp{} terminology, all class members (including the data members) are @@ -3806,10 +3811,13 @@ If a name is declared global, then all references and assignments go directly to the middle scope containing the module's global names. -Otherwise, all variables found outside of the innermost scope are read-only. +Otherwise, all variables found outside of the innermost scope are read-only +(an attempt to write to such a variable will simply create a \emph{new} +local variable in the innermost scope, leaving the identically named +outer variable unchanged). Usually, the local scope references the local names of the (textually) -current function. Outside of functions, the local scope references +current function. Outside functions, the local scope references the same namespace as the global scope: the module's namespace. Class definitions place yet another namespace in the local scope. @@ -3873,7 +3881,7 @@ object} is created. This is basically a wrapper around the contents of the namespace created by the class definition; we'll learn more about class objects in the next section. The original local scope -(the one in effect just before the class definitions were entered) is +(the one in effect just before the class definition was entered) is reinstated, and the class object is bound here to the class name given in the class definition header (\class{ClassName} in the example). @@ -5309,7 +5317,7 @@ editing. This library has its own documentation which I won't duplicate here; however, the basics are easily explained. The interactive editing and history described here are optionally -available in the \UNIX{} and CygWin versions of the interpreter. +available in the \UNIX{} and Cygwin versions of the interpreter. This chapter does \emph{not} document the editing facilities of Mark Hammond's PythonWin package or the Tk-based environment, IDLE, @@ -5541,7 +5549,7 @@ 0.1000000000000000055511151231257827021181583404541015625 \end{verbatim} -instead! The Python prompt (implicitly) uses the builtin +instead! The Python prompt uses the builtin \function{repr()} function to obtain a string version of everything it displays. For floats, \code{repr(\var{float})} rounds the true decimal value to 17 significant digits, giving @@ -5556,7 +5564,7 @@ \var{x}, but rounding to 16 digits is not enough to make that true. Note that this is in the very nature of binary floating-point: this is -not a bug in Python, it is not a bug in your code either. You'll +not a bug in Python, and it is not a bug in your code either. You'll see the same kind of thing in all languages that support your hardware's floating-point arithmetic (although some languages may not \emph{display} the difference by default, or in all output modes). @@ -5595,8 +5603,8 @@ to round it again can't make it better: it was already as good as it gets. -Another consequence is that since 0.1 is not exactly 1/10, adding 0.1 -to itself 10 times may not yield exactly 1.0, either: +Another consequence is that since 0.1 is not exactly 1/10, +summing ten values of 0.1 may not yield exactly 1.0, either: \begin{verbatim} >>> sum = 0.0 @@ -5637,7 +5645,7 @@ you can perform an exact analysis of cases like this yourself. Basic familiarity with binary floating-point representation is assumed. -\dfn{Representation error} refers to that some (most, actually) +\dfn{Representation error} refers to fact that some (most, actually) decimal fractions cannot be represented exactly as binary (base 2) fractions. This is the chief reason why Python (or Perl, C, \Cpp, Java, Fortran, and many others) often won't display the exact decimal @@ -5672,9 +5680,9 @@ \begin{verbatim} >>> 2**52 4503599627370496L ->>> 2L**53 +>>> 2**53 9007199254740992L ->>> 2L**56/10 +>>> 2**56/10 7205759403792793L \end{verbatim} @@ -5683,7 +5691,7 @@ quotient rounded: \begin{verbatim} ->>> q, r = divmod(2L**56, 10) +>>> q, r = divmod(2**56, 10) >>> r 6L \end{verbatim} @@ -5711,7 +5719,7 @@ fraction given above, the best 754 double approximation it can get: \begin{verbatim} ->>> .1 * 2L**56 +>>> .1 * 2**56 7205759403792794.0 \end{verbatim} @@ -5719,7 +5727,7 @@ value of its 30 most significant decimal digits: \begin{verbatim} ->>> 7205759403792794L * 10L**30 / 2L**56 +>>> 7205759403792794 * 10**30 / 2**56 100000000000000005551115123125L \end{verbatim} From rhettinger at users.sourceforge.net Tue Aug 23 17:01:54 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 23 Aug 2005 17:01:54 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/tut tut.tex, 1.261.2.10, 1.261.2.11 Message-ID: <20050823150154.381FA1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21893 Modified Files: Tag: release24-maint tut.tex Log Message: SF bug #1168135: Python 2.5a0 Tutorial errors and observations (Contributed by Michael R Bax.) Index: tut.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/tut.tex,v retrieving revision 1.261.2.10 retrieving revision 1.261.2.11 diff -u -d -r1.261.2.10 -r1.261.2.11 --- tut.tex 8 Jul 2005 21:36:42 -0000 1.261.2.10 +++ tut.tex 23 Aug 2005 15:01:43 -0000 1.261.2.11 @@ -100,7 +100,7 @@ \emph{Awk} or even \emph{Perl}, yet many things are at least as easy in Python as in those languages. -Python allows you to split up your program in modules that can be +Python allows you to split your program in modules that can be reused in other Python programs. It comes with a large collection of standard modules that you can use as the basis of your programs --- or as examples to start learning to program in Python. Some of these @@ -114,7 +114,7 @@ programs, or to test functions during bottom-up program development. It is also a handy desk calculator. -Python allows writing very compact and readable programs. Programs +Python enables programs to written compactly and readably. Programs written in Python are typically much shorter than equivalent C or \Cpp{} programs, for several reasons: \begin{itemize} @@ -145,7 +145,7 @@ Now that you are all excited about Python, you'll want to examine it in some more detail. Since the best way to learn a language is -using it, you are invited to do so with this tutorial. +to use it, you are invited to do so with this tutorial. In the next chapter, the mechanics of using the interpreter are explained. This is rather mundane information, but essential for @@ -283,7 +283,7 @@ unconditionally fatal and cause an exit with a nonzero exit; this applies to internal inconsistencies and some cases of running out of memory. All error messages are written to the standard error stream; -normal output from the executed commands is written to standard +normal output from executed commands is written to standard output. Typing the interrupt character (usually Control-C or DEL) to the @@ -1217,7 +1217,7 @@ \end{verbatim} The given end point is never part of the generated list; -\code{range(10)} generates a list of 10 values, exactly the legal +\code{range(10)} generates a list of 10 values, the legal indices for items of a sequence of length 10. It is possible to let the range start at another number, or to specify a different increment (even negative; sometimes this is called the `step'): @@ -1416,7 +1416,7 @@ same name without causing ambiguity. (It is possible to define your own object types and methods, using \emph{classes}, as discussed later in this tutorial.) -The method \method{append()} shown in the example, is defined for +The method \method{append()} shown in the example is defined for list objects; it adds a new element at the end of the list. In this example it is equivalent to \samp{result = result + [b]}, but more efficient. @@ -1511,7 +1511,7 @@ \begin{verbatim} def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print "-- This parrot wouldn't", action, - print "if you put", voltage, "Volts through it." + print "if you put", voltage, "volts through it." print "-- Lovely plumage, the", type print "-- It's", state, "!" \end{verbatim} @@ -1636,7 +1636,7 @@ \subsection{Lambda Forms \label{lambda}} By popular demand, a few features commonly found in functional -programming languages and Lisp have been added to Python. With the +programming languages like Lisp have been added to Python. With the \keyword{lambda} keyword, small anonymous functions can be created. Here's a function that returns the sum of its two arguments: \samp{lambda a, b: a+b}. Lambda forms can be used wherever function @@ -1743,8 +1743,8 @@ \begin{methoddesc}[list]{pop}{\optional{i}} Remove the item at the given position in the list, and return it. If -no index is specified, \code{a.pop()} returns the last item in the -list. The item is also removed from the list. (The square brackets +no index is specified, \code{a.pop()} removes and returns the last item +in the list. The item is also removed from the list. (The square brackets around the \var{i} in the method signature denote that the parameter is optional, not that you should type square brackets at that position. You will see this notation frequently in the @@ -1847,10 +1847,12 @@ There are three built-in functions that are very useful when used with lists: \function{filter()}, \function{map()}, and \function{reduce()}. -\samp{filter(\var{function}, \var{sequence})} returns a sequence (of -the same type, if possible) consisting of those items from the -sequence for which \code{\var{function}(\var{item})} is true. For -example, to compute some primes: +\samp{filter(\var{function}, \var{sequence})} returns a sequence +consisting of those items from the +sequence for which \code{\var{function}(\var{item})} is true. +If \var{sequence} is a \class{string} or \class{tuple}, the result will +be of the same type; otherwise, it is always a \class{list}. +For example, to compute some primes: \begin{verbatim} >>> def f(x): return x % 2 != 0 and x % 3 != 0 @@ -1964,7 +1966,7 @@ \end{verbatim} List comprehensions are much more flexible than \function{map()} and can be -applied to functions with more than one argument and to nested functions: +applied to complex expressions and nested functions: \begin{verbatim} >>> [str(round(355/113.0, i)) for i in range(1,6)] @@ -1975,7 +1977,9 @@ \section{The \keyword{del} statement \label{del}} There is a way to remove an item from a list given its index instead -of its value: the \keyword{del} statement. This can also be used to +of its value: the \keyword{del} statement. Unlike the \method{pop()}) +method which returns a value, the \keyword{del} keyword is a statement +and can also be used to remove slices from a list (which we did earlier by assignment of an empty list to the slice). For example: @@ -2064,7 +2068,7 @@ \end{verbatim} This is called, appropriately enough, \emph{sequence unpacking}. -Sequence unpacking requires that the list of variables on the left +Sequence unpacking requires the list of variables on the left to have the same number of elements as the length of the sequence. Note that multiple assignment is really just a combination of tuple packing and sequence unpacking! @@ -2087,12 +2091,12 @@ \begin{verbatim} >>> basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana'] ->>> fruits = set(basket) # create a set without duplicates ->>> fruits +>>> fruit = set(basket) # create a set without duplicates +>>> fruit set(['orange', 'pear', 'apple', 'banana']) ->>> 'orange' in fruits # fast membership testing +>>> 'orange' in fruit # fast membership testing True ->>> 'crabgrass' in fruits +>>> 'crabgrass' in fruit False >>> # Demonstrate set operations on unique letters from two words @@ -2123,8 +2127,8 @@ keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can't use -lists as keys, since lists can be modified in place using their -\method{append()} and \method{extend()} methods, as well as slice and +lists as keys, since lists can be modified in place using methods like +\method{append()} and \method{extend()} or modified with slice and indexed assignments. It is best to think of a dictionary as an unordered set of @@ -2281,7 +2285,7 @@ whether \code{a} is less than \code{b} and moreover \code{b} equals \code{c}. -Comparisons may be combined by the Boolean operators \code{and} and +Comparisons may be combined using the Boolean operators \code{and} and \code{or}, and the outcome of a comparison (or of any other Boolean expression) may be negated with \code{not}. These have lower priorities than comparison operators; between them, \code{not} has @@ -2294,9 +2298,9 @@ left to right, and evaluation stops as soon as the outcome is determined. For example, if \code{A} and \code{C} are true but \code{B} is false, \code{A and B and C} does not evaluate the -expression \code{C}. In general, the return value of a short-circuit -operator, when used as a general value and not as a Boolean, is the -last evaluated argument. +expression \code{C}. When used as a general value and not as a +Boolean, the return value of a short-circuit operator is the last +evaluated argument. It is possible to assign the result of a comparison or other Boolean expression to a variable. For example, @@ -2327,8 +2331,8 @@ equal. If one sequence is an initial sub-sequence of the other, the shorter sequence is the smaller (lesser) one. Lexicographical ordering for strings uses the \ASCII{} ordering for individual -characters. Some examples of comparisons between sequences with the -same types: +characters. Some examples of comparisons between sequences of the +same type: \begin{verbatim} (1, 2, 3) < (1, 2, 4) @@ -2609,7 +2613,7 @@ These two variables are only defined if the interpreter is in interactive mode. -The variable \code{sys.path} is a list of strings that determine the +The variable \code{sys.path} is a list of strings that determines the interpreter's search path for modules. It is initialized to a default path taken from the environment variable \envvar{PYTHONPATH}, or from a built-in default if \envvar{PYTHONPATH} is not set. You can modify @@ -2936,8 +2940,9 @@ One question remains, of course: how do you convert values to strings? Luckily, Python has ways to convert any value to a string: pass it to the \function{repr()} or \function{str()} functions. Reverse quotes -(\code{``}) are equivalent to \function{repr()}, but their use is -discouraged. +(\code{``}) are equivalent to \function{repr()}, but they are no +longer used in modern Python code and will likely not be in future +versions of the language. The \function{str()} function is meant to return representations of values which are fairly human-readable, while \function{repr()} is @@ -3025,7 +3030,7 @@ unchanged; this will mess up your column lay-out but that's usually better than the alternative, which would be lying about a value. (If you really want truncation you can always add a slice operation, as in -\samp{x.ljust(~n)[:n]}.) +\samp{x.ljust(n)[:n]}.) There is another method, \method{zfill()}, which pads a numeric string on the left with zeros. It understands about plus and @@ -3113,8 +3118,8 @@ distinction between text and binary files; the end-of-line characters in text files are automatically altered slightly when data is read or written. This behind-the-scenes modification to file data is fine for -\ASCII{} text files, but it'll corrupt binary data like that in JPEGs or -\file{.EXE} files. Be very careful to use binary mode when reading and +\ASCII{} text files, but it'll corrupt binary data like that in \file{JPEG} or +\file{EXE} files. Be very careful to use binary mode when reading and writing such files. \subsection{Methods of File Objects \label{fileMethods}} @@ -3357,8 +3362,8 @@ and what caused it. The preceding part of the error message shows the context where the -exception happened, in the form of a stack backtrace. -In general it contains a stack backtrace listing source lines; however, +exception happened, in the form of a stack traceback. +In general it contains a stack traceback listing source lines; however, it will not display lines read from standard input. The \citetitle[../lib/module-exceptions.html]{Python Library @@ -3380,7 +3385,7 @@ ... x = int(raw_input("Please enter a number: ")) ... break ... except ValueError: -... print "Oops! That was no valid number. Try again..." +... print "Oops! That was no valid number. Try again..." ... \end{verbatim} @@ -3414,7 +3419,7 @@ be executed. Handlers only handle exceptions that occur in the corresponding try clause, not in other handlers of the same \keyword{try} statement. An except clause may name multiple exceptions -as a parenthesized list, for example: +as a parenthesized tuple, for example: \begin{verbatim} ... except (RuntimeError, TypeError, NameError): @@ -3469,7 +3474,7 @@ the exception's \emph{argument}. The presence and type of the argument depend on the exception type. -The except clause may specify a variable after the exception name (or list). +The except clause may specify a variable after the exception name (or tuple). The variable is bound to an exception instance with the arguments stored in \code{instance.args}. For convenience, the exception instance defines \method{__getitem__} and \method{__str__} so the arguments can @@ -3657,11 +3662,11 @@ The code in the finally clause is useful for releasing external resources (such as files or network connections), regardless of -whether or not the use of the resource was successful. +whether the use of the resource was successful. A \keyword{try} statement must either have one or more except clauses or one finally clause, but not both (because it would be unclear which -clause should be executed). +clause should be executed first). \chapter{Classes \label{classes}} @@ -3674,7 +3679,7 @@ definition.'' The most important features of classes are retained with full power, however: the class inheritance mechanism allows multiple base classes, a derived class can override any methods of its -base class or classes, a method can call the method of a base class with the +base class or classes, and a method can call the method of a base class with the same name. Objects can contain an arbitrary amount of private data. In \Cpp{} terminology, all class members (including the data members) are @@ -3796,10 +3801,13 @@ If a name is declared global, then all references and assignments go directly to the middle scope containing the module's global names. -Otherwise, all variables found outside of the innermost scope are read-only. +Otherwise, all variables found outside of the innermost scope are read-only +(an attempt to write to such a variable will simply create a \emph{new} +local variable in the innermost scope, leaving the identically named +outer variable unchanged). Usually, the local scope references the local names of the (textually) -current function. Outside of functions, the local scope references +current function. Outside functions, the local scope references the same namespace as the global scope: the module's namespace. Class definitions place yet another namespace in the local scope. @@ -3863,7 +3871,7 @@ object} is created. This is basically a wrapper around the contents of the namespace created by the class definition; we'll learn more about class objects in the next section. The original local scope -(the one in effect just before the class definitions were entered) is +(the one in effect just before the class definition was entered) is reinstated, and the class object is bound here to the class name given in the class definition header (\class{ClassName} in the example). @@ -5299,7 +5307,7 @@ editing. This library has its own documentation which I won't duplicate here; however, the basics are easily explained. The interactive editing and history described here are optionally -available in the \UNIX{} and CygWin versions of the interpreter. +available in the \UNIX{} and Cygwin versions of the interpreter. This chapter does \emph{not} document the editing facilities of Mark Hammond's PythonWin package or the Tk-based environment, IDLE, @@ -5531,7 +5539,7 @@ 0.1000000000000000055511151231257827021181583404541015625 \end{verbatim} -instead! The Python prompt (implicitly) uses the builtin +instead! The Python prompt uses the builtin \function{repr()} function to obtain a string version of everything it displays. For floats, \code{repr(\var{float})} rounds the true decimal value to 17 significant digits, giving @@ -5546,7 +5554,7 @@ \var{x}, but rounding to 16 digits is not enough to make that true. Note that this is in the very nature of binary floating-point: this is -not a bug in Python, it is not a bug in your code either. You'll +not a bug in Python, and it is not a bug in your code either. You'll see the same kind of thing in all languages that support your hardware's floating-point arithmetic (although some languages may not \emph{display} the difference by default, or in all output modes). @@ -5585,8 +5593,8 @@ to round it again can't make it better: it was already as good as it gets. -Another consequence is that since 0.1 is not exactly 1/10, adding 0.1 -to itself 10 times may not yield exactly 1.0, either: +Another consequence is that since 0.1 is not exactly 1/10, +summing ten values of 0.1 may not yield exactly 1.0, either: \begin{verbatim} >>> sum = 0.0 @@ -5627,7 +5635,7 @@ you can perform an exact analysis of cases like this yourself. Basic familiarity with binary floating-point representation is assumed. -\dfn{Representation error} refers to that some (most, actually) +\dfn{Representation error} refers to fact that some (most, actually) decimal fractions cannot be represented exactly as binary (base 2) fractions. This is the chief reason why Python (or Perl, C, \Cpp, Java, Fortran, and many others) often won't display the exact decimal @@ -5662,9 +5670,9 @@ \begin{verbatim} >>> 2**52 4503599627370496L ->>> 2L**53 +>>> 2**53 9007199254740992L ->>> 2L**56/10 +>>> 2**56/10 7205759403792793L \end{verbatim} @@ -5673,7 +5681,7 @@ quotient rounded: \begin{verbatim} ->>> q, r = divmod(2L**56, 10) +>>> q, r = divmod(2**56, 10) >>> r 6L \end{verbatim} @@ -5701,7 +5709,7 @@ fraction given above, the best 754 double approximation it can get: \begin{verbatim} ->>> .1 * 2L**56 +>>> .1 * 2**56 7205759403792794.0 \end{verbatim} @@ -5709,7 +5717,7 @@ value of its 30 most significant decimal digits: \begin{verbatim} ->>> 7205759403792794L * 10L**30 / 2L**56 +>>> 7205759403792794 * 10**30 / 2**56 100000000000000005551115123125L \end{verbatim} From kbk at users.sourceforge.net Tue Aug 23 19:39:07 2005 From: kbk at users.sourceforge.net (kbk@users.sourceforge.net) Date: Tue, 23 Aug 2005 19:39:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/idlelib NEWS.txt, 1.49.2.7, 1.49.2.8 ScriptBinding.py, 1.28, 1.28.4.1 Message-ID: <20050823173907.D0B4F1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/idlelib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30883 Modified Files: Tag: release24-maint NEWS.txt ScriptBinding.py Log Message: - Mac line endings were incorrect when pasting code from some browsers when using X11 and the Fink distribution. Python Bug 1263656. Modified Files: Tag: release24-maint NEWS.txt ScriptBinding.py Index: NEWS.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/NEWS.txt,v retrieving revision 1.49.2.7 retrieving revision 1.49.2.8 diff -u -d -r1.49.2.7 -r1.49.2.8 --- NEWS.txt 30 Mar 2005 03:01:43 -0000 1.49.2.7 +++ NEWS.txt 23 Aug 2005 17:38:55 -0000 1.49.2.8 @@ -1,3 +1,12 @@ +What's New in IDLE 1.1.2c1? +========================= + +*Release date: XX-SEP-2005* + +- Mac line endings were incorrect when pasting code from some browsers + when using X11 and the Fink distribution. Python Bug 1263656. + + What's New in IDLE 1.1.1? ========================= Index: ScriptBinding.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/idlelib/ScriptBinding.py,v retrieving revision 1.28 retrieving revision 1.28.4.1 diff -u -d -r1.28 -r1.28.4.1 --- ScriptBinding.py 4 Jul 2004 01:25:56 -0000 1.28 +++ ScriptBinding.py 23 Aug 2005 17:38:56 -0000 1.28.4.1 @@ -90,6 +90,7 @@ f.close() if '\r' in source: source = re.sub(r"\r\n", "\n", source) + source = re.sub(r"\r", "\n", source) if source and source[-1] != '\n': source = source + '\n' text = self.editwin.text From rhettinger at users.sourceforge.net Tue Aug 23 20:02:39 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 23 Aug 2005 20:02:39 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/tut tut.tex,1.277,1.278 Message-ID: <20050823180239.A4EF01E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5137 Modified Files: tut.tex Log Message: SF bug #1168135: Python 2.5a0 Tutorial errors and observations (Contributed by Michael R Bax.) Index: tut.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/tut.tex,v retrieving revision 1.277 retrieving revision 1.278 diff -u -d -r1.277 -r1.278 --- tut.tex 23 Aug 2005 15:00:45 -0000 1.277 +++ tut.tex 23 Aug 2005 18:02:28 -0000 1.278 @@ -3924,8 +3924,9 @@ the local variable \code{x}. The instantiation operation (``calling'' a class object) creates an -empty object. Many classes like to create objects in a known initial -state. Therefore a class may define a special method named +empty object. Many classes like to create objects with instances +customized to a specific initial state. +Therefore a class may define a special method named \method{__init__()}, like this: \begin{verbatim} @@ -3981,7 +3982,7 @@ del x.counter \end{verbatim} -The other kind of instance attribute references is a \emph{method}. +The other kind of instance attribute reference is a \emph{method}. A method is a function that ``belongs to'' an object. (In Python, the term method is not unique to class instances: other object types can have methods as well. For example, list objects have @@ -4001,13 +4002,13 @@ \subsection{Method Objects \label{methodObjects}} -Usually, a method is called immediately: +Usually, a method is called right after it is bound: \begin{verbatim} x.f() \end{verbatim} -In our example, this will return the string \code{'hello world'}. +In the \class{MyClass} example, this will return the string \code{'hello world'}. However, it is not necessary to call a method right away: \code{x.f} is a method object, and can be stored away and called at a later time. For example: @@ -4085,7 +4086,7 @@ variables and instance variables when glancing through a method. -Conventionally, the first argument of a method is often called +Often, the first argument of a method is called \code{self}. This is nothing more than a convention: the name \code{self} has absolutely no special meaning to Python. (Note, however, that by not following the convention your code may be less @@ -4149,7 +4150,7 @@ Of course, a language feature would not be worthy of the name ``class'' without supporting inheritance. The syntax for a derived class -definition looks as follows: +definition looks like this: \begin{verbatim} class DerivedClassName(BaseClassName): @@ -4161,9 +4162,9 @@ \end{verbatim} The name \class{BaseClassName} must be defined in a scope containing -the derived class definition. Instead of a base class name, an -expression is also allowed. This is useful when the base class is -defined in another module, +the derived class definition. In place of a base class name, other +arbitrary expressions are also allowed. This can be useful, for +example, when the base class is defined in another module: \begin{verbatim} class DerivedClassName(modname.BaseClassName): @@ -4172,7 +4173,7 @@ Execution of a derived class definition proceeds the same as for a base class. When the class object is constructed, the base class is remembered. This is used for resolving attribute references: if a -requested attribute is not found in the class, it is searched in the +requested attribute is not found in the class, the search proceeds to look in the base class. This rule is applied recursively if the base class itself is derived from some other class. @@ -4185,7 +4186,7 @@ Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method -defined in the same base class, may in fact end up calling a method of +defined in the same base class may end up calling a method of a derived class that overrides it. (For \Cpp{} programmers: all methods in Python are effectively \keyword{virtual}.) @@ -4200,7 +4201,7 @@ \subsection{Multiple Inheritance \label{multiple}} Python supports a limited form of multiple inheritance as well. A -class definition with multiple base classes looks as follows: +class definition with multiple base classes looks like this: \begin{verbatim} class DerivedClassName(Base1, Base2, Base3): @@ -4359,15 +4360,15 @@ \samp{except B} first), it would have printed B, B, B --- the first matching except clause is triggered. -When an error message is printed for an unhandled exception which is a -class, the class name is printed, then a colon and a space, and +When an error message is printed for an unhandled exception, the +exception's class name is printed, then a colon and a space, and finally the instance converted to a string using the built-in function \function{str()}. \section{Iterators\label{iterators}} -By now, you've probably noticed that most container objects can be looped +By now you have probably noticed that most container objects can be looped over using a \keyword{for} statement: \begin{verbatim} @@ -4406,7 +4407,7 @@ >>> it.next() Traceback (most recent call last): - File "", line 1, in -toplevel- + File "", line 1, in ? it.next() StopIteration \end{verbatim} @@ -4743,7 +4744,7 @@ \section{Performance Measurement\label{performance-measurement}} Some Python users develop a deep interest in knowing the relative -performance between different approaches to the same problem. +performance of different approaches to the same problem. Python provides a measurement tool that answers those questions immediately. @@ -4907,7 +4908,7 @@ >>> locale.format("%d", x, grouping=True) '1,234,567' >>> locale.format("%s%.*f", (conv['currency_symbol'], - ... conv['int_frac_digits'], x), grouping=True) + ... conv['frac_digits'], x), grouping=True) '$1,234,567.80' \end{verbatim} @@ -4974,8 +4975,8 @@ \end{verbatim} Another application for templating is separating program logic from the -details of multiple output formats. The makes it possible to substitute -custom templates for XML files, plain text reports, and HMTL web reports. +details of multiple output formats. This makes it possible to substitute +custom templates for XML files, plain text reports, and HTML web reports. \section{Working with Binary Data Record Layouts\label{binary-formats}} @@ -4995,7 +4996,7 @@ for i in range(3): # show the first 3 file headers start += 14 fields = struct.unpack('LLLHH', data[start:start+16]) - crc32, comp_size, uncomp_size, filenamesize, extra_size = fields + crc32, comp_size, uncomp_size, filenamesize, extra_size = fields start += 16 filename = data[start:start+filenamesize] @@ -5049,7 +5050,7 @@ While those tools are powerful, minor design errors can result in problems that are difficult to reproduce. So, the preferred approach to task coordination is to concentrate all access to a resource -in a single thread and then using the +in a single thread and then use the \ulink{\module{Queue}}{../lib/module-Queue.html} module to feed that thread with requests from other threads. Applications using \class{Queue} objects for inter-thread communication and coordination @@ -5229,7 +5230,7 @@ \end{verbatim} The \class{Decimal} result keeps a trailing zero, automatically inferring four -place significance from the two digit multiplicands. Decimal reproduces +place significance from multiplicands with two place significance. Decimal reproduces mathematics as done by hand and avoids issues that can arise when binary floating point cannot exactly represent decimal quantities. From rhettinger at users.sourceforge.net Tue Aug 23 20:03:43 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 23 Aug 2005 20:03:43 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/tut tut.tex, 1.261.2.11, 1.261.2.12 Message-ID: <20050823180343.5D1711E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5558 Modified Files: Tag: release24-maint tut.tex Log Message: SF bug #1168135: Python 2.5a0 Tutorial errors and observations (Contributed by Michael R Bax.) Index: tut.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/tut.tex,v retrieving revision 1.261.2.11 retrieving revision 1.261.2.12 diff -u -d -r1.261.2.11 -r1.261.2.12 --- tut.tex 23 Aug 2005 15:01:43 -0000 1.261.2.11 +++ tut.tex 23 Aug 2005 18:03:33 -0000 1.261.2.12 @@ -3914,8 +3914,9 @@ the local variable \code{x}. The instantiation operation (``calling'' a class object) creates an -empty object. Many classes like to create objects in a known initial -state. Therefore a class may define a special method named +empty object. Many classes like to create objects with instances +customized to a specific initial state. +Therefore a class may define a special method named \method{__init__()}, like this: \begin{verbatim} @@ -3971,7 +3972,7 @@ del x.counter \end{verbatim} -The other kind of instance attribute references is a \emph{method}. +The other kind of instance attribute reference is a \emph{method}. A method is a function that ``belongs to'' an object. (In Python, the term method is not unique to class instances: other object types can have methods as well. For example, list objects have @@ -3991,13 +3992,13 @@ \subsection{Method Objects \label{methodObjects}} -Usually, a method is called immediately: +Usually, a method is called right after it is bound: \begin{verbatim} x.f() \end{verbatim} -In our example, this will return the string \code{'hello world'}. +In the \class{MyClass} example, this will return the string \code{'hello world'}. However, it is not necessary to call a method right away: \code{x.f} is a method object, and can be stored away and called at a later time. For example: @@ -4075,7 +4076,7 @@ variables and instance variables when glancing through a method. -Conventionally, the first argument of a method is often called +Often, the first argument of a method is called \code{self}. This is nothing more than a convention: the name \code{self} has absolutely no special meaning to Python. (Note, however, that by not following the convention your code may be less @@ -4139,7 +4140,7 @@ Of course, a language feature would not be worthy of the name ``class'' without supporting inheritance. The syntax for a derived class -definition looks as follows: +definition looks like this: \begin{verbatim} class DerivedClassName(BaseClassName): @@ -4151,9 +4152,9 @@ \end{verbatim} The name \class{BaseClassName} must be defined in a scope containing -the derived class definition. Instead of a base class name, an -expression is also allowed. This is useful when the base class is -defined in another module, +the derived class definition. In place of a base class name, other +arbitrary expressions are also allowed. This can be useful, for +example, when the base class is defined in another module: \begin{verbatim} class DerivedClassName(modname.BaseClassName): @@ -4162,7 +4163,7 @@ Execution of a derived class definition proceeds the same as for a base class. When the class object is constructed, the base class is remembered. This is used for resolving attribute references: if a -requested attribute is not found in the class, it is searched in the +requested attribute is not found in the class, the search proceeds to look in the base class. This rule is applied recursively if the base class itself is derived from some other class. @@ -4175,7 +4176,7 @@ Derived classes may override methods of their base classes. Because methods have no special privileges when calling other methods of the same object, a method of a base class that calls another method -defined in the same base class, may in fact end up calling a method of +defined in the same base class may end up calling a method of a derived class that overrides it. (For \Cpp{} programmers: all methods in Python are effectively \keyword{virtual}.) @@ -4190,7 +4191,7 @@ \subsection{Multiple Inheritance \label{multiple}} Python supports a limited form of multiple inheritance as well. A -class definition with multiple base classes looks as follows: +class definition with multiple base classes looks like this: \begin{verbatim} class DerivedClassName(Base1, Base2, Base3): @@ -4349,15 +4350,15 @@ \samp{except B} first), it would have printed B, B, B --- the first matching except clause is triggered. -When an error message is printed for an unhandled exception which is a -class, the class name is printed, then a colon and a space, and +When an error message is printed for an unhandled exception, the +exception's class name is printed, then a colon and a space, and finally the instance converted to a string using the built-in function \function{str()}. \section{Iterators\label{iterators}} -By now, you've probably noticed that most container objects can be looped +By now you have probably noticed that most container objects can be looped over using a \keyword{for} statement: \begin{verbatim} @@ -4396,7 +4397,7 @@ >>> it.next() Traceback (most recent call last): - File "", line 1, in -toplevel- + File "", line 1, in ? it.next() StopIteration \end{verbatim} @@ -4733,7 +4734,7 @@ \section{Performance Measurement\label{performance-measurement}} Some Python users develop a deep interest in knowing the relative -performance between different approaches to the same problem. +performance of different approaches to the same problem. Python provides a measurement tool that answers those questions immediately. @@ -4897,7 +4898,7 @@ >>> locale.format("%d", x, grouping=True) '1,234,567' >>> locale.format("%s%.*f", (conv['currency_symbol'], - ... conv['int_frac_digits'], x), grouping=True) + ... conv['frac_digits'], x), grouping=True) '$1,234,567.80' \end{verbatim} @@ -4964,8 +4965,8 @@ \end{verbatim} Another application for templating is separating program logic from the -details of multiple output formats. The makes it possible to substitute -custom templates for XML files, plain text reports, and HMTL web reports. +details of multiple output formats. This makes it possible to substitute +custom templates for XML files, plain text reports, and HTML web reports. \section{Working with Binary Data Record Layouts\label{binary-formats}} @@ -4985,7 +4986,7 @@ for i in range(3): # show the first 3 file headers start += 14 fields = struct.unpack('LLLHH', data[start:start+16]) - crc32, comp_size, uncomp_size, filenamesize, extra_size = fields + crc32, comp_size, uncomp_size, filenamesize, extra_size = fields start += 16 filename = data[start:start+filenamesize] @@ -5039,7 +5040,7 @@ While those tools are powerful, minor design errors can result in problems that are difficult to reproduce. So, the preferred approach to task coordination is to concentrate all access to a resource -in a single thread and then using the +in a single thread and then use the \ulink{\module{Queue}}{../lib/module-Queue.html} module to feed that thread with requests from other threads. Applications using \class{Queue} objects for inter-thread communication and coordination @@ -5219,7 +5220,7 @@ \end{verbatim} The \class{Decimal} result keeps a trailing zero, automatically inferring four -place significance from the two digit multiplicands. Decimal reproduces +place significance from multiplicands with two place significance. Decimal reproduces mathematics as done by hand and avoids issues that can arise when binary floating point cannot exactly represent decimal quantities. From rhettinger at users.sourceforge.net Tue Aug 23 20:26:11 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Tue, 23 Aug 2005 20:26:11 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/tut tut.tex,1.278,1.279 Message-ID: <20050823182611.1DC851E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/tut In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12606 Modified Files: tut.tex Log Message: More tutorial nits. Index: tut.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/tut/tut.tex,v retrieving revision 1.278 retrieving revision 1.279 diff -u -d -r1.278 -r1.279 --- tut.tex 23 Aug 2005 18:02:28 -0000 1.278 +++ tut.tex 23 Aug 2005 18:26:00 -0000 1.279 @@ -114,7 +114,7 @@ programs, or to test functions during bottom-up program development. It is also a handy desk calculator. -Python enables programs to written compactly and readably. Programs +Python enables programs to be written compactly and readably. Programs written in Python are typically much shorter than equivalent C or \Cpp{} programs, for several reasons: \begin{itemize} @@ -1754,7 +1754,7 @@ \begin{methoddesc}[list]{pop}{\optional{i}} Remove the item at the given position in the list, and return it. If no index is specified, \code{a.pop()} removes and returns the last item -in the list. The item is also removed from the list. (The square brackets +in the list. (The square brackets around the \var{i} in the method signature denote that the parameter is optional, not that you should type square brackets at that position. You will see this notation frequently in the @@ -1987,9 +1987,9 @@ \section{The \keyword{del} statement \label{del}} There is a way to remove an item from a list given its index instead -of its value: the \keyword{del} statement. Unlike the \method{pop()}) -method which returns a value, the \keyword{del} keyword is a statement -and can also be used to +of its value: the \keyword{del} statement. This differs from the +\method{pop()}) method which returns a value. The \keyword{del} +statement can also be used to remove slices from a list (which we did earlier by assignment of an empty list to the slice). For example: @@ -2137,9 +2137,9 @@ keys. Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key. You can't use -lists as keys, since lists can be modified in place using methods like -\method{append()} and \method{extend()} or modified with slice and -indexed assignments. +lists as keys, since lists can be modified in place using +index assignments, slice assignments, or methods like +\method{append()} and \method{extend()}. It is best to think of a dictionary as an unordered set of \emph{key: value} pairs, with the requirement that the keys are unique @@ -5646,7 +5646,7 @@ you can perform an exact analysis of cases like this yourself. Basic familiarity with binary floating-point representation is assumed. -\dfn{Representation error} refers to fact that some (most, actually) +\dfn{Representation error} refers to the fact that some (most, actually) decimal fractions cannot be represented exactly as binary (base 2) fractions. This is the chief reason why Python (or Perl, C, \Cpp, Java, Fortran, and many others) often won't display the exact decimal From greg at electricrain.com Tue Aug 23 21:04:30 2005 From: greg at electricrain.com (Gregory P. Smith) Date: Tue, 23 Aug 2005 12:04:30 -0700 Subject: [Python-checkins] [Python-Dev] python/dist/src/Modules _hashopenssl.c, NONE, 2.1 sha256module.c, NONE, 2.1 sha512module.c, NONE, 2.1 md5module.c, 2.35, 2.36 shamodule.c, 2.22, 2.23 In-Reply-To: <000601c5a7ec$9f614680$8901a044@oemcomputer> References: <20050821184613.A45C11E4288@bag.python.org> <000601c5a7ec$9f614680$8901a044@oemcomputer> Message-ID: <20050823190430.GJ16043@zot.electricrain.com> > This patch should be reverted or fixed so that the Py2.5 build works > again. > > It contains a disasterous search and replace error that prevents it from > compiling. Hence, it couldn't have passed the test suite before being > checked in. > > Also, all of the project and config files need to be updated for the new > modules. It passes fine on linux. I don't have a windows dev environment. regardless, the quick way to work around the sha512 on windows issue is to comment it out in setup.py and comment out the sha384 and sha512 tests in test_hashlib.py and commit that until the complation issues are worked out. -g > > -----Original Message----- > > From: python-checkins-bounces at python.org [mailto:python-checkins- > > bounces at python.org] On Behalf Of greg at users.sourceforge.net > > Sent: Sunday, August 21, 2005 2:46 PM > > To: python-checkins at python.org > > Subject: [Python-checkins] python/dist/src/Modules _hashopenssl.c, > > NONE,2.1 sha256module.c, NONE, 2.1 sha512module.c, NONE,2.1 > md5module.c, > > 2.35, 2.36 shamodule.c, 2.22, 2.23 > > > > Update of /cvsroot/python/python/dist/src/Modules > > In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32064/Modules > > > > Modified Files: > > md5module.c shamodule.c > > Added Files: > > _hashopenssl.c sha256module.c sha512module.c > > Log Message: > > [ sf.net patch # 1121611 ] > > > > A new hashlib module to replace the md5 and sha modules. It adds > > support for additional secure hashes such as SHA-256 and SHA-512. The > > hashlib module uses OpenSSL for fast platform optimized > > implementations of algorithms when available. The old md5 and sha > > modules still exist as wrappers around hashlib to preserve backwards > > compatibility. From gregorykjohnson at users.sourceforge.net Tue Aug 23 21:53:44 2005 From: gregorykjohnson at users.sourceforge.net (gregorykjohnson@users.sourceforge.net) Date: Tue, 23 Aug 2005 21:53:44 +0200 (CEST) Subject: [Python-checkins] python/nondist/sandbox/mailbox libmailbox.tex, 1.15, 1.16 mailbox.py, 1.16, 1.17 Message-ID: <20050823195344.3BA4D1E4003@bag.python.org> Update of /cvsroot/python/python/nondist/sandbox/mailbox In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv2755 Modified Files: libmailbox.tex mailbox.py Log Message: * Add a documentation section on exceptions. * Make a couple small fixes. Index: libmailbox.tex =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/libmailbox.tex,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- libmailbox.tex 23 Aug 2005 03:43:11 -0000 1.15 +++ libmailbox.tex 23 Aug 2005 19:53:33 -0000 1.16 @@ -265,8 +265,8 @@ \begin{notice} The Maildir specification requires the use of a colon (\character{:}) in -certain message file names. Some operating systems do not permit this character -in file names, however. If you wish to use a Maildir-like format on such an +certain message file names. However, some operating systems do not permit this +character in file names, If you wish to use a Maildir-like format on such an operating system, you should specify another character to use instead. The exclamation point (\character{!}) is a popular choice. For example: \begin{verbatim} @@ -365,12 +365,12 @@ messages in an mbox mailbox are stored in a single file with the beginning of each message indicated by a line whose first five characters are "From~". -Several variations of the mbox format exist to address perceived shortcomings. -In the interest of compatibility, \class{mbox} implements the original format, -which is sometimes referred to as \dfn{mboxo}. This means that the -\mailheader{Content-Length} header, if present, is ignored and that any +Several variations of the mbox format exist to address perceived shortcomings +in the original. In the interest of compatibility, \class{mbox} implements the +original format, which is sometimes referred to as \dfn{mboxo}. This means that +the \mailheader{Content-Length} header, if present, is ignored and that any occurrences of "From~" at the beginning of a line in a message body are -transformed to ">From~" when storing the message although occurences of +transformed to ">From~" when storing the message, although occurences of ">From~" are not transformed to "From~" when reading the message. Some \class{Mailbox} methods implemented by \class{mbox} deserve special @@ -423,9 +423,9 @@ \file{.mh_sequences} in each folder. The \class{MH} class manipulates MH mailboxes, but it does not attempt to -emulate all of \program{mh}'s behaviors. In particular, it does not access or -modify the \file{context} or \file{.mh_profile} files that are used by -\program{mh} to store its state and configuration. +emulate all of \program{mh}'s behaviors. In particular, it does not modify and +is not affected by the \file{context} or \file{.mh_profile} files that are used +by \program{mh} to store its state and configuration. \class{MH} instances have all of the methods of \class{Mailbox} in addition to the following: @@ -503,7 +503,7 @@ \begin{seealso} \seelink{http://www.nongnu.org/nmh/}{nmh - Message Handling System}{Home page -of \program{nmh}, a modern version of the original \program{mh}.} +of \program{nmh}, an updated version of the original \program{mh}.} \seelink{http://www.ics.uci.edu/\tilde{}mh/book/}{MH \& nmh: Email for Users \& Programmers}{A GPL-licensed book on \program{mh} and \program{nmh}, with some information on the mailbox format.} @@ -521,12 +521,12 @@ mailbox is created if it does not exist. \end{classdesc} -Babyl is a single-file mailbox format invented for the Rmail mail user agent +Babyl is a single-file mailbox format used by the Rmail mail user agent included with Emacs. The beginning of a message is indicated by a line -containing exactly the two characters Control-Underscore +containing the two characters Control-Underscore (\character{\textbackslash037}) and Control-L (\character{\textbackslash014}). The end of a message is indicated by the start of the next message or, in the -case of the last message, a line containing only a Control-Underscore +case of the last message, a line containing a Control-Underscore (\character{\textbackslash037}) character. Messages in a Babyl mailbox have two sets of headers, original headers and @@ -590,7 +590,7 @@ Control-A (\character{\textbackslash001}) characters. As with the mbox format, the beginning of each message is indicated by a line whose first five characters are "From~", but additional occurrences of "From~" are not -transformed to ">From~" when storing messages because the additional message +transformed to ">From~" when storing messages because the extra message separator lines prevent mistaking such occurrences for the starts of subsequent messages. @@ -681,7 +681,8 @@ subdirectory) or "cur" (if the message should be stored in the \file{cur} subdirectory). \note{A message is typically moved from \file{new} to \file{cur} after its mailbox has been accessed, whether or not the message is has been -read. A message has been read if \code{"S" not in get_flags()} is \code{True}.} +read. A message \code{msg} has been read if \code{"S" not in msg.get_flags()} +is \code{True}.} \end{methoddesc} \begin{methoddesc}{set_subdir}{subdir} @@ -1183,6 +1184,39 @@ \lineii{A flag}{A flag} \end{tableii} +\subsection{Exceptions} +\label{mailbox-deprecated} + +The following exception classes are defined in the \module{mailbox} module: + +\begin{classdesc}{Error}{} +The based class for all other module-specific exceptions. +\end{classdesc} + +\begin{classdesc}{NoSuchMailboxError}{} +Raised when a mailbox is expected but is not found, such as when instantiating +a \class{Mailbox} subclass with a path that does not exist (and with the +\var{create} parameter set to \code{False}), or when opening a folder that does +not exist. +\end{classdesc} + +\begin{classdesc}{NotEmptyErrorError}{} +Raised when a mailbox is not empty but is expected to be, such as when deleting +a folder that contains messages. +\end{classdesc} + +\begin{classdesc}{ExternalClashError}{} +Raised when some mailbox-related condition beyond the control of the program +causes it to be unable to proceed, such as when failing to acquire a lock that +another program already holds a lock, or when a uniquely-generated file name +already exists. +\end{classdesc} + +\begin{classdesc}{FormatError}{} +Raised when the data in a file cannot be parsed, such as when an \class{MH} +instance attempts to read a corrupted \file{.mh_sequences} file. +\end{classdesc} + \subsection{Deprecated classes and methods} \label{mailbox-deprecated} @@ -1302,8 +1336,8 @@ return email.message_from_file(fp) except email.Errors.MessageParseError: # Don't return None since that will - # stop the mailbox iterator - return '' + # stop the mailbox iterator + return '' mbox = mailbox.UnixMailbox(fp, msgfactory) \end{verbatim} Index: mailbox.py =================================================================== RCS file: /cvsroot/python/python/nondist/sandbox/mailbox/mailbox.py,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- mailbox.py 23 Aug 2005 03:43:11 -0000 1.16 +++ mailbox.py 23 Aug 2005 19:53:33 -0000 1.17 @@ -347,7 +347,7 @@ """Lock the mailbox.""" return - def unlock(self, f=None): + def unlock(self): """Unlock the mailbox if it is locked.""" return @@ -1143,7 +1143,8 @@ def get_file(self, key): """Return a file-like representation or raise a KeyError.""" - return StringIO.StringIO(self.get_string(key)) + return StringIO.StringIO(self.get_string(key).replace('\n', + os.linesep)) def get_labels(self): """Return a list of user-defined labels in the mailbox.""" From greg at users.sourceforge.net Tue Aug 23 23:19:51 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Tue, 23 Aug 2005 23:19:51 +0200 (CEST) Subject: [Python-checkins] python/dist/src setup.py,1.220,1.221 Message-ID: <20050823211951.19C4D1E400C@bag.python.org> Update of /cvsroot/python/python/dist/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24629 Modified Files: setup.py Log Message: Add a check for the OpenSSL version number to conditionally compile the _hashlibopenssl module (>= 0.9.7 required) and to not compile the sha256 and sha512 modules if OpenSSL >= 0.9.8 is found. Index: setup.py =================================================================== RCS file: /cvsroot/python/python/dist/src/setup.py,v retrieving revision 1.220 retrieving revision 1.221 diff -u -d -r1.220 -r1.221 --- setup.py 21 Aug 2005 18:45:58 -0000 1.220 +++ setup.py 23 Aug 2005 21:19:40 -0000 1.221 @@ -474,10 +474,12 @@ exts.append( Extension('_socket', ['socketmodule.c'], depends = ['socketmodule.h']) ) # Detect SSL support for the socket module (via _ssl) - ssl_incs = find_file('openssl/ssl.h', inc_dirs, - ['/usr/local/ssl/include', + search_for_ssl_incs_in = [ + '/usr/local/ssl/include', '/usr/contrib/ssl/include/' ] + ssl_incs = find_file('openssl/ssl.h', inc_dirs, + search_for_ssl_incs_in ) if ssl_incs is not None: krb5_h = find_file('krb5.h', inc_dirs, @@ -497,8 +499,32 @@ libraries = ['ssl', 'crypto'], depends = ['socketmodule.h']), ) + # find out which version of OpenSSL we have + openssl_ver = 0 + openssl_ver_re = re.compile( + '^\s*#\s*define\s+OPENSSL_VERSION_NUMBER\s+(0x[0-9a-fA-F]+)' ) + for ssl_inc_dir in inc_dirs + search_for_ssl_incs_in: + name = os.path.join(ssl_inc_dir, 'openssl', 'opensslv.h') + if os.path.isfile(name): + try: + incfile = open(name, 'r') + for line in incfile: + m = openssl_ver_re.match(line) + if m: + openssl_ver = eval(m.group(1)) + break + except IOError: + pass + + # first version found is what we'll use (as the compiler should) + if openssl_ver: + break + + #print 'openssl_ver = 0x%08x' % openssl_ver + if (ssl_incs is not None and - ssl_libs is not None): + ssl_libs is not None and + openssl_ver >= 0x00907000): # The _hashlib module wraps optimized implementations # of hash functions from the OpenSSL library. exts.append( Extension('_hashlib', ['_hashopenssl.c'], @@ -513,14 +539,10 @@ # necessary files md5c.c and md5.h are included here. exts.append( Extension('_md5', ['md5module.c', 'md5c.c']) ) - # always compile these for now under the assumption that - # OpenSSL does not support them (it doesn't in common OpenSSL - # 0.9.7e installs at the time of this writing; OpenSSL 0.9.8 - # does). In the future we could make this conditional on - # OpenSSL version or support. The hashlib module uses the - # better implementation regardless. - exts.append( Extension('_sha256', ['sha256module.c']) ) - exts.append( Extension('_sha512', ['sha512module.c']) ) + if (openssl_ver < 0x00908000): + # OpenSSL doesn't do these until 0.9.8 so we'll bring our own hash + exts.append( Extension('_sha256', ['sha256module.c']) ) + exts.append( Extension('_sha512', ['sha512module.c']) ) # Modules that provide persistent dictionary-like semantics. You will From greg at users.sourceforge.net Tue Aug 23 23:30:16 2005 From: greg at users.sourceforge.net (greg@users.sourceforge.net) Date: Tue, 23 Aug 2005 23:30:16 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules sha512module.c,2.1,2.2 Message-ID: <20050823213016.E85CA1E4090@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26573/Modules Modified Files: sha512module.c Log Message: Remove the C99 "ULL" suffix from the 64bit unsigned long constants. VC++6 doesn't accept them. This *will* result in tons of the following warning from gcc 3.x: (gcc "2.96ish" doesn't issue this warning) warning: integer constant is too large for "long" type the code compiles fine regardless. squashing the gcc warnings is the next task. Would someone on windows please confirm that this does or does not compile and if it does or does not pass the test_hashlib.py unit tests. Index: sha512module.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/sha512module.c,v retrieving revision 2.1 retrieving revision 2.2 diff -u -d -r2.1 -r2.2 --- sha512module.c 21 Aug 2005 18:46:02 -0000 2.1 +++ sha512module.c 23 Aug 2005 21:30:04 -0000 2.2 @@ -121,12 +121,12 @@ /* Various logical functions */ #define ROR64(x, y) \ - ( ((((x) & 0xFFFFFFFFFFFFFFFFULL)>>((unsigned PY_LONG_LONG)(y) & 63)) | \ - ((x)<<((unsigned PY_LONG_LONG)(64-((y) & 63))))) & 0xFFFFFFFFFFFFFFFFULL) + ( ((((x) & 0xFFFFFFFFFFFFFFFF)>>((unsigned PY_LONG_LONG)(y) & 63)) | \ + ((x)<<((unsigned PY_LONG_LONG)(64-((y) & 63))))) & 0xFFFFFFFFFFFFFFFF) #define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Maj(x,y,z) (((x | y) & z) | (x & y)) #define S(x, n) ROR64((x),(n)) -#define R(x, n) (((x) & 0xFFFFFFFFFFFFFFFFULL) >> ((unsigned PY_LONG_LONG)n)) +#define R(x, n) (((x) & 0xFFFFFFFFFFFFFFFF) >> ((unsigned PY_LONG_LONG)n)) #define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) #define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) #define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) @@ -156,86 +156,86 @@ d += t0; \ h = t0 + t1; - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98d728ae22ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x7137449123ef65cdULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcfec4d3b2fULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba58189dbbcULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25bf348b538ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1b605d019ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4af194f9bULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5da6d8118ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98a3030242ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b0145706fbeULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be4ee4b28cULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3d5ffb4e2ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74f27b896fULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe3b1696b1ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a725c71235ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174cf692694ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c19ef14ad2ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786384f25e3ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc68b8cd5b5ULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc77ac9c65ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f592b0275ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa6ea6e483ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dcbd41fbd4ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da831153b5ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152ee66dfabULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d2db43210ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c898fb213fULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7beef0ee4ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf33da88fc2ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147930aa725ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351e003826fULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x142929670a0e6e70ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a8546d22ffcULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b21385c26c926ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc5ac42aedULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d139d95b3dfULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a73548baf63deULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb3c77b2a8ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e47edaee6ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c851482353bULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a14cf10364ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664bbc423001ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70d0f89791ULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a30654be30ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819d6ef5218ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd69906245565a910ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e35855771202aULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa07032bbd1b8ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116b8d2d0c8ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c085141ab53ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774cdf8eeb99ULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5e19b48a8ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3c5c95a63ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4ae3418acbULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f7763e373ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3d6b2b8a3ULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee5defb2fcULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f43172f60ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814a1f0ab72ULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc702081a6439ecULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa23631e28ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506cebde82bde9ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7b2c67915ULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2e372532bULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],64,0xca273eceea26619cULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],65,0xd186b8c721c0c207ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],66,0xeada7dd6cde0eb1eULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],67,0xf57d4f7fee6ed178ULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],68,0x06f067aa72176fbaULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],69,0x0a637dc5a2c898a6ULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],70,0x113f9804bef90daeULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],71,0x1b710b35131c471bULL); - RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],72,0x28db77f523047d84ULL); - RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],73,0x32caab7b40c72493ULL); - RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],74,0x3c9ebe0a15c9bebcULL); - RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],75,0x431d67c49c100d4cULL); - RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],76,0x4cc5d4becb3e42b6ULL); - RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],77,0x597f299cfc657e2aULL); - RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],78,0x5fcb6fab3ad6faecULL); - RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],79,0x6c44198c4a475817ULL); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],0,0x428a2f98d728ae22); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],1,0x7137449123ef65cd); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],2,0xb5c0fbcfec4d3b2f); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],3,0xe9b5dba58189dbbc); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],4,0x3956c25bf348b538); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],5,0x59f111f1b605d019); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],6,0x923f82a4af194f9b); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],7,0xab1c5ed5da6d8118); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],8,0xd807aa98a3030242); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],9,0x12835b0145706fbe); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],10,0x243185be4ee4b28c); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],11,0x550c7dc3d5ffb4e2); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],12,0x72be5d74f27b896f); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],13,0x80deb1fe3b1696b1); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],14,0x9bdc06a725c71235); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],15,0xc19bf174cf692694); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],16,0xe49b69c19ef14ad2); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],17,0xefbe4786384f25e3); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],18,0x0fc19dc68b8cd5b5); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],19,0x240ca1cc77ac9c65); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],20,0x2de92c6f592b0275); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],21,0x4a7484aa6ea6e483); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],22,0x5cb0a9dcbd41fbd4); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],23,0x76f988da831153b5); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],24,0x983e5152ee66dfab); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],25,0xa831c66d2db43210); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],26,0xb00327c898fb213f); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],27,0xbf597fc7beef0ee4); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],28,0xc6e00bf33da88fc2); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],29,0xd5a79147930aa725); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],30,0x06ca6351e003826f); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],31,0x142929670a0e6e70); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],32,0x27b70a8546d22ffc); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],33,0x2e1b21385c26c926); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],34,0x4d2c6dfc5ac42aed); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],35,0x53380d139d95b3df); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],36,0x650a73548baf63de); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],37,0x766a0abb3c77b2a8); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],38,0x81c2c92e47edaee6); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],39,0x92722c851482353b); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],40,0xa2bfe8a14cf10364); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],41,0xa81a664bbc423001); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],42,0xc24b8b70d0f89791); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],43,0xc76c51a30654be30); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],44,0xd192e819d6ef5218); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],45,0xd69906245565a910); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],46,0xf40e35855771202a); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],47,0x106aa07032bbd1b8); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],48,0x19a4c116b8d2d0c8); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],49,0x1e376c085141ab53); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],50,0x2748774cdf8eeb99); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],51,0x34b0bcb5e19b48a8); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],52,0x391c0cb3c5c95a63); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],53,0x4ed8aa4ae3418acb); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],54,0x5b9cca4f7763e373); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],55,0x682e6ff3d6b2b8a3); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],56,0x748f82ee5defb2fc); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],57,0x78a5636f43172f60); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],58,0x84c87814a1f0ab72); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],59,0x8cc702081a6439ec); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],60,0x90befffa23631e28); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],61,0xa4506cebde82bde9); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],62,0xbef9a3f7b2c67915); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],63,0xc67178f2e372532b); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],64,0xca273eceea26619c); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],65,0xd186b8c721c0c207); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],66,0xeada7dd6cde0eb1e); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],67,0xf57d4f7fee6ed178); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],68,0x06f067aa72176fba); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],69,0x0a637dc5a2c898a6); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],70,0x113f9804bef90dae); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],71,0x1b710b35131c471b); + RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],72,0x28db77f523047d84); + RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],73,0x32caab7b40c72493); + RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],74,0x3c9ebe0a15c9bebc); + RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],75,0x431d67c49c100d4c); + RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],76,0x4cc5d4becb3e42b6); + RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],77,0x597f299cfc657e2a); + RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],78,0x5fcb6fab3ad6faec); + RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],79,0x6c44198c4a475817); #undef RND @@ -254,14 +254,14 @@ sha512_init(SHAobject *sha_info) { TestEndianness(sha_info->Endianness) - sha_info->digest[0] = 0x6a09e667f3bcc908ULL; - sha_info->digest[1] = 0xbb67ae8584caa73bULL; - sha_info->digest[2] = 0x3c6ef372fe94f82bULL; - sha_info->digest[3] = 0xa54ff53a5f1d36f1ULL; - sha_info->digest[4] = 0x510e527fade682d1ULL; - sha_info->digest[5] = 0x9b05688c2b3e6c1fULL; - sha_info->digest[6] = 0x1f83d9abfb41bd6bULL; - sha_info->digest[7] = 0x5be0cd19137e2179ULL; + sha_info->digest[0] = 0x6a09e667f3bcc908; + sha_info->digest[1] = 0xbb67ae8584caa73b; + sha_info->digest[2] = 0x3c6ef372fe94f82b; + sha_info->digest[3] = 0xa54ff53a5f1d36f1; + sha_info->digest[4] = 0x510e527fade682d1; + sha_info->digest[5] = 0x9b05688c2b3e6c1f; + sha_info->digest[6] = 0x1f83d9abfb41bd6b; + sha_info->digest[7] = 0x5be0cd19137e2179; sha_info->count_lo = 0L; sha_info->count_hi = 0L; sha_info->local = 0; @@ -272,14 +272,14 @@ sha384_init(SHAobject *sha_info) { TestEndianness(sha_info->Endianness) - sha_info->digest[0] = 0xcbbb9d5dc1059ed8ULL; - sha_info->digest[1] = 0x629a292a367cd507ULL; - sha_info->digest[2] = 0x9159015a3070dd17ULL; - sha_info->digest[3] = 0x152fecd8f70e5939ULL; - sha_info->digest[4] = 0x67332667ffc00b31ULL; - sha_info->digest[5] = 0x8eb44a8768581511ULL; - sha_info->digest[6] = 0xdb0c2e0d64f98fa7ULL; - sha_info->digest[7] = 0x47b5481dbefa4fa4ULL; + sha_info->digest[0] = 0xcbbb9d5dc1059ed8; + sha_info->digest[1] = 0x629a292a367cd507; + sha_info->digest[2] = 0x9159015a3070dd17; + sha_info->digest[3] = 0x152fecd8f70e5939; + sha_info->digest[4] = 0x67332667ffc00b31; + sha_info->digest[5] = 0x8eb44a8768581511; + sha_info->digest[6] = 0xdb0c2e0d64f98fa7; + sha_info->digest[7] = 0x47b5481dbefa4fa4; sha_info->count_lo = 0L; sha_info->count_hi = 0L; sha_info->local = 0; From rhettinger at users.sourceforge.net Wed Aug 24 02:24:51 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 24 Aug 2005 02:24:51 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects setobject.c,1.54,1.55 Message-ID: <20050824002451.47F671E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9408 Modified Files: setobject.c Log Message: * Add a fast equality check path for frozensets where the hash value has already been computed. * Apply a GET_SIZE macro(). Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.54 retrieving revision 1.55 diff -u -d -r1.54 -r1.55 --- setobject.c 17 Aug 2005 12:27:17 -0000 1.54 +++ setobject.c 24 Aug 2005 00:24:40 -0000 1.55 @@ -1495,12 +1495,15 @@ case Py_EQ: if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w)) Py_RETURN_FALSE; + if (v->hash != -1 && + ((PySetObject *)w)->hash != -1 && + v->hash != ((PySetObject *)w)->hash) + Py_RETURN_FALSE; return set_issubset(v, w); case Py_NE: - if (PySet_GET_SIZE(v) != PySet_GET_SIZE(w)) - Py_RETURN_TRUE; - r1 = set_issubset(v, w); - assert (r1 != NULL); + r1 = set_richcompare(v, w, Py_EQ); + if (r1 == NULL) + return NULL; r2 = PyBool_FromLong(PyObject_Not(r1)); Py_DECREF(r1); return r2; @@ -1956,7 +1959,7 @@ PyErr_BadInternalCall(); return -1; } - return ((PySetObject *)anyset)->used; + return PySet_GET_SIZE(anyset); } int From rhettinger at users.sourceforge.net Wed Aug 24 02:28:31 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 24 Aug 2005 02:28:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/PC/VC6 pythoncore.dsp,1.17,1.18 Message-ID: <20050824002831.4D8EA1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/PC/VC6 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10518/PC/VC6 Modified Files: pythoncore.dsp Log Message: Update the PC configuration and project files for sha256 and sha512. Index: pythoncore.dsp =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/VC6/pythoncore.dsp,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- pythoncore.dsp 28 Feb 2005 19:39:44 -0000 1.17 +++ pythoncore.dsp 24 Aug 2005 00:28:21 -0000 1.18 @@ -539,6 +539,14 @@ # End Source File # Begin Source File +SOURCE=..\..\Modules\sha256module.c +# End Source File +# Begin Source File + +SOURCE=..\..\Modules\sha512module.c +# End Source File +# Begin Source File + SOURCE=..\..\Modules\signalmodule.c # End Source File # Begin Source File From rhettinger at users.sourceforge.net Wed Aug 24 02:28:31 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 24 Aug 2005 02:28:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/PCbuild pythoncore.vcproj, 1.27, 1.28 Message-ID: <20050824002831.8001A1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/PCbuild In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10518/PCbuild Modified Files: pythoncore.vcproj Log Message: Update the PC configuration and project files for sha256 and sha512. Index: pythoncore.vcproj =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/pythoncore.vcproj,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- pythoncore.vcproj 28 Feb 2005 19:39:44 -0000 1.27 +++ pythoncore.vcproj 24 Aug 2005 00:28:21 -0000 1.28 @@ -2764,6 +2764,60 @@ + + + + + + + + + + + + + + + + + + + + + + From rhettinger at users.sourceforge.net Wed Aug 24 02:28:31 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 24 Aug 2005 02:28:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/PC config.c,1.52,1.53 Message-ID: <20050824002831.C3AA41E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/PC In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10518/PC Modified Files: config.c Log Message: Update the PC configuration and project files for sha256 and sha512. Index: config.c =================================================================== RCS file: /cvsroot/python/python/dist/src/PC/config.c,v retrieving revision 1.52 retrieving revision 1.53 diff -u -d -r1.52 -r1.53 --- config.c 28 Feb 2005 19:39:44 -0000 1.52 +++ config.c 24 Aug 2005 00:28:19 -0000 1.53 @@ -17,7 +17,7 @@ extern void initimageop(void); #endif extern void initmath(void); -extern void initmd5(void); +extern void init_md5(void); extern void initnt(void); extern void initoperator(void); extern void initregex(void); @@ -25,7 +25,9 @@ extern void initrgbimg(void); #endif extern void initsignal(void); -extern void initsha(void); +extern void init_sha(void); +extern void init_sha256(void); +extern void init_sha512(void); extern void initstrop(void); extern void initstruct(void); extern void inittime(void); @@ -86,7 +88,7 @@ {"imageop", initimageop}, #endif {"math", initmath}, - {"md5", initmd5}, + {"_md5", init_md5}, {"nt", initnt}, /* Use the NT os functions, not posix */ {"operator", initoperator}, {"regex", initregex}, @@ -94,7 +96,9 @@ {"rgbimg", initrgbimg}, #endif {"signal", initsignal}, - {"sha", initsha}, + {"_sha", init_sha}, + {"_sha256", init_sha256}, + {"_sha512", init_sha512}, {"strop", initstrop}, {"struct", initstruct}, {"time", inittime}, From rhettinger at users.sourceforge.net Wed Aug 24 06:47:16 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 24 Aug 2005 06:47:16 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib ftplib.py,1.73,1.73.4.1 Message-ID: <20050824044716.7FFBD1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27057 Modified Files: Tag: release24-maint ftplib.py Log Message: Backport 1.74 Index: ftplib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/ftplib.py,v retrieving revision 1.73 retrieving revision 1.73.4.1 diff -u -d -r1.73 -r1.73.4.1 --- ftplib.py 12 Feb 2004 17:35:06 -0000 1.73 +++ ftplib.py 24 Aug 2005 04:47:05 -0000 1.73.4.1 @@ -208,13 +208,13 @@ if self.debugging: print '*resp*', self.sanitize(resp) self.lastresp = resp[:3] c = resp[:1] + if c in ('1', '2', '3'): + return resp if c == '4': raise error_temp, resp if c == '5': raise error_perm, resp - if c not in '123': - raise error_proto, resp - return resp + raise error_proto, resp def voidresp(self): """Expect a response beginning with '2'.""" @@ -582,17 +582,17 @@ Raises error_proto if it does not contain '(|||port|)' Return ('host.addr.as.numbers', port#) tuple.''' - if resp[:3] <> '229': + if resp[:3] != '229': raise error_reply, resp left = resp.find('(') if left < 0: raise error_proto, resp right = resp.find(')', left + 1) if right < 0: raise error_proto, resp # should contain '(|||port|)' - if resp[left + 1] <> resp[right - 1]: + if resp[left + 1] != resp[right - 1]: raise error_proto, resp parts = resp[left + 1:right].split(resp[left+1]) - if len(parts) <> 5: + if len(parts) != 5: raise error_proto, resp host = peer[0] port = int(parts[3]) @@ -755,7 +755,16 @@ def test(): '''Test program. - Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ...''' + Usage: ftp [-d] [-r[file]] host [-l[dir]] [-d[dir]] [-p] [file] ... + + -d dir + -l list + -p password + ''' + + if len(sys.argv) < 2: + print test.__doc__ + sys.exit(0) debugging = 0 rcfile = None From loewis at users.sourceforge.net Wed Aug 24 08:07:03 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 08:07:03 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1338,1.1339 Message-ID: <20050824060703.1DDF51E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7036/Misc Modified Files: NEWS Log Message: Patch #1262036: Make tarfile name absolute. Fixes #1257255. Will backport to 2.4. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1338 retrieving revision 1.1339 diff -u -d -r1.1338 -r1.1339 --- NEWS 23 Aug 2005 00:57:07 -0000 1.1338 +++ NEWS 24 Aug 2005 06:06:52 -0000 1.1339 @@ -188,6 +188,8 @@ Library ------- +- Patch #1262036: Make tarfile name absolute. Fixes #1257255. + - Patch #827386: Support absolute source paths in msvccompiler.py. - Patch #1105730: Apply the new implementation of commonprefix in posixpath From loewis at users.sourceforge.net Wed Aug 24 08:07:03 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 08:07:03 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib tarfile.py,1.29,1.30 Message-ID: <20050824060703.608C81E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7036/Lib Modified Files: tarfile.py Log Message: Patch #1262036: Make tarfile name absolute. Fixes #1257255. Will backport to 2.4. Index: tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/tarfile.py,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- tarfile.py 22 Jul 2005 21:49:29 -0000 1.29 +++ tarfile.py 24 Aug 2005 06:06:52 -0000 1.30 @@ -849,7 +849,7 @@ can be determined, `mode' is overridden by `fileobj's mode. `fileobj' is not closed, when TarFile is closed. """ - self.name = name + self.name = os.path.abspath(name) if len(mode) > 1 or mode not in "raw": raise ValueError, "mode must be 'r', 'a' or 'w'" @@ -861,7 +861,7 @@ self._extfileobj = False else: if self.name is None and hasattr(fileobj, "name"): - self.name = fileobj.name + self.name = os.path.abspath(fileobj.name) if hasattr(fileobj, "mode"): self.mode = fileobj.mode self._extfileobj = True @@ -998,22 +998,18 @@ raise CompressionError, "gzip module is not available" pre, ext = os.path.splitext(name) - pre = os.path.basename(pre) if ext == ".tgz": ext = ".tar" if ext == ".gz": ext = "" - tarname = pre + ext + tarname = os.path.basename(pre + ext) if fileobj is None: fileobj = file(name, mode + "b") - if mode != "r": - name = tarname - try: - t = cls.taropen(tarname, mode, - gzip.GzipFile(name, mode, compresslevel, fileobj) + t = cls.taropen(name, mode, + gzip.GzipFile(tarname, mode, compresslevel, fileobj) ) except IOError: raise ReadError, "not a gzip file" @@ -1033,19 +1029,11 @@ except ImportError: raise CompressionError, "bz2 module is not available" - pre, ext = os.path.splitext(name) - pre = os.path.basename(pre) - if ext == ".tbz2": - ext = ".tar" - if ext == ".bz2": - ext = "" - tarname = pre + ext - if fileobj is not None: raise ValueError, "no support for external file objects" try: - t = cls.taropen(tarname, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel)) + t = cls.taropen(name, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel)) except IOError: raise ReadError, "not a bzip2 file" t._extfileobj = False @@ -1250,8 +1238,7 @@ arcname = name # Skip if somebody tries to archive the archive... - if self.name is not None \ - and os.path.abspath(name) == os.path.abspath(self.name): + if self.name is not None and os.path.samefile(name, self.name): self._dbg(2, "tarfile: Skipped %r" % name) return From loewis at users.sourceforge.net Wed Aug 24 08:07:27 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 08:07:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.74, 1.1193.2.75 Message-ID: <20050824060727.860F21E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7131/Misc Modified Files: Tag: release24-maint NEWS Log Message: Patch #1262036: Make tarfile name absolute. Fixes #1257255. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.74 retrieving revision 1.1193.2.75 diff -u -d -r1.1193.2.74 -r1.1193.2.75 --- NEWS 22 Aug 2005 18:07:04 -0000 1.1193.2.74 +++ NEWS 24 Aug 2005 06:07:17 -0000 1.1193.2.75 @@ -63,6 +63,8 @@ Library ------- +- Patch #1262036: Make tarfile name absolute. Fixes #1257255. + - Bug #1266283: "lexists" is now in os.path.__all__. - The sets module can now properly compute s-=s and s^=s as an empty set. From loewis at users.sourceforge.net Wed Aug 24 08:07:27 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 08:07:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib tarfile.py, 1.21.2.2, 1.21.2.3 Message-ID: <20050824060727.C5EA71E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7131/Lib Modified Files: Tag: release24-maint tarfile.py Log Message: Patch #1262036: Make tarfile name absolute. Fixes #1257255. Index: tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/tarfile.py,v retrieving revision 1.21.2.2 retrieving revision 1.21.2.3 diff -u -d -r1.21.2.2 -r1.21.2.3 --- tarfile.py 22 Jul 2005 21:48:50 -0000 1.21.2.2 +++ tarfile.py 24 Aug 2005 06:07:17 -0000 1.21.2.3 @@ -800,7 +800,7 @@ can be determined, `mode' is overridden by `fileobj's mode. `fileobj' is not closed, when TarFile is closed. """ - self.name = name + self.name = os.path.abspath(name) if len(mode) > 1 or mode not in "raw": raise ValueError, "mode must be 'r', 'a' or 'w'" @@ -812,7 +812,7 @@ self._extfileobj = False else: if self.name is None and hasattr(fileobj, "name"): - self.name = fileobj.name + self.name = os.path.abspath(fileobj.name) if hasattr(fileobj, "mode"): self.mode = fileobj.mode self._extfileobj = True @@ -948,22 +948,18 @@ raise CompressionError, "gzip module is not available" pre, ext = os.path.splitext(name) - pre = os.path.basename(pre) if ext == ".tgz": ext = ".tar" if ext == ".gz": ext = "" - tarname = pre + ext + tarname = os.path.basename(pre + ext) if fileobj is None: fileobj = file(name, mode + "b") - if mode != "r": - name = tarname - try: - t = cls.taropen(tarname, mode, - gzip.GzipFile(name, mode, compresslevel, fileobj) + t = cls.taropen(name, mode, + gzip.GzipFile(tarname, mode, compresslevel, fileobj) ) except IOError: raise ReadError, "not a gzip file" @@ -984,19 +980,11 @@ except ImportError: raise CompressionError, "bz2 module is not available" - pre, ext = os.path.splitext(name) - pre = os.path.basename(pre) - if ext == ".tbz2": - ext = ".tar" - if ext == ".bz2": - ext = "" - tarname = pre + ext - if fileobj is not None: raise ValueError, "no support for external file objects" try: - t = cls.taropen(tarname, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel)) + t = cls.taropen(name, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel)) except IOError: raise ReadError, "not a bzip2 file" t._extfileobj = False @@ -1203,8 +1191,7 @@ arcname = name # Skip if somebody tries to archive the archive... - if self.name is not None \ - and os.path.abspath(name) == os.path.abspath(self.name): + if self.name is not None and os.path.samefile(name, self.name): self._dbg(2, "tarfile: Skipped %r" % name) return From loewis at users.sourceforge.net Wed Aug 24 08:43:19 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 08:43:19 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib tarfile.py,1.30,1.31 Message-ID: <20050824064319.5EC281E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13637/Lib Modified Files: tarfile.py Log Message: Revert previous checkin. Index: tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/tarfile.py,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- tarfile.py 24 Aug 2005 06:06:52 -0000 1.30 +++ tarfile.py 24 Aug 2005 06:43:09 -0000 1.31 @@ -849,7 +849,7 @@ can be determined, `mode' is overridden by `fileobj's mode. `fileobj' is not closed, when TarFile is closed. """ - self.name = os.path.abspath(name) + self.name = name if len(mode) > 1 or mode not in "raw": raise ValueError, "mode must be 'r', 'a' or 'w'" @@ -861,7 +861,7 @@ self._extfileobj = False else: if self.name is None and hasattr(fileobj, "name"): - self.name = os.path.abspath(fileobj.name) + self.name = fileobj.name if hasattr(fileobj, "mode"): self.mode = fileobj.mode self._extfileobj = True @@ -998,18 +998,22 @@ raise CompressionError, "gzip module is not available" pre, ext = os.path.splitext(name) + pre = os.path.basename(pre) if ext == ".tgz": ext = ".tar" if ext == ".gz": ext = "" - tarname = os.path.basename(pre + ext) + tarname = pre + ext if fileobj is None: fileobj = file(name, mode + "b") + if mode != "r": + name = tarname + try: - t = cls.taropen(name, mode, - gzip.GzipFile(tarname, mode, compresslevel, fileobj) + t = cls.taropen(tarname, mode, + gzip.GzipFile(name, mode, compresslevel, fileobj) ) except IOError: raise ReadError, "not a gzip file" @@ -1029,11 +1033,19 @@ except ImportError: raise CompressionError, "bz2 module is not available" + pre, ext = os.path.splitext(name) + pre = os.path.basename(pre) + if ext == ".tbz2": + ext = ".tar" + if ext == ".bz2": + ext = "" + tarname = pre + ext + if fileobj is not None: raise ValueError, "no support for external file objects" try: - t = cls.taropen(name, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel)) + t = cls.taropen(tarname, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel)) except IOError: raise ReadError, "not a bzip2 file" t._extfileobj = False @@ -1238,7 +1250,8 @@ arcname = name # Skip if somebody tries to archive the archive... - if self.name is not None and os.path.samefile(name, self.name): + if self.name is not None \ + and os.path.abspath(name) == os.path.abspath(self.name): self._dbg(2, "tarfile: Skipped %r" % name) return From loewis at users.sourceforge.net Wed Aug 24 08:43:19 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 08:43:19 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1339,1.1340 Message-ID: <20050824064319.6E9EA1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13637/Misc Modified Files: NEWS Log Message: Revert previous checkin. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1339 retrieving revision 1.1340 diff -u -d -r1.1339 -r1.1340 --- NEWS 24 Aug 2005 06:06:52 -0000 1.1339 +++ NEWS 24 Aug 2005 06:43:09 -0000 1.1340 @@ -188,8 +188,6 @@ Library ------- -- Patch #1262036: Make tarfile name absolute. Fixes #1257255. - - Patch #827386: Support absolute source paths in msvccompiler.py. - Patch #1105730: Apply the new implementation of commonprefix in posixpath From loewis at users.sourceforge.net Wed Aug 24 08:45:06 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 08:45:06 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.75, 1.1193.2.76 Message-ID: <20050824064506.AB7001E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13900/Misc Modified Files: Tag: release24-maint NEWS Log Message: Revert previous checkin. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.75 retrieving revision 1.1193.2.76 diff -u -d -r1.1193.2.75 -r1.1193.2.76 --- NEWS 24 Aug 2005 06:07:17 -0000 1.1193.2.75 +++ NEWS 24 Aug 2005 06:44:56 -0000 1.1193.2.76 @@ -63,8 +63,6 @@ Library ------- -- Patch #1262036: Make tarfile name absolute. Fixes #1257255. - - Bug #1266283: "lexists" is now in os.path.__all__. - The sets module can now properly compute s-=s and s^=s as an empty set. From loewis at users.sourceforge.net Wed Aug 24 08:45:07 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 08:45:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib tarfile.py, 1.21.2.3, 1.21.2.4 Message-ID: <20050824064507.01DF71E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13900/Lib Modified Files: Tag: release24-maint tarfile.py Log Message: Revert previous checkin. Index: tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/tarfile.py,v retrieving revision 1.21.2.3 retrieving revision 1.21.2.4 diff -u -d -r1.21.2.3 -r1.21.2.4 --- tarfile.py 24 Aug 2005 06:07:17 -0000 1.21.2.3 +++ tarfile.py 24 Aug 2005 06:44:55 -0000 1.21.2.4 @@ -800,7 +800,7 @@ can be determined, `mode' is overridden by `fileobj's mode. `fileobj' is not closed, when TarFile is closed. """ - self.name = os.path.abspath(name) + self.name = name if len(mode) > 1 or mode not in "raw": raise ValueError, "mode must be 'r', 'a' or 'w'" @@ -812,7 +812,7 @@ self._extfileobj = False else: if self.name is None and hasattr(fileobj, "name"): - self.name = os.path.abspath(fileobj.name) + self.name = fileobj.name if hasattr(fileobj, "mode"): self.mode = fileobj.mode self._extfileobj = True @@ -948,18 +948,22 @@ raise CompressionError, "gzip module is not available" pre, ext = os.path.splitext(name) + pre = os.path.basename(pre) if ext == ".tgz": ext = ".tar" if ext == ".gz": ext = "" - tarname = os.path.basename(pre + ext) + tarname = pre + ext if fileobj is None: fileobj = file(name, mode + "b") + if mode != "r": + name = tarname + try: - t = cls.taropen(name, mode, - gzip.GzipFile(tarname, mode, compresslevel, fileobj) + t = cls.taropen(tarname, mode, + gzip.GzipFile(name, mode, compresslevel, fileobj) ) except IOError: raise ReadError, "not a gzip file" @@ -980,11 +984,19 @@ except ImportError: raise CompressionError, "bz2 module is not available" + pre, ext = os.path.splitext(name) + pre = os.path.basename(pre) + if ext == ".tbz2": + ext = ".tar" + if ext == ".bz2": + ext = "" + tarname = pre + ext + if fileobj is not None: raise ValueError, "no support for external file objects" try: - t = cls.taropen(name, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel)) + t = cls.taropen(tarname, mode, bz2.BZ2File(name, mode, compresslevel=compresslevel)) except IOError: raise ReadError, "not a bzip2 file" t._extfileobj = False @@ -1191,7 +1203,8 @@ arcname = name # Skip if somebody tries to archive the archive... - if self.name is not None and os.path.samefile(name, self.name): + if self.name is not None \ + and os.path.abspath(name) == os.path.abspath(self.name): self._dbg(2, "tarfile: Skipped %r" % name) return From rhettinger at users.sourceforge.net Wed Aug 24 09:06:36 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:06:36 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libfuncs.tex, 1.188, 1.189 Message-ID: <20050824070636.65F4F1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17304 Modified Files: libfuncs.tex Log Message: SF bug #1100368: Wrong "type()" syntax in docs Docs were missing the name/bases/dict form of type(). (Much of the wording contributed by Steven Bethard.) Index: libfuncs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libfuncs.tex,v retrieving revision 1.188 retrieving revision 1.189 diff -u -d -r1.188 -r1.189 --- libfuncs.tex 23 Aug 2005 04:33:29 -0000 1.188 +++ libfuncs.tex 24 Aug 2005 07:06:25 -0000 1.189 @@ -1057,26 +1057,30 @@ \begin{funcdesc}{type}{object} Return the type of an \var{object}. The return value is a - type\obindex{type} object. The standard module - \module{types}\refstmodindex{types} defines names for all built-in - types that don't already have built-in names. - For instance: + type\obindex{type} object. The \function{isinstance()} built-in + function is recommended for testing the type of an object. + + With three arguments, \function{type} functions as a constructor + as detailed below. +\end{funcdesc} + +\begin{funcdesc}{type}{name, bases, dict} + Return a new type object. This is essentially a dynamic form of the + \keyword{class} statement. The \var{name} string is the class name + and becomes the \member{__name__} attribute; the \var{bases} tuple + itemizes the base classes and becomes the \member{__bases__} + attribute; and the \var{dict} dictionary is the namespace containing + definitions for class body and becomes the \member{__dict__} + attribute. For example, the following two statements create + identical \class{type} objects: \begin{verbatim} ->>> import types ->>> x = 'abc' ->>> if type(x) is str: print "It's a string" -... -It's a string ->>> def f(): pass -... ->>> if type(f) is types.FunctionType: print "It's a function" -... -It's a function + >>> class X(object): + ... a = 1 + ... + >>> X = type('X', (object,), dict(a=1)) \end{verbatim} - - The \function{isinstance()} built-in function is recommended for - testing the type of an object. +\versionadded{2.2} \end{funcdesc} \begin{funcdesc}{unichr}{i} From rhettinger at users.sourceforge.net Wed Aug 24 09:07:54 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:07:54 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libfuncs.tex, 1.175.2.8, 1.175.2.9 Message-ID: <20050824070754.C314C1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18080 Modified Files: Tag: release24-maint libfuncs.tex Log Message: SF bug #1100368: Wrong "type()" syntax in docs Docs were missing the name/bases/dict form of type(). (Much of the wording contributed by Steven Bethard.) Index: libfuncs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libfuncs.tex,v retrieving revision 1.175.2.8 retrieving revision 1.175.2.9 diff -u -d -r1.175.2.8 -r1.175.2.9 --- libfuncs.tex 23 Aug 2005 04:35:22 -0000 1.175.2.8 +++ libfuncs.tex 24 Aug 2005 07:07:44 -0000 1.175.2.9 @@ -1019,26 +1019,30 @@ \begin{funcdesc}{type}{object} Return the type of an \var{object}. The return value is a - type\obindex{type} object. The standard module - \module{types}\refstmodindex{types} defines names for all built-in - types that don't already have built-in names. - For instance: + type\obindex{type} object. The \function{isinstance()} built-in + function is recommended for testing the type of an object. + + With three arguments, \function{type} functions as a constructor + as detailed below. +\end{funcdesc} + +\begin{funcdesc}{type}{name, bases, dict} + Return a new type object. This is essentially a dynamic form of the + \keyword{class} statement. The \var{name} string is the class name + and becomes the \member{__name__} attribute; the \var{bases} tuple + itemizes the base classes and becomes the \member{__bases__} + attribute; and the \var{dict} dictionary is the namespace containing + definitions for class body and becomes the \member{__dict__} + attribute. For example, the following two statements create + identical \class{type} objects: \begin{verbatim} ->>> import types ->>> x = 'abc' ->>> if type(x) is str: print "It's a string" -... -It's a string ->>> def f(): pass -... ->>> if type(f) is types.FunctionType: print "It's a function" -... -It's a function + >>> class X(object): + ... a = 1 + ... + >>> X = type('X', (object,), dict(a=1)) \end{verbatim} - - The \function{isinstance()} built-in function is recommended for - testing the type of an object. +\versionadded{2.2} \end{funcdesc} \begin{funcdesc}{unichr}{i} From birkenfeld at users.sourceforge.net Wed Aug 24 09:17:45 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:17:45 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.76, 1.1193.2.77 Message-ID: <20050824071745.15E331E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20590/Misc Modified Files: Tag: release24-maint NEWS Log Message: backport bug [ 728515 ] mmap's resize method resizes the file in win32 but not unix Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.76 retrieving revision 1.1193.2.77 diff -u -d -r1.1193.2.76 -r1.1193.2.77 --- NEWS 24 Aug 2005 06:44:56 -0000 1.1193.2.76 +++ NEWS 24 Aug 2005 07:17:34 -0000 1.1193.2.77 @@ -50,6 +50,9 @@ Extension Modules ----------------- +- Bug #728515: mmap.resize() now resizes the file on Unix as it did + on Windows. + - Bug #1234979: For the argument of thread.Lock.acquire, the Windows implemented treated all integer values except 1 as false. From birkenfeld at users.sourceforge.net Wed Aug 24 09:17:45 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:17:45 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules mmapmodule.c, 2.48, 2.48.4.1 Message-ID: <20050824071745.197651E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20590/Modules Modified Files: Tag: release24-maint mmapmodule.c Log Message: backport bug [ 728515 ] mmap's resize method resizes the file in win32 but not unix Index: mmapmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/mmapmodule.c,v retrieving revision 2.48 retrieving revision 2.48.4.1 diff -u -d -r2.48 -r2.48.4.1 --- mmapmodule.c 19 May 2004 14:39:08 -0000 2.48 +++ mmapmodule.c 24 Aug 2005 07:17:35 -0000 2.48.4.1 @@ -421,6 +421,11 @@ return NULL; #else } else { + if (ftruncate(self->fd, new_size) == -1) { + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } + void *newmap; #ifdef MREMAP_MAYMOVE @@ -907,7 +912,12 @@ if (m_obj == NULL) {return NULL;} m_obj->size = (size_t) map_size; m_obj->pos = (size_t) 0; - m_obj->fd = fd; + m_obj->fd = dup(fd); + if (m_obj->fd == -1) { + Py_DECREF(m_obj); + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } m_obj->data = mmap(NULL, map_size, prot, flags, fd, 0); From birkenfeld at users.sourceforge.net Wed Aug 24 09:17:45 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:17:45 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libmmap.tex, 1.9.4.1, 1.9.4.2 Message-ID: <20050824071745.2246D1E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20590/Doc/lib Modified Files: Tag: release24-maint libmmap.tex Log Message: backport bug [ 728515 ] mmap's resize method resizes the file in win32 but not unix Index: libmmap.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libmmap.tex,v retrieving revision 1.9.4.1 retrieving revision 1.9.4.2 diff -u -d -r1.9.4.1 -r1.9.4.2 --- libmmap.tex 19 Jan 2005 03:42:09 -0000 1.9.4.1 +++ libmmap.tex 24 Aug 2005 07:17:35 -0000 1.9.4.2 @@ -130,6 +130,7 @@ \end{methoddesc} \begin{methoddesc}{resize}{\var{newsize}} + Resizes the map and the underlying file, if any. If the mmap was created with \constant{ACCESS_READ} or \constant{ACCESS_COPY}, resizing the map will throw a \exception{TypeError} exception. \end{methoddesc} From birkenfeld at users.sourceforge.net Wed Aug 24 09:17:45 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:17:45 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_mmap.py, 1.30, 1.30.18.1 Message-ID: <20050824071745.341B51E400F@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20590/Lib/test Modified Files: Tag: release24-maint test_mmap.py Log Message: backport bug [ 728515 ] mmap's resize method resizes the file in win32 but not unix Index: test_mmap.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_mmap.py,v retrieving revision 1.30 retrieving revision 1.30.18.1 diff -u -d -r1.30 -r1.30.18.1 --- test_mmap.py 13 Jan 2003 21:38:45 -0000 1.30 +++ test_mmap.py 24 Aug 2005 07:17:35 -0000 1.30.18.1 @@ -120,6 +120,14 @@ else: verify(0, 'Could seek beyond the new size') + # Check that the underlying file is truncated too + # (bug #728515) + f = open(TESTFN) + f.seek(0, 2) + verify(f.tell() == 512, 'Underlying file not truncated') + f.close() + verify(m.size() == 512, 'New size not reflected in file') + m.close() finally: From birkenfeld at users.sourceforge.net Wed Aug 24 09:17:50 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:17:50 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1340,1.1341 Message-ID: <20050824071750.131091E4028@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20685/Misc Modified Files: NEWS Log Message: bug [ 728515 ] mmap's resize method resizes the file in win32 but not unix Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1340 retrieving revision 1.1341 diff -u -d -r1.1340 -r1.1341 --- NEWS 24 Aug 2005 06:43:09 -0000 1.1340 +++ NEWS 24 Aug 2005 07:17:39 -0000 1.1341 @@ -128,6 +128,9 @@ Extension Modules ----------------- +- Bug #728515: mmap.resize() now resizes the file on Unix as it did + on Windows. + - Patch #1180695: Add nanosecond stat resolution, and st_gen, st_birthtime for FreeBSD. From birkenfeld at users.sourceforge.net Wed Aug 24 09:17:50 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:17:50 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules mmapmodule.c,2.49,2.50 Message-ID: <20050824071750.19A811E4030@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20685/Modules Modified Files: mmapmodule.c Log Message: bug [ 728515 ] mmap's resize method resizes the file in win32 but not unix Index: mmapmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/mmapmodule.c,v retrieving revision 2.49 retrieving revision 2.50 diff -u -d -r2.49 -r2.50 --- mmapmodule.c 3 Mar 2005 11:22:44 -0000 2.49 +++ mmapmodule.c 24 Aug 2005 07:17:39 -0000 2.50 @@ -421,6 +421,11 @@ return NULL; #else } else { + if (ftruncate(self->fd, new_size) == -1) { + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } + void *newmap; #ifdef MREMAP_MAYMOVE @@ -910,7 +915,12 @@ if (m_obj == NULL) {return NULL;} m_obj->size = (size_t) map_size; m_obj->pos = (size_t) 0; - m_obj->fd = fd; + m_obj->fd = dup(fd); + if (m_obj->fd == -1) { + Py_DECREF(m_obj); + PyErr_SetFromErrno(mmap_module_error); + return NULL; + } m_obj->data = mmap(NULL, map_size, prot, flags, fd, 0); From birkenfeld at users.sourceforge.net Wed Aug 24 09:17:50 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:17:50 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_mmap.py,1.32,1.33 Message-ID: <20050824071750.1D6CF1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20685/Lib/test Modified Files: test_mmap.py Log Message: bug [ 728515 ] mmap's resize method resizes the file in win32 but not unix Index: test_mmap.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_mmap.py,v retrieving revision 1.32 retrieving revision 1.33 diff -u -d -r1.32 -r1.33 --- test_mmap.py 28 Mar 2005 01:08:04 -0000 1.32 +++ test_mmap.py 24 Aug 2005 07:17:40 -0000 1.33 @@ -120,6 +120,14 @@ else: verify(0, 'Could seek beyond the new size') + # Check that the underlying file is truncated too + # (bug #728515) + f = open(TESTFN) + f.seek(0, 2) + verify(f.tell() == 512, 'Underlying file not truncated') + f.close() + verify(m.size() == 512, 'New size not reflected in file') + m.close() finally: From birkenfeld at users.sourceforge.net Wed Aug 24 09:17:50 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:17:50 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libmmap.tex,1.11,1.12 Message-ID: <20050824071750.2425F1E4052@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv20685/Doc/lib Modified Files: libmmap.tex Log Message: bug [ 728515 ] mmap's resize method resizes the file in win32 but not unix Index: libmmap.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libmmap.tex,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- libmmap.tex 3 Mar 2005 11:22:41 -0000 1.11 +++ libmmap.tex 24 Aug 2005 07:17:40 -0000 1.12 @@ -132,6 +132,7 @@ \end{methoddesc} \begin{methoddesc}{resize}{\var{newsize}} + Resizes the map and the underlying file, if any. If the mmap was created with \constant{ACCESS_READ} or \constant{ACCESS_COPY}, resizing the map will throw a \exception{TypeError} exception. \end{methoddesc} From birkenfeld at users.sourceforge.net Wed Aug 24 09:27:05 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:27:05 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1341,1.1342 Message-ID: <20050824072705.50A4A1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22611/Misc Modified Files: NEWS Log Message: bug [ 1193849 ] os.path.expanduser documentation wrt. empty $HOME Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1341 retrieving revision 1.1342 diff -u -d -r1.1341 -r1.1342 --- NEWS 24 Aug 2005 07:17:39 -0000 1.1341 +++ NEWS 24 Aug 2005 07:26:55 -0000 1.1342 @@ -456,6 +456,8 @@ Documentation ------------- +- Bug #1193849: Clarify os.path.expanduser() documentation. + - Bug #1243192: re.UNICODE and re.LOCALE affect \d, \D, \s and \S. - Bug #755617: Document the effects of os.chown() on Windows. From birkenfeld at users.sourceforge.net Wed Aug 24 09:27:05 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:27:05 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libposixpath.tex, 1.41, 1.42 Message-ID: <20050824072705.7F43F1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22611/Doc/lib Modified Files: libposixpath.tex Log Message: bug [ 1193849 ] os.path.expanduser documentation wrt. empty $HOME Index: libposixpath.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libposixpath.tex,v retrieving revision 1.41 retrieving revision 1.42 diff -u -d -r1.41 -r1.42 --- libposixpath.tex 22 Dec 2004 05:40:45 -0000 1.41 +++ libposixpath.tex 24 Aug 2005 07:26:55 -0000 1.42 @@ -55,12 +55,20 @@ \end{funcdesc} \begin{funcdesc}{expanduser}{path} -Return the argument with an initial component of \samp{\~} or -\samp{\~\var{user}} replaced by that \var{user}'s home directory. An -initial \samp{\~{}} is replaced by the environment variable -\envvar{HOME}; an initial \samp{\~\var{user}} is looked up in the -password directory through the built-in module -\refmodule{pwd}\refbimodindex{pwd}. If the expansion fails, or if the +On \UNIX, return the argument with an initial component of \samp{\~} or +\samp{\~\var{user}} replaced by that \var{user}'s home directory. +An initial \samp{\~} is replaced by the environment variable +\envvar{HOME} if it is set; otherwise the current user's home directory +is looked up in the password directory through the built-in module +\refmodule{pwd}\refbimodindex{pwd}. +An initial \samp{\~\var{user}} is looked up directly in the +password directory. + +On Windows, only \samp{\~} is supported; it is replaced by the +environment variable \envvar{HOME} or by a combination of +\envvar{HOMEDRIVE} and \envvar{HOMEPATH}. + +If the expansion fails or if the path does not begin with a tilde, the path is returned unchanged. \end{funcdesc} @@ -158,7 +166,7 @@ \begin{funcdesc}{normpath}{path} Normalize a pathname. This collapses redundant separators and -up-level references, e.g. \code{A//B}, \code{A/./B} and +up-level references so that \code{A//B}, \code{A/./B} and \code{A/foo/../B} all become \code{A/B}. It does not normalize the case (use \function{normcase()} for that). On Windows, it converts forward slashes to backward slashes. It should be understood that this may @@ -234,7 +242,7 @@ directory, the argument \var{names} lists the files in the directory (gotten from \code{os.listdir(\var{dirname})}). The \var{visit} function may modify \var{names} to -influence the set of directories visited below \var{dirname}, e.g., to +influence the set of directories visited below \var{dirname}, e.g. to avoid visiting certain parts of the tree. (The object referred to by \var{names} must be modified in place, using \keyword{del} or slice assignment.) From birkenfeld at users.sourceforge.net Wed Aug 24 09:27:10 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:27:10 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.77, 1.1193.2.78 Message-ID: <20050824072710.795F81E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22624/Misc Modified Files: Tag: release24-maint NEWS Log Message: backport bug [ 1193849 ] os.path.expanduser documentation wrt. empty $HOME Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.77 retrieving revision 1.1193.2.78 diff -u -d -r1.1193.2.77 -r1.1193.2.78 --- NEWS 24 Aug 2005 07:17:34 -0000 1.1193.2.77 +++ NEWS 24 Aug 2005 07:27:00 -0000 1.1193.2.78 @@ -120,6 +120,8 @@ Documentation ------------- +- Bug #1193849: Clarify os.path.expanduser() documentation. + - Bug #1243192: re.UNICODE and re.LOCALE affect \d, \D, \s and \S. - Bug #755617: Document the effects of os.chown() on Windows. From birkenfeld at users.sourceforge.net Wed Aug 24 09:27:10 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:27:10 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libposixpath.tex, 1.40.2.1, 1.40.2.2 Message-ID: <20050824072710.A69091E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22624/Doc/lib Modified Files: Tag: release24-maint libposixpath.tex Log Message: backport bug [ 1193849 ] os.path.expanduser documentation wrt. empty $HOME Index: libposixpath.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libposixpath.tex,v retrieving revision 1.40.2.1 retrieving revision 1.40.2.2 diff -u -d -r1.40.2.1 -r1.40.2.2 --- libposixpath.tex 22 Dec 2004 05:41:56 -0000 1.40.2.1 +++ libposixpath.tex 24 Aug 2005 07:27:00 -0000 1.40.2.2 @@ -55,12 +55,20 @@ \end{funcdesc} \begin{funcdesc}{expanduser}{path} -Return the argument with an initial component of \samp{\~} or -\samp{\~\var{user}} replaced by that \var{user}'s home directory. An -initial \samp{\~{}} is replaced by the environment variable -\envvar{HOME}; an initial \samp{\~\var{user}} is looked up in the -password directory through the built-in module -\refmodule{pwd}\refbimodindex{pwd}. If the expansion fails, or if the +On \UNIX, return the argument with an initial component of \samp{\~} or +\samp{\~\var{user}} replaced by that \var{user}'s home directory. +An initial \samp{\~} is replaced by the environment variable +\envvar{HOME} if it is set; otherwise the current user's home directory +is looked up in the password directory through the built-in module +\refmodule{pwd}\refbimodindex{pwd}. +An initial \samp{\~\var{user}} is looked up directly in the +password directory. + +On Windows, only \samp{\~} is supported; it is replaced by the +environment variable \envvar{HOME} or by a combination of +\envvar{HOMEDRIVE} and \envvar{HOMEPATH}. + +If the expansion fails or if the path does not begin with a tilde, the path is returned unchanged. \end{funcdesc} @@ -158,7 +166,7 @@ \begin{funcdesc}{normpath}{path} Normalize a pathname. This collapses redundant separators and -up-level references, e.g. \code{A//B}, \code{A/./B} and +up-level references so that \code{A//B}, \code{A/./B} and \code{A/foo/../B} all become \code{A/B}. It does not normalize the case (use \function{normcase()} for that). On Windows, it converts forward slashes to backward slashes. It should be understood that this may @@ -234,7 +242,7 @@ directory, the argument \var{names} lists the files in the directory (gotten from \code{os.listdir(\var{dirname})}). The \var{visit} function may modify \var{names} to -influence the set of directories visited below \var{dirname}, e.g., to +influence the set of directories visited below \var{dirname}, e.g. to avoid visiting certain parts of the tree. (The object referred to by \var{names} must be modified in place, using \keyword{del} or slice assignment.) From birkenfeld at users.sourceforge.net Wed Aug 24 09:31:39 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:31:39 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libsite.tex, 1.26.4.1, 1.26.4.2 Message-ID: <20050824073139.647C31E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23505/Doc/lib Modified Files: Tag: release24-maint libsite.tex Log Message: backport bug [ 1190204 ] 3.29 site is confusing re site-packages on Windows Index: libsite.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libsite.tex,v retrieving revision 1.26.4.1 retrieving revision 1.26.4.2 diff -u -d -r1.26.4.1 -r1.26.4.2 --- libsite.tex 13 Feb 2005 22:56:40 -0000 1.26.4.1 +++ libsite.tex 24 Aug 2005 07:31:29 -0000 1.26.4.2 @@ -17,8 +17,8 @@ tail part. For the head part, it uses \code{sys.prefix} and \code{sys.exec_prefix}; empty heads are skipped. For the tail part, it uses the empty string (on Windows) or -it uses first \file{lib/python\shortversion/site-packages} and then -\file{lib/site-python} (on \UNIX and Macintosh). For each of the distinct +\file{lib/python\shortversion/site-packages} (on \UNIX{} and Macintosh) +and then \file{lib/site-python}. For each of the distinct head-tail combinations, it sees if it refers to an existing directory, and if so, adds it to \code{sys.path} and also inspects the newly added path for configuration files. From birkenfeld at users.sourceforge.net Wed Aug 24 09:31:39 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:31:39 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.78, 1.1193.2.79 Message-ID: <20050824073139.718661E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23505/Misc Modified Files: Tag: release24-maint NEWS Log Message: backport bug [ 1190204 ] 3.29 site is confusing re site-packages on Windows Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.78 retrieving revision 1.1193.2.79 diff -u -d -r1.1193.2.78 -r1.1193.2.79 --- NEWS 24 Aug 2005 07:27:00 -0000 1.1193.2.78 +++ NEWS 24 Aug 2005 07:31:29 -0000 1.1193.2.79 @@ -120,6 +120,8 @@ Documentation ------------- +- Bug #1190204: Clarify which directories are searched by site.py. + - Bug #1193849: Clarify os.path.expanduser() documentation. - Bug #1243192: re.UNICODE and re.LOCALE affect \d, \D, \s and \S. From birkenfeld at users.sourceforge.net Wed Aug 24 09:31:43 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:31:43 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1342,1.1343 Message-ID: <20050824073143.AF1CC1E4040@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23508/Misc Modified Files: NEWS Log Message: bug [ 1190204 ] 3.29 site is confusing re site-packages on Windows Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1342 retrieving revision 1.1343 diff -u -d -r1.1342 -r1.1343 --- NEWS 24 Aug 2005 07:26:55 -0000 1.1342 +++ NEWS 24 Aug 2005 07:31:33 -0000 1.1343 @@ -456,6 +456,8 @@ Documentation ------------- +- Bug #1190204: Clarify which directories are searched by site.py. + - Bug #1193849: Clarify os.path.expanduser() documentation. - Bug #1243192: re.UNICODE and re.LOCALE affect \d, \D, \s and \S. From birkenfeld at users.sourceforge.net Wed Aug 24 09:31:43 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:31:43 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libsite.tex,1.27,1.28 Message-ID: <20050824073143.D13731E4043@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23508/Doc/lib Modified Files: libsite.tex Log Message: bug [ 1190204 ] 3.29 site is confusing re site-packages on Windows Index: libsite.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libsite.tex,v retrieving revision 1.27 retrieving revision 1.28 diff -u -d -r1.27 -r1.28 --- libsite.tex 13 Feb 2005 22:50:03 -0000 1.27 +++ libsite.tex 24 Aug 2005 07:31:33 -0000 1.28 @@ -17,8 +17,8 @@ tail part. For the head part, it uses \code{sys.prefix} and \code{sys.exec_prefix}; empty heads are skipped. For the tail part, it uses the empty string (on Windows) or -it uses first \file{lib/python\shortversion/site-packages} and then -\file{lib/site-python} (on \UNIX and Macintosh). For each of the distinct +\file{lib/python\shortversion/site-packages} (on \UNIX{} and Macintosh) +and then \file{lib/site-python}. For each of the distinct head-tail combinations, it sees if it refers to an existing directory, and if so, adds it to \code{sys.path} and also inspects the newly added path for configuration files. From birkenfeld at users.sourceforge.net Wed Aug 24 09:36:27 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:36:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1343,1.1344 Message-ID: <20050824073627.1A7F31E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24305/Misc Modified Files: NEWS Log Message: bug [ 1192315 ] 'clear -1' in pdb Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1343 retrieving revision 1.1344 diff -u -d -r1.1343 -r1.1344 --- NEWS 24 Aug 2005 07:31:33 -0000 1.1343 +++ NEWS 24 Aug 2005 07:36:17 -0000 1.1344 @@ -191,6 +191,8 @@ Library ------- +- Bug #1192315: Disallow negative arguments to clear() in pdb. + - Patch #827386: Support absolute source paths in msvccompiler.py. - Patch #1105730: Apply the new implementation of commonprefix in posixpath From birkenfeld at users.sourceforge.net Wed Aug 24 09:36:27 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:36:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib pdb.py,1.73,1.74 Message-ID: <20050824073627.2F8361E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24305/Lib Modified Files: pdb.py Log Message: bug [ 1192315 ] 'clear -1' in pdb Index: pdb.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/pdb.py,v retrieving revision 1.73 retrieving revision 1.74 diff -u -d -r1.73 -r1.74 --- pdb.py 7 Nov 2004 11:35:30 -0000 1.73 +++ pdb.py 24 Aug 2005 07:36:17 -0000 1.74 @@ -450,11 +450,14 @@ return numberlist = arg.split() for i in numberlist: + if not (0 <= i < len(bdb.Breakpoint.bpbynumber)): + print 'No breakpoint numbered', i + continue err = self.clear_bpbynumber(i) if err: print '***', err else: - print 'Deleted breakpoint %s ' % (i,) + print 'Deleted breakpoint', i do_cl = do_clear # 'c' is already an abbreviation for 'continue' def do_where(self, arg): From birkenfeld at users.sourceforge.net Wed Aug 24 09:36:31 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:36:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.79, 1.1193.2.80 Message-ID: <20050824073631.CB4DB1E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24331/Misc Modified Files: Tag: release24-maint NEWS Log Message: backport bug [ 1192315 ] 'clear -1' in pdb Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.79 retrieving revision 1.1193.2.80 diff -u -d -r1.1193.2.79 -r1.1193.2.80 --- NEWS 24 Aug 2005 07:31:29 -0000 1.1193.2.79 +++ NEWS 24 Aug 2005 07:36:21 -0000 1.1193.2.80 @@ -70,6 +70,8 @@ - The sets module can now properly compute s-=s and s^=s as an empty set. +- Bug #1192315: Disallow negative arguments to clear() in pdb. + - Patch #827386: Support absolute source paths in msvccompiler.py. - Fix a problem in Tkinter introduced by SF patch #869468: delete bogus From birkenfeld at users.sourceforge.net Wed Aug 24 09:36:31 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:36:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib pdb.py,1.73,1.73.2.1 Message-ID: <20050824073631.D0EB21E400F@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24331/Lib Modified Files: Tag: release24-maint pdb.py Log Message: backport bug [ 1192315 ] 'clear -1' in pdb Index: pdb.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/pdb.py,v retrieving revision 1.73 retrieving revision 1.73.2.1 diff -u -d -r1.73 -r1.73.2.1 --- pdb.py 7 Nov 2004 11:35:30 -0000 1.73 +++ pdb.py 24 Aug 2005 07:36:21 -0000 1.73.2.1 @@ -450,11 +450,14 @@ return numberlist = arg.split() for i in numberlist: + if not (0 <= i < len(bdb.Breakpoint.bpbynumber)): + print 'No breakpoint numbered', i + continue err = self.clear_bpbynumber(i) if err: print '***', err else: - print 'Deleted breakpoint %s ' % (i,) + print 'Deleted breakpoint', i do_cl = do_clear # 'c' is already an abbreviation for 'continue' def do_where(self, arg): From loewis at users.sourceforge.net Wed Aug 24 09:38:22 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:38:22 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libcodecs.tex,1.35,1.36 Message-ID: <20050824073822.64E441E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24669/Doc/lib Modified Files: libcodecs.tex Log Message: Return complete lines from codec stream readers even if there is an exception in later lines, resulting in correct line numbers for decoding errors in source code. Fixes #1178484. Will backport to 2.4. Index: libcodecs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcodecs.tex,v retrieving revision 1.35 retrieving revision 1.36 diff -u -d -r1.35 -r1.36 --- libcodecs.tex 1 Jan 2005 00:28:34 -0000 1.35 +++ libcodecs.tex 24 Aug 2005 07:38:12 -0000 1.36 @@ -394,7 +394,7 @@ be extended with \function{register_error()}. \end{classdesc} -\begin{methoddesc}{read}{\optional{size\optional{, chars}}} +\begin{methoddesc}{read}{\optional{size\optional{, chars, \optional{firstline}}}} Decodes data from the stream and returns the resulting object. \var{chars} indicates the number of characters to read from the @@ -408,12 +408,16 @@ decode as much as possible. \var{size} is intended to prevent having to decode huge files in one step. + \var{firstline} indicates that it would be sufficient to only return + the first line, if there are decoding errors on later lines. + The method should use a greedy read strategy meaning that it should read as much data as is allowed within the definition of the encoding and the given size, e.g. if optional encoding endings or state markers are available on the stream, these should be read too. \versionchanged[\var{chars} argument added]{2.4} + \versionchanged[\var{firstline} argument added]{2.4.2} \end{methoddesc} \begin{methoddesc}{readline}{\optional{size\optional{, keepends}}} From loewis at users.sourceforge.net Wed Aug 24 09:38:22 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:38:22 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib codecs.py,1.46,1.47 Message-ID: <20050824073822.9C34C1E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24669/Lib Modified Files: codecs.py Log Message: Return complete lines from codec stream readers even if there is an exception in later lines, resulting in correct line numbers for decoding errors in source code. Fixes #1178484. Will backport to 2.4. Index: codecs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/codecs.py,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- codecs.py 20 Jul 2005 22:15:39 -0000 1.46 +++ codecs.py 24 Aug 2005 07:38:12 -0000 1.47 @@ -236,7 +236,7 @@ def decode(self, input, errors='strict'): raise NotImplementedError - def read(self, size=-1, chars=-1): + def read(self, size=-1, chars=-1, firstline=False): """ Decodes data from the stream self.stream and returns the resulting object. @@ -253,6 +253,11 @@ is intended to prevent having to decode huge files in one step. + If firstline is true, and a UnicodeDecodeError happens + after the first line terminator in the input only the first line + will be returned, the rest of the input will be kept until the + next call to read(). + The method should use a greedy read strategy meaning that it should read as much data as is allowed within the definition of the encoding and the given size, e.g. if @@ -275,7 +280,16 @@ newdata = self.stream.read(size) # decode bytes (those remaining from the last call included) data = self.bytebuffer + newdata - newchars, decodedbytes = self.decode(data, self.errors) + try: + newchars, decodedbytes = self.decode(data, self.errors) + except UnicodeDecodeError, exc: + if firstline: + newchars, decodedbytes = self.decode(data[:exc.start], self.errors) + lines = newchars.splitlines(True) + if len(lines)<=1: + raise + else: + raise # keep undecoded bytes until the next call self.bytebuffer = data[decodedbytes:] # put new characters in the character buffer @@ -306,7 +320,7 @@ line = "" # If size is given, we call read() only once while True: - data = self.read(readsize) + data = self.read(readsize, firstline=True) if data: # If we're at a "\r" read one extra character (which might # be a "\n") to get a proper line ending. If the stream is From loewis at users.sourceforge.net Wed Aug 24 09:38:23 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:38:23 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1344,1.1345 Message-ID: <20050824073823.371161E400F@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24669/Misc Modified Files: NEWS Log Message: Return complete lines from codec stream readers even if there is an exception in later lines, resulting in correct line numbers for decoding errors in source code. Fixes #1178484. Will backport to 2.4. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1344 retrieving revision 1.1345 diff -u -d -r1.1344 -r1.1345 --- NEWS 24 Aug 2005 07:36:17 -0000 1.1344 +++ NEWS 24 Aug 2005 07:38:12 -0000 1.1345 @@ -191,6 +191,10 @@ Library ------- +- Bug #1178484: Return complete lines from codec stream readers + even if there is an exception in later lines, resulting in + correct line numbers for decoding errors in source code. + - Bug #1192315: Disallow negative arguments to clear() in pdb. - Patch #827386: Support absolute source paths in msvccompiler.py. From loewis at users.sourceforge.net Wed Aug 24 09:38:46 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:38:46 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.80, 1.1193.2.81 Message-ID: <20050824073846.DA43E1E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24772/Misc Modified Files: Tag: release24-maint NEWS Log Message: Return complete lines from codec stream readers even if there is an exception in later lines, resulting in correct line numbers for decoding errors in source code. Fixes #1178484. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.80 retrieving revision 1.1193.2.81 diff -u -d -r1.1193.2.80 -r1.1193.2.81 --- NEWS 24 Aug 2005 07:36:21 -0000 1.1193.2.80 +++ NEWS 24 Aug 2005 07:38:36 -0000 1.1193.2.81 @@ -66,6 +66,10 @@ Library ------- +- Bug #1178484: Return complete lines from codec stream readers + even if there is an exception in later lines, resulting in + correct line numbers for decoding errors in source code. + - Bug #1266283: "lexists" is now in os.path.__all__. - The sets module can now properly compute s-=s and s^=s as an empty set. From loewis at users.sourceforge.net Wed Aug 24 09:38:46 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:38:46 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libcodecs.tex, 1.34.2.1, 1.34.2.2 Message-ID: <20050824073846.DAAD81E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24772/Doc/lib Modified Files: Tag: release24-maint libcodecs.tex Log Message: Return complete lines from codec stream readers even if there is an exception in later lines, resulting in correct line numbers for decoding errors in source code. Fixes #1178484. Index: libcodecs.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcodecs.tex,v retrieving revision 1.34.2.1 retrieving revision 1.34.2.2 diff -u -d -r1.34.2.1 -r1.34.2.2 --- libcodecs.tex 1 Jan 2005 00:34:53 -0000 1.34.2.1 +++ libcodecs.tex 24 Aug 2005 07:38:36 -0000 1.34.2.2 @@ -394,7 +394,7 @@ be extended with \function{register_error()}. \end{classdesc} -\begin{methoddesc}{read}{\optional{size\optional{, chars}}} +\begin{methoddesc}{read}{\optional{size\optional{, chars, \optional{firstline}}}} Decodes data from the stream and returns the resulting object. \var{chars} indicates the number of characters to read from the @@ -408,12 +408,16 @@ decode as much as possible. \var{size} is intended to prevent having to decode huge files in one step. + \var{firstline} indicates that it would be sufficient to only return + the first line, if there are decoding errors on later lines. + The method should use a greedy read strategy meaning that it should read as much data as is allowed within the definition of the encoding and the given size, e.g. if optional encoding endings or state markers are available on the stream, these should be read too. \versionchanged[\var{chars} argument added]{2.4} + \versionchanged[\var{firstline} argument added]{2.4.2} \end{methoddesc} \begin{methoddesc}{readline}{\optional{size\optional{, keepends}}} From loewis at users.sourceforge.net Wed Aug 24 09:38:46 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 09:38:46 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib codecs.py,1.35.2.8,1.35.2.9 Message-ID: <20050824073846.00B111E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24772/Lib Modified Files: Tag: release24-maint codecs.py Log Message: Return complete lines from codec stream readers even if there is an exception in later lines, resulting in correct line numbers for decoding errors in source code. Fixes #1178484. Index: codecs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/codecs.py,v retrieving revision 1.35.2.8 retrieving revision 1.35.2.9 diff -u -d -r1.35.2.8 -r1.35.2.9 --- codecs.py 20 Jul 2005 22:52:08 -0000 1.35.2.8 +++ codecs.py 24 Aug 2005 07:38:36 -0000 1.35.2.9 @@ -236,7 +236,7 @@ def decode(self, input, errors='strict'): raise NotImplementedError - def read(self, size=-1, chars=-1): + def read(self, size=-1, chars=-1, firstline=False): """ Decodes data from the stream self.stream and returns the resulting object. @@ -253,6 +253,11 @@ is intended to prevent having to decode huge files in one step. + If firstline is true, and a UnicodeDecodeError happens + after the first line terminator in the input only the first line + will be returned, the rest of the input will be kept until the + next call to read(). + The method should use a greedy read strategy meaning that it should read as much data as is allowed within the definition of the encoding and the given size, e.g. if @@ -275,7 +280,16 @@ newdata = self.stream.read(size) # decode bytes (those remaining from the last call included) data = self.bytebuffer + newdata - newchars, decodedbytes = self.decode(data, self.errors) + try: + newchars, decodedbytes = self.decode(data, self.errors) + except UnicodeDecodeError, exc: + if firstline: + newchars, decodedbytes = self.decode(data[:exc.start], self.errors) + lines = newchars.splitlines(True) + if len(lines)<=1: + raise + else: + raise # keep undecoded bytes until the next call self.bytebuffer = data[decodedbytes:] # put new characters in the character buffer @@ -306,7 +320,7 @@ line = "" # If size is given, we call read() only once while True: - data = self.read(readsize) + data = self.read(readsize, firstline=True) if data: # If we're at a "\r" read one extra character (which might # be a "\n") to get a proper line ending. If the stream is From loewis at users.sourceforge.net Wed Aug 24 10:39:34 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 10:39:34 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1345,1.1346 Message-ID: <20050824083934.ADC221E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3014/Misc Modified Files: NEWS Log Message: Forward UnicodeDecodeError into SyntaxError for source encoding errors. Will backport to 2.4. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1345 retrieving revision 1.1346 diff -u -d -r1.1345 -r1.1346 --- NEWS 24 Aug 2005 07:38:12 -0000 1.1345 +++ NEWS 24 Aug 2005 08:39:24 -0000 1.1346 @@ -12,6 +12,8 @@ Core and builtins ----------------- +- Forward UnicodeDecodeError into SyntaxError for source encoding errors. + - SF bug #900092: When tracing (e.g. for hotshot), restore 'return' events for exceptions that cause a function to exit. From loewis at users.sourceforge.net Wed Aug 24 10:39:34 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 10:39:34 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python pythonrun.c,2.215,2.216 Message-ID: <20050824083934.BC2E21E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3014/Python Modified Files: pythonrun.c Log Message: Forward UnicodeDecodeError into SyntaxError for source encoding errors. Will backport to 2.4. Index: pythonrun.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pythonrun.c,v retrieving revision 2.215 retrieving revision 2.216 diff -u -d -r2.215 -r2.216 --- pythonrun.c 1 Aug 2005 21:39:29 -0000 2.215 +++ pythonrun.c 24 Aug 2005 08:39:24 -0000 2.216 @@ -1474,18 +1474,20 @@ errtype = PyExc_IndentationError; msg = "too many levels of indentation"; break; - case E_DECODE: { /* XXX */ - PyThreadState* tstate = PyThreadState_GET(); - PyObject* value = tstate->curexc_value; + case E_DECODE: { + PyObject *type, *value, *tb; + PyErr_Fetch(&type, &value, &tb); if (value != NULL) { - u = PyObject_Repr(value); + u = PyObject_Str(value); if (u != NULL) { msg = PyString_AsString(u); - break; } } if (msg == NULL) msg = "unknown decode error"; + Py_DECREF(type); + Py_DECREF(value); + Py_DECREF(tb); break; } case E_LINECONT: From loewis at users.sourceforge.net Wed Aug 24 10:39:57 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 10:39:57 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.81, 1.1193.2.82 Message-ID: <20050824083957.205DB1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3103/Misc Modified Files: Tag: release24-maint NEWS Log Message: Forward UnicodeDecodeError into SyntaxError for source encoding errors. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.81 retrieving revision 1.1193.2.82 diff -u -d -r1.1193.2.81 -r1.1193.2.82 --- NEWS 24 Aug 2005 07:38:36 -0000 1.1193.2.81 +++ NEWS 24 Aug 2005 08:39:46 -0000 1.1193.2.82 @@ -12,6 +12,8 @@ Core and builtins ----------------- +- Forward UnicodeDecodeError into SyntaxError for source encoding errors. + - SF bug #900092: When tracing (e.g. for hotshot), restore 'return' events for exceptions that cause a function to exit. From loewis at users.sourceforge.net Wed Aug 24 10:39:57 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 10:39:57 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python pythonrun.c, 2.211.2.1, 2.211.2.2 Message-ID: <20050824083957.4BB191E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3103/Python Modified Files: Tag: release24-maint pythonrun.c Log Message: Forward UnicodeDecodeError into SyntaxError for source encoding errors. Index: pythonrun.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/pythonrun.c,v retrieving revision 2.211.2.1 retrieving revision 2.211.2.2 diff -u -d -r2.211.2.1 -r2.211.2.2 --- pythonrun.c 29 Mar 2005 12:32:50 -0000 2.211.2.1 +++ pythonrun.c 24 Aug 2005 08:39:46 -0000 2.211.2.2 @@ -1471,18 +1471,20 @@ errtype = PyExc_IndentationError; msg = "too many levels of indentation"; break; - case E_DECODE: { /* XXX */ - PyThreadState* tstate = PyThreadState_GET(); - PyObject* value = tstate->curexc_value; + case E_DECODE: { + PyObject *type, *value, *tb; + PyErr_Fetch(&type, &value, &tb); if (value != NULL) { - u = PyObject_Repr(value); + u = PyObject_Str(value); if (u != NULL) { msg = PyString_AsString(u); - break; } } if (msg == NULL) msg = "unknown decode error"; + Py_DECREF(type); + Py_DECREF(value); + Py_DECREF(tb); break; } default: From birkenfeld at users.sourceforge.net Wed Aug 24 11:02:40 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 11:02:40 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_generators.py, 1.46, 1.47 Message-ID: <20050824090240.63F3D1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9148/Lib/test Modified Files: test_generators.py Log Message: [ 1113421 ] New tutorial tests in test_generators.py Index: test_generators.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_generators.py,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- test_generators.py 7 Aug 2005 03:04:58 -0000 1.46 +++ test_generators.py 24 Aug 2005 09:02:29 -0000 1.47 @@ -649,6 +649,84 @@ >>> firstn(iter(fib), 17) [1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584] >>> fib.close() + + +Running after your tail with itertools.tee (new in version 2.4) + +The algorithms "m235" (Hamming) and Fibonacci presented above are both +examples of a whole family of FP (functional programming) algorithms +where a function produces and returns a list while the production algorithm +suppose the list as already produced by recursively calling itself. +For these algorithms to work, they must: + +- produce at least a first element without presupposing the existence of + the rest of the list +- produce their elements in a lazy manner + +To work efficiently, the beginning of the list must not be recomputed over +and over again. This is ensured in most FP languages as a built-in feature. +In python, we have to explicitly maintain a list of already computed results +and abandon genuine recursivity. + +This is what had been attempted above with the LazyList class. One problem +with that class is that it keeps a list of all of the generated results and +therefore continually grows. This partially defeats the goal of the generator +concept, viz. produce the results only as needed instead of producing them +all and thereby wasting memory. + +Thanks to itertools.tee, it is now clear "how to get the internal uses of +m235 to share a single generator". + +>>> from itertools import tee +>>> def m235(): +... def _m235(): +... yield 1 +... for n in merge(times(2, m2), +... merge(times(3, m3), +... times(5, m5))): +... yield n +... m2, m3, m5, mRes = tee(_m235(), 4) +... return mRes + +>>> it = m235() +>>> for i in range(5): +... print firstn(it, 15) +[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24] +[25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80] +[81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192] +[200, 216, 225, 240, 243, 250, 256, 270, 288, 300, 320, 324, 360, 375, 384] +[400, 405, 432, 450, 480, 486, 500, 512, 540, 576, 600, 625, 640, 648, 675] + +The "tee" function does just what we want. It internally keeps a generated +result for as long as it has not been "consumed" from all of the duplicated +iterators, whereupon it is deleted. You can therefore print the hamming +sequence during hours without increasing memory usage, or very little. + +The beauty of it is that recursive running after their tail FP algorithms +are quite straightforwardly expressed with this Python idiom. + + +Ye olde Fibonacci generator, tee style. + +>>> def fib(): +... +... def _isum(g, h): +... while 1: +... yield g.next() + h.next() +... +... def _fib(): +... yield 1 +... yield 2 +... fibTail.next() # throw first away +... for res in _isum(fibHead, fibTail): +... yield res +... +... fibHead, fibTail, fibRes = tee(_fib(), 3) +... return fibRes + +>>> firstn(fib(), 17) +[1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584] + """ # syntax_tests mostly provokes SyntaxErrors. Also fiddling with #if 0 From birkenfeld at users.sourceforge.net Wed Aug 24 11:09:08 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 11:09:08 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_richcmp.py, 1.10, 1.11 seq_tests.py, 1.4, 1.5 Message-ID: <20050824090908.2B7FA1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11448 Modified Files: test_richcmp.py seq_tests.py Log Message: patch [ 1141428 ] more __contains__ tests Index: test_richcmp.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_richcmp.py,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- test_richcmp.py 28 Oct 2003 12:05:47 -0000 1.10 +++ test_richcmp.py 24 Aug 2005 09:08:57 -0000 1.11 @@ -259,8 +259,8 @@ def test_dicts(self): # Verify that __eq__ and __ne__ work for dicts even if the keys and - # values don't support anything other than __eq__ and __ne__. Complex - # numbers are a fine example of that. + # values don't support anything other than __eq__ and __ne__ (and + # __hash__). Complex numbers are a fine example of that. import random imag1a = {} for i in range(50): Index: seq_tests.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/seq_tests.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- seq_tests.py 22 Mar 2005 22:43:27 -0000 1.4 +++ seq_tests.py 24 Aug 2005 09:08:57 -0000 1.5 @@ -207,6 +207,33 @@ self.assertRaises(TypeError, u.__contains__) + def test_contains_fake(self): + class AllEq: + # Sequences must use rich comparison against each item + # (unless "is" is true, or an earlier item answered) + # So instances of AllEq must be found in all non-empty sequences. + def __eq__(self, other): + return True + def __hash__(self): + raise NotImplemented + self.assert_(AllEq() not in self.type2test([])) + self.assert_(AllEq() in self.type2test([1])) + + def test_contains_order(self): + # Sequences must test in-order. If a rich comparison has side + # effects, these will be visible to tests against later members. + # In this test, the "side effect" is a short-circuiting raise. + class DoNotTestEq(Exception): + pass + class StopCompares: + def __eq__(self, other): + raise DoNotTestEq + + checkfirst = self.type2test([1, StopCompares()]) + self.assert_(1 in checkfirst) + checklast = self.type2test([StopCompares(), 1]) + self.assertRaises(DoNotTestEq, checklast.__contains__, 1) + def test_len(self): self.assertEqual(len(self.type2test()), 0) self.assertEqual(len(self.type2test([])), 0) From rhettinger at users.sourceforge.net Wed Aug 24 14:13:33 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Wed, 24 Aug 2005 14:13:33 +0200 (CEST) Subject: [Python-checkins] python/dist/src/PCbuild pythoncore.vcproj, 1.28, 1.29 Message-ID: <20050824121333.B43631E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/PCbuild In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16077 Modified Files: pythoncore.vcproj Log Message: Correct names of sha modules. Index: pythoncore.vcproj =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/pythoncore.vcproj,v retrieving revision 1.28 retrieving revision 1.29 diff -u -d -r1.28 -r1.29 --- pythoncore.vcproj 24 Aug 2005 00:28:21 -0000 1.28 +++ pythoncore.vcproj 24 Aug 2005 12:13:23 -0000 1.29 @@ -2764,7 +2764,7 @@ + RelativePath="..\Modules\sha256module.c"> + RelativePath="..\Modules\sha512module.c"> Update of /cvsroot/python/python/dist/src/Lib/distutils In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19752/Lib/distutils Modified Files: dir_util.py Log Message: Patch #1167716: Support Unicode filenames in mkpath. Fixes #1121494. Will backport to 2.4. Index: dir_util.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/dir_util.py,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- dir_util.py 10 Nov 2004 22:23:14 -0000 1.15 +++ dir_util.py 24 Aug 2005 14:55:22 -0000 1.16 @@ -31,7 +31,7 @@ global _path_created # Detect a common bug -- name is None - if type(name) is not StringType: + if not isinstance(name, StringTypes): raise DistutilsInternalError, \ "mkpath: 'name' must be a string (got %r)" % (name,) From loewis at users.sourceforge.net Wed Aug 24 16:55:32 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 16:55:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1346,1.1347 Message-ID: <20050824145532.99F5E1E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19752/Misc Modified Files: NEWS Log Message: Patch #1167716: Support Unicode filenames in mkpath. Fixes #1121494. Will backport to 2.4. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1346 retrieving revision 1.1347 diff -u -d -r1.1346 -r1.1347 --- NEWS 24 Aug 2005 08:39:24 -0000 1.1346 +++ NEWS 24 Aug 2005 14:55:21 -0000 1.1347 @@ -193,6 +193,8 @@ Library ------- +- Bug #1121494: distutils.dir_utils.mkpath now accepts Unicode strings. + - Bug #1178484: Return complete lines from codec stream readers even if there is an exception in later lines, resulting in correct line numbers for decoding errors in source code. From loewis at users.sourceforge.net Wed Aug 24 16:55:53 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 16:55:53 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/distutils dir_util.py, 1.15, 1.15.2.1 Message-ID: <20050824145553.4B6F61E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/distutils In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19638/Lib/distutils Modified Files: Tag: release24-maint dir_util.py Log Message: Patch #1167716: Support Unicode filenames in mkpath. Fixes #1121494. Index: dir_util.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/dir_util.py,v retrieving revision 1.15 retrieving revision 1.15.2.1 diff -u -d -r1.15 -r1.15.2.1 --- dir_util.py 10 Nov 2004 22:23:14 -0000 1.15 +++ dir_util.py 24 Aug 2005 14:55:42 -0000 1.15.2.1 @@ -31,7 +31,7 @@ global _path_created # Detect a common bug -- name is None - if type(name) is not StringType: + if not isinstance(name, StringTypes): raise DistutilsInternalError, \ "mkpath: 'name' must be a string (got %r)" % (name,) From loewis at users.sourceforge.net Wed Aug 24 16:55:53 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Wed, 24 Aug 2005 16:55:53 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.82, 1.1193.2.83 Message-ID: <20050824145553.637681E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19638/Misc Modified Files: Tag: release24-maint NEWS Log Message: Patch #1167716: Support Unicode filenames in mkpath. Fixes #1121494. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.82 retrieving revision 1.1193.2.83 diff -u -d -r1.1193.2.82 -r1.1193.2.83 --- NEWS 24 Aug 2005 08:39:46 -0000 1.1193.2.82 +++ NEWS 24 Aug 2005 14:55:42 -0000 1.1193.2.83 @@ -68,6 +68,8 @@ Library ------- +- Bug #1121494: distutils.dir_utils.mkpath now accepts Unicode strings. + - Bug #1178484: Return complete lines from codec stream readers even if there is an exception in later lines, resulting in correct line numbers for decoding errors in source code. From birkenfeld at users.sourceforge.net Wed Aug 24 20:28:53 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 20:28:53 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Tools/scripts pysource.py, NONE, 1.1 findnocoding.py, NONE, 1.1 Message-ID: <20050824182853.095071E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Tools/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6928 Added Files: pysource.py findnocoding.py Log Message: Patch [ 784089 ] A program to scan python files and list those require coding --- NEW FILE: pysource.py --- #!/usr/bin/env python """\ List python source files. There are three functions to check whether a file is a Python source, listed here with increasing complexity: - has_python_ext() checks whether a file name ends in '.py[w]'. - look_like_python() checks whether the file is not binary and either has the '.py[w]' extension or the first line contains the word 'python'. - can_be_compiled() checks whether the file can be compiled by compile(). The file also must be of appropriate size - not bigger than a megabyte. walk_python_files() recursively lists all Python files under the given directories. """ __author__ = "Oleg Broytmann, Reinhold Birkenfeld" __all__ = ["has_python_ext", "looks_like_python", "can_be_compiled", "walk_python_files"] import sys, os, re binary_re = re.compile('[\x00-\x08\x0E-\x1F\x7F]') debug = False def print_debug(msg): if debug: print msg def _open(fullpath): try: size = os.stat(fullpath).st_size except OSError, err: # Permission denied - ignore the file print_debug("%s: permission denied: %s" % (fullpath, err)) return None if size > 1024*1024: # too big print_debug("%s: the file is too big: %d bytes" % (fullpath, size)) return None try: return open(fullpath, 'rU') except IOError, err: # Access denied, or a special file - ignore it print_debug("%s: access denied: %s" % (fullpath, err)) return None def has_python_ext(fullpath): return fullpath.endswith(".py") or fullpath.endswith(".pyw") def looks_like_python(fullpath): infile = _open(fullpath) if infile is None: return False line = infile.readline() infile.close() if binary_re.search(line): # file appears to be binary print_debug("%s: appears to be binary" % fullpath) return False if fullpath.endswith(".py") or fullpath.endswith(".pyw"): return True elif "python" in line: # disguised Python script (e.g. CGI) return True return False def can_be_compiled(fullpath): infile = _open(fullpath) if infile is None: return False code = infile.read() infile.close() try: compile(code, fullpath, "exec") except Exception, err: print_debug("%s: cannot compile: %s" % (fullpath, err)) return False return True def walk_python_files(paths, is_python=looks_like_python, exclude_dirs=None): """\ Recursively yield all Python source files below the given paths. paths: a list of files and/or directories to be checked. is_python: a function that takes a file name and checks whether it is a Python source file exclude_dirs: a list of directory base names that should be excluded in the search """ if exclude_dirs is None: exclude_dirs=[] for path in paths: print_debug("testing: %s" % path) if os.path.isfile(path): if is_python(path): yield path elif os.path.isdir(path): print_debug(" it is a directory") for dirpath, dirnames, filenames in os.walk(path): for exclude in exclude_dirs: if exclude in dirnames: dirnames.remove(exclude) for filename in filenames: fullpath = os.path.join(dirpath, filename) print_debug("testing: %s" % fullpath) if is_python(fullpath): yield fullpath else: print_debug(" unknown type") if __name__ == "__main__": # Two simple examples/tests for fullpath in walk_python_files(['.']): print fullpath print "----------" for fullpath in walk_python_files(['.'], is_python=can_be_compiled): print fullpath --- NEW FILE: findnocoding.py --- #!/usr/bin/env python """List all those Python files that require a coding directive Usage: nocoding.py dir1 [dir2...] """ __author__ = "Oleg Broytmann, Reinhold Birkenfeld" import sys, os, re, getopt # our pysource module finds Python source files try: import pysource except: # emulate the module with a simple os.walk class pysource: has_python_ext = looks_like_python = can_be_compiled = None def walk_python_files(self, paths, *args, **kwargs): for path in paths: if os.path.isfile(path): yield path.endswith(".py") elif os.path.isdir(path): for root, dirs, files in os.walk(path): for filename in files: if filename.endswith(".py"): yield os.path.join(root, filename) pysource = pysource() print >>sys.stderr, ("The pysource module is not available; " "no sophisticated Python source file search will be done.") decl_re = re.compile(r"coding[=:]\s*([-\w.]+)") def get_declaration(line): match = decl_re.search(line) if match: return match.group(1) return '' def has_correct_encoding(text, codec): try: unicode(text, codec) except UnicodeDecodeError: return False else: return True def needs_declaration(fullpath): try: infile = open(fullpath, 'rU') except IOError: # Oops, the file was removed - ignore it return None line1 = infile.readline() line2 = infile.readline() if get_declaration(line1) or get_declaration(line2): # the file does have an encoding declaration, so trust it infile.close() return False # check the whole file for non-ASCII characters rest = infile.read() infile.close() if has_correct_encoding(line1+line2+rest, "ascii"): return False return True usage = """Usage: %s [-cd] paths... -c: recognize Python source files trying to compile them -d: debug output""" % sys.argv[0] try: opts, args = getopt.getopt(sys.argv[1:], 'cd') except getopt.error, msg: print >>sys.stderr, msg print >>sys.stderr, usage sys.exit(1) is_python = pysource.looks_like_python debug = False for o, a in opts: if o == '-c': is_python = pysource.can_be_compiled elif o == '-d': debug = True if not args: print >>sys.stderr, usage sys.exit(1) for fullpath in pysource.walk_python_files(args, is_python): if debug: print "Testing for coding: %s" % fullpath result = needs_declaration(fullpath) if result: print fullpath From birkenfeld at users.sourceforge.net Wed Aug 24 20:32:42 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 20:32:42 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1347,1.1348 Message-ID: <20050824183242.5A7B61E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7884/Misc Modified Files: NEWS Log Message: Patch [ 784089 ] A program to scan python files and list those require coding Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1347 retrieving revision 1.1348 diff -u -d -r1.1347 -r1.1348 --- NEWS 24 Aug 2005 14:55:21 -0000 1.1347 +++ NEWS 24 Aug 2005 18:32:30 -0000 1.1348 @@ -502,6 +502,11 @@ Tools/Demos ----------- +- Added two new files to Tools/scripts: pysource.py, which recursively + finds Python source files, and findnocoding.py, which finds Python + source files that need an encoding declaration. + Patch #784089, credits to Oleg Broytmann. + - Bug #1072853: pindent.py used an uninitialized variable. - Patch #1177597: Correct Complex.__init__. From birkenfeld at users.sourceforge.net Wed Aug 24 20:46:49 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 20:46:49 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1348,1.1349 Message-ID: <20050824184649.3862F1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11387/Misc Modified Files: NEWS Log Message: Patch [ 1062060 ] fix for 1016880 urllib.urlretrieve silently truncates dwnld Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1348 retrieving revision 1.1349 diff -u -d -r1.1348 -r1.1349 --- NEWS 24 Aug 2005 18:32:30 -0000 1.1348 +++ NEWS 24 Aug 2005 18:46:38 -0000 1.1349 @@ -193,6 +193,10 @@ Library ------- +- Patch #1062060: urllib.urlretrieve() now raises a new exception, named + ContentTooShortException, when the actually downloaded size does not + match the Content-Length header. + - Bug #1121494: distutils.dir_utils.mkpath now accepts Unicode strings. - Bug #1178484: Return complete lines from codec stream readers From birkenfeld at users.sourceforge.net Wed Aug 24 20:46:49 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 20:46:49 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib urllib.py,1.166,1.167 Message-ID: <20050824184649.414521E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11387/Lib Modified Files: urllib.py Log Message: Patch [ 1062060 ] fix for 1016880 urllib.urlretrieve silently truncates dwnld Index: urllib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib.py,v retrieving revision 1.166 retrieving revision 1.167 diff -u -d -r1.166 -r1.167 --- urllib.py 31 Dec 2004 19:15:26 -0000 1.166 +++ urllib.py 24 Aug 2005 18:46:39 -0000 1.167 @@ -86,6 +86,11 @@ if _urlopener: _urlopener.cleanup() +# exception raised when downloaded size does not match content-length +class ContentTooShortError(IOError): + def __init__(self, message, content): + IOError.__init__(self, message) + self.content = content ftpcache = {} class URLopener: @@ -228,24 +233,33 @@ self.tempcache[url] = result bs = 1024*8 size = -1 + read = 0 blocknum = 1 if reporthook: if "content-length" in headers: size = int(headers["Content-Length"]) reporthook(0, bs, size) block = fp.read(bs) + read += len(block) if reporthook: reporthook(1, bs, size) while block: tfp.write(block) block = fp.read(bs) - blocknum = blocknum + 1 + read += len(block) + blocknum += 1 if reporthook: reporthook(blocknum, bs, size) fp.close() tfp.close() del fp del tfp + + # raise exception if actual size does not match content-length header + if size >= 0 and read < size: + raise ContentTooShortError("retrieval incomplete: got only %i out " + "of %i bytes" % (read, size), result) + return result # Each method named open_ knows how to open that type of URL From birkenfeld at users.sourceforge.net Wed Aug 24 20:46:49 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 20:46:49 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib liburllib.tex,1.57,1.58 Message-ID: <20050824184649.81B381E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11387/Doc/lib Modified Files: liburllib.tex Log Message: Patch [ 1062060 ] fix for 1016880 urllib.urlretrieve silently truncates dwnld Index: liburllib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liburllib.tex,v retrieving revision 1.57 retrieving revision 1.58 diff -u -d -r1.57 -r1.58 --- liburllib.tex 1 Jun 2005 15:26:24 -0000 1.57 +++ liburllib.tex 24 Aug 2005 18:46:39 -0000 1.58 @@ -142,6 +142,25 @@ (normally the request type is \code{GET}). The \var{data} argument must in standard \mimetype{application/x-www-form-urlencoded} format; see the \function{urlencode()} function below. + +\versionchanged[ +\function{urlretrieve()} will raise \exception{ContentTooShortError} +when it detects that the amount of data available +was less than the expected amount (which is the size reported by a +\var{Content-Length} header). This can occur, for example, when the +download is interrupted. + +The \var{Content-Length} is treated as a lower bound: if there's more data +to read, urlretrieve reads more data, but if less data is available, +it raises the exception. + +You can still retrieve the downloaded data in this case, it is stored +in the \member{content} attribute of the exception instance. + +If no \var{Content-Length} header was supplied, urlretrieve can +not check the size of the data it has downloaded, and just returns it. +In this case you just have to assume that the download was successful]{2.5} + \end{funcdesc} \begin{datadesc}{_urlopener} @@ -283,6 +302,15 @@ if needed.} \end{classdesc} +\begin{excclassdesc}{ContentTooShortError}{msg\optional{, content}} +This exception is raised when the \function{urlretrieve()} function +detects that the amount of the downloaded data is less than the +expected amount (given by the \var{Content-Length} header). The +\member{content} attribute stores the downloaded (and supposedly +truncated) data. +\versionadded{2.5} +\end{excclassdesc} + Restrictions: \begin{itemize} @@ -317,7 +345,7 @@ \item The data returned by \function{urlopen()} or \function{urlretrieve()} is the raw data returned by the server. This may be binary data -(e.g. an image), plain text or (for example) HTML\index{HTML}. The +(such as an image), plain text or (for example) HTML\index{HTML}. The HTTP\indexii{HTTP}{protocol} protocol provides type information in the reply header, which can be inspected by looking at the \mailheader{Content-Type} header. For the From birkenfeld at users.sourceforge.net Wed Aug 24 22:29:43 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 22:29:43 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib urllib2.py,1.84,1.85 Message-ID: <20050824202943.045701E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25148/Lib Modified Files: urllib2.py Log Message: Bug 1016563: Bug in urllib2 proxy auth Index: urllib2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib2.py,v retrieving revision 1.84 retrieving revision 1.85 diff -u -d -r1.84 -r1.85 --- urllib2.py 17 Jul 2005 23:16:17 -0000 1.84 +++ urllib2.py 24 Aug 2005 20:29:32 -0000 1.85 @@ -585,7 +585,7 @@ if ':' in user_pass: user, password = user_pass.split(':', 1) user_pass = base64.encodestring('%s:%s' % (unquote(user), - unquote(password))) + unquote(password))).strip() req.add_header('Proxy-authorization', 'Basic ' + user_pass) host = unquote(host) req.set_proxy(host, type) From birkenfeld at users.sourceforge.net Wed Aug 24 22:30:48 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 22:30:48 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib urllib2.py, 1.77.2.1, 1.77.2.2 Message-ID: <20050824203048.79CA31E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25953/Lib Modified Files: Tag: release24-maint urllib2.py Log Message: Backport bug #1016563: Bug in urllib2 proxy auth Index: urllib2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib2.py,v retrieving revision 1.77.2.1 retrieving revision 1.77.2.2 diff -u -d -r1.77.2.1 -r1.77.2.2 --- urllib2.py 9 Jan 2005 05:53:27 -0000 1.77.2.1 +++ urllib2.py 24 Aug 2005 20:30:35 -0000 1.77.2.2 @@ -582,7 +582,7 @@ if ':' in user_pass: user, password = user_pass.split(':', 1) user_pass = base64.encodestring('%s:%s' % (unquote(user), - unquote(password))) + unquote(password))).strip() req.add_header('Proxy-authorization', 'Basic ' + user_pass) host = unquote(host) req.set_proxy(host, type) From birkenfeld at users.sourceforge.net Wed Aug 24 23:42:24 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Wed, 24 Aug 2005 23:42:24 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Tools/scripts README,1.15,1.16 Message-ID: <20050824214224.56FD01E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Tools/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13125/Tools/scripts Modified Files: README Log Message: Add findnocoding.py and pysource.py. Index: README =================================================================== RCS file: /cvsroot/python/python/dist/src/Tools/scripts/README,v retrieving revision 1.15 retrieving revision 1.16 diff -u -d -r1.15 -r1.16 --- README 27 Jan 2004 14:47:23 -0000 1.15 +++ README 24 Aug 2005 21:42:14 -0000 1.16 @@ -20,6 +20,7 @@ eptags.py Create Emacs TAGS file for Python modules finddiv.py A grep-like tool that looks for division operators. findlinksto.py Recursively find symbolic links to a given path prefix +findnocoding.py Find source files which need an encoding declaration fixcid.py Massive identifier substitution on C source files fixdiv.py Tool to fix division operators. fixheader.py Add some cpp magic to a C include file @@ -51,6 +52,7 @@ pindent.py Indent Python code, giving block-closing comments ptags.py Create vi tags file for Python modules pydoc Python documentation browser. +pysource.py Find Python source files redemo.py Basic regular expression demostration facility reindent.py Change .py files to use 4-space indents. rgrep.py Reverse grep through a file (useful for big logfiles) From birkenfeld at users.sourceforge.net Thu Aug 25 00:20:43 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 00:20:43 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_urllib2.py, 1.21, 1.22 Message-ID: <20050824222043.2B5131E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24098/Lib/test Modified Files: test_urllib2.py Log Message: Bug #735248: Fix urllib2.parse_http_list. Index: test_urllib2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_urllib2.py,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- test_urllib2.py 17 Jul 2005 23:16:18 -0000 1.21 +++ test_urllib2.py 24 Aug 2005 22:20:32 -0000 1.22 @@ -45,6 +45,14 @@ # test the new-in-2.5 httpresponses dictionary self.assertEquals(urllib2.httpresponses[404], "Not Found") + def test_parse_http_list(self): + tests = [('a,b,c', ['a', 'b', 'c']), + ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']), + ('a, b, "c", "d", "e,f", g, h', ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']), + ('a="b\\"c", d="e\\,f", g="h\\\\i"', ['a="b"c"', 'd="e,f"', 'g="h\\i"'])] + for string, list in tests: + self.assertEquals(urllib2.parse_http_list(string), list) + class MockOpener: addheaders = [] From birkenfeld at users.sourceforge.net Thu Aug 25 00:20:43 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 00:20:43 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib urllib2.py,1.85,1.86 Message-ID: <20050824222043.322701E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24098/Lib Modified Files: urllib2.py Log Message: Bug #735248: Fix urllib2.parse_http_list. Index: urllib2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib2.py,v retrieving revision 1.85 retrieving revision 1.86 diff -u -d -r1.85 -r1.86 --- urllib2.py 24 Aug 2005 20:29:32 -0000 1.85 +++ urllib2.py 24 Aug 2005 22:20:32 -0000 1.86 @@ -1069,49 +1069,46 @@ def parse_http_list(s): """Parse lists as described by RFC 2068 Section 2. - + In particular, parse comma-separated lists where the elements of the list may include quoted-strings. A quoted-string could - contain a comma. + contain a comma. A non-quoted string could have quotes in the + middle. Neither commas nor quotes count if they are escaped. + Only double-quotes count, not single-quotes. """ - # XXX this function could probably use more testing + res = [] + part = '' - list = [] - end = len(s) - i = 0 - inquote = 0 - start = 0 - while i < end: - cur = s[i:] - c = cur.find(',') - q = cur.find('"') - if c == -1: - list.append(s[start:]) - break - if q == -1: - if inquote: - raise ValueError, "unbalanced quotes" - else: - list.append(s[start:i+c]) - i = i + c + 1 + escape = quote = False + for cur in s: + if escape: + part += cur + escape = False + continue + if quote: + if cur == '\\': + escape = True continue - if inquote: - if q < c: - list.append(s[start:i+c]) - i = i + c + 1 - start = i - inquote = 0 - else: - i = i + q - else: - if c < q: - list.append(s[start:i+c]) - i = i + c + 1 - start = i - else: - inquote = 1 - i = i + q + 1 - return map(lambda x: x.strip(), list) + elif cur == '"': + quote = False + part += cur + continue + + if cur == ',': + res.append(part) + part = '' + continue + + if cur == '"': + quote = True + + part += cur + + # append last part + if part: + res.append(part) + + return [part.strip() for part in res] class FileHandler(BaseHandler): # Use local file or FTP depending on form of URL From birkenfeld at users.sourceforge.net Thu Aug 25 00:20:56 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 00:20:56 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_urllib2.py, 1.19, 1.19.2.1 Message-ID: <20050824222056.C7DC81E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24127/Lib/test Modified Files: Tag: release24-maint test_urllib2.py Log Message: Backport bug #735248: fix urllib2.parse_http_list(). Index: test_urllib2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_urllib2.py,v retrieving revision 1.19 retrieving revision 1.19.2.1 diff -u -d -r1.19 -r1.19.2.1 --- test_urllib2.py 7 Aug 2004 17:40:50 -0000 1.19 +++ test_urllib2.py 24 Aug 2005 22:20:46 -0000 1.19.2.1 @@ -41,6 +41,14 @@ buf = f.read() f.close() + def test_parse_http_list(self): + tests = [('a,b,c', ['a', 'b', 'c']), + ('path"o,l"og"i"cal, example', ['path"o,l"og"i"cal', 'example']), + ('a, b, "c", "d", "e,f", g, h', ['a', 'b', '"c"', '"d"', '"e,f"', 'g', 'h']), + ('a="b\\"c", d="e\\,f", g="h\\\\i"', ['a="b"c"', 'd="e,f"', 'g="h\\i"'])] + for string, list in tests: + self.assertEquals(urllib2.parse_http_list(string), list) + class MockOpener: addheaders = [] From birkenfeld at users.sourceforge.net Thu Aug 25 00:20:57 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 00:20:57 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib urllib2.py, 1.77.2.2, 1.77.2.3 Message-ID: <20050824222057.214751E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24127/Lib Modified Files: Tag: release24-maint urllib2.py Log Message: Backport bug #735248: fix urllib2.parse_http_list(). Index: urllib2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib2.py,v retrieving revision 1.77.2.2 retrieving revision 1.77.2.3 diff -u -d -r1.77.2.2 -r1.77.2.3 --- urllib2.py 24 Aug 2005 20:30:35 -0000 1.77.2.2 +++ urllib2.py 24 Aug 2005 22:20:46 -0000 1.77.2.3 @@ -1064,49 +1064,46 @@ def parse_http_list(s): """Parse lists as described by RFC 2068 Section 2. - + In particular, parse comma-separated lists where the elements of the list may include quoted-strings. A quoted-string could - contain a comma. + contain a comma. A non-quoted string could have quotes in the + middle. Neither commas nor quotes count if they are escaped. + Only double-quotes count, not single-quotes. """ - # XXX this function could probably use more testing + res = [] + part = '' - list = [] - end = len(s) - i = 0 - inquote = 0 - start = 0 - while i < end: - cur = s[i:] - c = cur.find(',') - q = cur.find('"') - if c == -1: - list.append(s[start:]) - break - if q == -1: - if inquote: - raise ValueError, "unbalanced quotes" - else: - list.append(s[start:i+c]) - i = i + c + 1 + escape = quote = False + for cur in s: + if escape: + part += cur + escape = False + continue + if quote: + if cur == '\\': + escape = True continue - if inquote: - if q < c: - list.append(s[start:i+c]) - i = i + c + 1 - start = i - inquote = 0 - else: - i = i + q - else: - if c < q: - list.append(s[start:i+c]) - i = i + c + 1 - start = i - else: - inquote = 1 - i = i + q + 1 - return map(lambda x: x.strip(), list) + elif cur == '"': + quote = False + part += cur + continue + + if cur == ',': + res.append(part) + part = '' + continue + + if cur == '"': + quote = True + + part += cur + + # append last part + if part: + res.append(part) + + return [part.strip() for part in res] class FileHandler(BaseHandler): # Use local file or FTP depending on form of URL From birkenfeld at users.sourceforge.net Thu Aug 25 00:34:31 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 00:34:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1349,1.1350 Message-ID: <20050824223431.5BAE51E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27394/Misc Modified Files: NEWS Log Message: patch #848017: make Cookie more RFC-compliant. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1349 retrieving revision 1.1350 diff -u -d -r1.1349 -r1.1350 --- NEWS 24 Aug 2005 18:46:38 -0000 1.1349 +++ NEWS 24 Aug 2005 22:34:20 -0000 1.1350 @@ -193,6 +193,9 @@ Library ------- +- Patch #848017: Make Cookie more RFC-compliant. Use CRLF as default output + separator and do not output trailing semicola. + - Patch #1062060: urllib.urlretrieve() now raises a new exception, named ContentTooShortException, when the actually downloaded size does not match the Content-Length header. From birkenfeld at users.sourceforge.net Thu Aug 25 00:34:31 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 00:34:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib Cookie.py,1.18,1.19 Message-ID: <20050824223431.741141E400F@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27394/Lib Modified Files: Cookie.py Log Message: patch #848017: make Cookie more RFC-compliant. Index: Cookie.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/Cookie.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- Cookie.py 26 Jun 2005 21:02:49 -0000 1.18 +++ Cookie.py 24 Aug 2005 22:34:21 -0000 1.19 @@ -69,9 +69,8 @@ >>> C = Cookie.SmartCookie() >>> C["fig"] = "newton" >>> C["sugar"] = "wafer" - >>> print C - Set-Cookie: fig=newton; - Set-Cookie: sugar=wafer; + >>> C.output() + 'Set-Cookie: fig=newton\r\nSet-Cookie: sugar=wafer' Notice that the printable representation of a Cookie is the appropriate format for a Set-Cookie: header. This is the @@ -82,9 +81,9 @@ >>> C["rocky"] = "road" >>> C["rocky"]["path"] = "/cookie" >>> print C.output(header="Cookie:") - Cookie: rocky=road; Path=/cookie; + Cookie: rocky=road; Path=/cookie >>> print C.output(attrs=[], header="Cookie:") - Cookie: rocky=road; + Cookie: rocky=road The load() method of a Cookie extracts cookies from a string. In a CGI script, you would use this method to extract the cookies from the @@ -92,9 +91,8 @@ >>> C = Cookie.SmartCookie() >>> C.load("chips=ahoy; vienna=finger") - >>> print C - Set-Cookie: chips=ahoy; - Set-Cookie: vienna=finger; + >>> C.output() + 'Set-Cookie: chips=ahoy\r\nSet-Cookie: vienna=finger' The load() method is darn-tootin smart about identifying cookies within a string. Escaped quotation marks, nested semicolons, and other @@ -103,7 +101,7 @@ >>> C = Cookie.SmartCookie() >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";') >>> print C - Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"; + Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;" Each element of the Cookie also supports all of the RFC 2109 Cookie attributes. Here's an example which sets the Path @@ -113,7 +111,7 @@ >>> C["oreo"] = "doublestuff" >>> C["oreo"]["path"] = "/" >>> print C - Set-Cookie: oreo=doublestuff; Path=/; + Set-Cookie: oreo=doublestuff; Path=/ Each dictionary element has a 'value' attribute, which gives you back the value associated with the key. @@ -144,9 +142,8 @@ '7' >>> C["string"].value 'seven' - >>> print C - Set-Cookie: number=7; - Set-Cookie: string=seven; + >>> C.output() + 'Set-Cookie: number=7\r\nSet-Cookie: string=seven' SerialCookie @@ -165,9 +162,8 @@ 7 >>> C["string"].value 'seven' - >>> print C - Set-Cookie: number="I7\012."; - Set-Cookie: string="S'seven'\012p1\012."; + >>> C.output() + 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string="S\'seven\'\\012p1\\012."' Be warned, however, if SerialCookie cannot de-serialize a value (because it isn't a valid pickle'd object), IT WILL RAISE AN EXCEPTION. @@ -190,9 +186,8 @@ 7 >>> C["string"].value 'seven' - >>> print C - Set-Cookie: number="I7\012."; - Set-Cookie: string=seven; + >>> C.output() + 'Set-Cookie: number="I7\\012."\r\nSet-Cookie: string=seven' Backwards Compatibility @@ -228,7 +223,7 @@ "SmartCookie","Cookie"] _nulljoin = ''.join -_spacejoin = ' '.join +_semispacejoin = '; '.join # # Define an exception visible to External modules @@ -485,7 +480,7 @@ RA = result.append # First, the key=value pair - RA("%s=%s;" % (self.key, self.coded_value)) + RA("%s=%s" % (self.key, self.coded_value)) # Now add any defined attributes if attrs is None: @@ -496,16 +491,16 @@ if V == "": continue if K not in attrs: continue if K == "expires" and type(V) == type(1): - RA("%s=%s;" % (self._reserved[K], _getdate(V))) + RA("%s=%s" % (self._reserved[K], _getdate(V))) elif K == "max-age" and type(V) == type(1): - RA("%s=%d;" % (self._reserved[K], V)) + RA("%s=%d" % (self._reserved[K], V)) elif K == "secure": - RA("%s;" % self._reserved[K]) + RA(str(self._reserved[K])) else: - RA("%s=%s;" % (self._reserved[K], V)) + RA("%s=%s" % (self._reserved[K], V)) # Return the result - return _spacejoin(result) + return _semispacejoin(result) # end OutputString # end Morsel class @@ -581,7 +576,7 @@ self.__set(key, rval, cval) # end __setitem__ - def output(self, attrs=None, header="Set-Cookie:", sep="\n"): + def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"): """Return a string suitable for HTTP.""" result = [] items = self.items() @@ -599,7 +594,7 @@ items.sort() for K,V in items: L.append( '%s=%s' % (K,repr(V.value) ) ) - return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L)) + return '<%s: %s>' % (self.__class__.__name__, _semispacejoin(L)) def js_output(self, attrs=None): """Return a string suitable for JavaScript.""" From birkenfeld at users.sourceforge.net Thu Aug 25 00:34:31 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 00:34:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libcookie.tex,1.12,1.13 Message-ID: <20050824223431.889861E4010@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27394/Doc/lib Modified Files: libcookie.tex Log Message: patch #848017: make Cookie more RFC-compliant. Index: libcookie.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcookie.tex,v retrieving revision 1.12 retrieving revision 1.13 diff -u -d -r1.12 -r1.13 --- libcookie.tex 31 May 2004 18:22:39 -0000 1.12 +++ libcookie.tex 24 Aug 2005 22:34:21 -0000 1.13 @@ -98,7 +98,9 @@ Return a string representation suitable to be sent as HTTP headers. \var{attrs} and \var{header} are sent to each \class{Morsel}'s \method{output()} method. \var{sep} is used to join the headers -together, and is by default a newline. +together, and is by default the combination '\r\n' (CRLF). +\versionchanged[The default separator has been changed from '\n' to match the cookie +specification]{2.5} \end{methoddesc} \begin{methoddesc}[BaseCookie]{js_output}{\optional{attrs}} @@ -195,32 +197,32 @@ >>> C["fig"] = "newton" >>> C["sugar"] = "wafer" >>> print C # generate HTTP headers -Set-Cookie: sugar=wafer; -Set-Cookie: fig=newton; +Set-Cookie: sugar=wafer +Set-Cookie: fig=newton >>> print C.output() # same thing -Set-Cookie: sugar=wafer; -Set-Cookie: fig=newton; +Set-Cookie: sugar=wafer +Set-Cookie: fig=newton >>> C = Cookie.SmartCookie() >>> C["rocky"] = "road" >>> C["rocky"]["path"] = "/cookie" >>> print C.output(header="Cookie:") -Cookie: rocky=road; Path=/cookie; +Cookie: rocky=road; Path=/cookie >>> print C.output(attrs=[], header="Cookie:") -Cookie: rocky=road; +Cookie: rocky=road >>> C = Cookie.SmartCookie() >>> C.load("chips=ahoy; vienna=finger") # load from a string (HTTP header) >>> print C -Set-Cookie: vienna=finger; -Set-Cookie: chips=ahoy; +Set-Cookie: vienna=finger +Set-Cookie: chips=ahoy >>> C = Cookie.SmartCookie() >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";') >>> print C -Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"; +Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;" >>> C = Cookie.SmartCookie() >>> C["oreo"] = "doublestuff" >>> C["oreo"]["path"] = "/" >>> print C -Set-Cookie: oreo=doublestuff; Path=/; +Set-Cookie: oreo=doublestuff; Path=/ >>> C = Cookie.SmartCookie() >>> C["twix"] = "none for you" >>> C["twix"].value @@ -233,8 +235,8 @@ >>> C["string"].value 'seven' >>> print C -Set-Cookie: number=7; -Set-Cookie: string=seven; +Set-Cookie: number=7 +Set-Cookie: string=seven >>> C = Cookie.SerialCookie() >>> C["number"] = 7 >>> C["string"] = "seven" @@ -243,8 +245,8 @@ >>> C["string"].value 'seven' >>> print C -Set-Cookie: number="I7\012."; -Set-Cookie: string="S'seven'\012p1\012."; +Set-Cookie: number="I7\012." +Set-Cookie: string="S'seven'\012p1\012." >>> C = Cookie.SmartCookie() >>> C["number"] = 7 >>> C["string"] = "seven" @@ -253,6 +255,6 @@ >>> C["string"].value 'seven' >>> print C -Set-Cookie: number="I7\012."; -Set-Cookie: string=seven; +Set-Cookie: number="I7\012." +Set-Cookie: string=seven \end{verbatim} From loewis at users.sourceforge.net Thu Aug 25 09:11:42 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 25 Aug 2005 09:11:42 +0200 (CEST) Subject: [Python-checkins] python/dist/src/PCbuild pcbuild.sln, 1.5, 1.6 readme.txt, 1.62, 1.63 Message-ID: <20050825071142.45FB51E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/PCbuild In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29164 Modified Files: pcbuild.sln readme.txt Log Message: Patch #1160164: Use ReleaseItanium for zlib build. Will backport to 2.4. Index: pcbuild.sln =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/pcbuild.sln,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- pcbuild.sln 8 Sep 2004 15:57:36 -0000 1.5 +++ pcbuild.sln 25 Aug 2005 07:11:31 -0000 1.6 @@ -179,8 +179,8 @@ {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.Debug.Build.0 = Debug|Win32 {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.Release.ActiveCfg = Release|Win32 {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.Release.Build.0 = Release|Win32 - {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.ReleaseItanium.ActiveCfg = Release|Win32 - {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.ReleaseItanium.Build.0 = Release|Win32 + {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.ReleaseItanium.ActiveCfg = ReleaseItanium|Win32 + {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.ReleaseItanium.Build.0 = ReleaseItanium|Win32 EndGlobalSection GlobalSection(SolutionItems) = postSolution readme.txt = readme.txt Index: readme.txt =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/readme.txt,v retrieving revision 1.62 retrieving revision 1.63 diff -u -d -r1.62 -r1.63 --- readme.txt 7 Aug 2005 02:47:59 -0000 1.62 +++ readme.txt 25 Aug 2005 07:11:31 -0000 1.63 @@ -135,6 +135,9 @@ However, the zlib project is not smart enough to remove anything under zlib-1.2.3\ when you do a clean, so if you want to rebuild zlib.lib you need to clean up zlib-1.2.3\ by hand. + When building zlib.pyd for Itanium, the pre-link build step won't work, + so you will need to invoke nmake manually, using an IA64 build + environment. bz2 Python wrapper for the libbz2 compression library. Homepage From loewis at users.sourceforge.net Thu Aug 25 09:17:49 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 25 Aug 2005 09:17:49 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.83, 1.1193.2.84 Message-ID: <20050825071749.114371E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30086/Misc Modified Files: Tag: release24-maint NEWS Log Message: Patch #1160164: Use ReleaseItanium for zlib build. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.83 retrieving revision 1.1193.2.84 diff -u -d -r1.1193.2.83 -r1.1193.2.84 --- NEWS 24 Aug 2005 14:55:42 -0000 1.1193.2.83 +++ NEWS 25 Aug 2005 07:17:37 -0000 1.1193.2.84 @@ -120,6 +120,8 @@ Build ----- +- Patch #1160164: Build zlib.pyd for Itanium. + - Bug #1189330: configure did not correctly determine the necessary value of LINKCC if python was built with GCC 4.0. From loewis at users.sourceforge.net Thu Aug 25 09:17:49 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 25 Aug 2005 09:17:49 +0200 (CEST) Subject: [Python-checkins] python/dist/src/PCbuild pcbuild.sln,1.5,1.5.2.1 Message-ID: <20050825071749.0F9381E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/PCbuild In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30086/PCbuild Modified Files: Tag: release24-maint pcbuild.sln Log Message: Patch #1160164: Use ReleaseItanium for zlib build. Index: pcbuild.sln =================================================================== RCS file: /cvsroot/python/python/dist/src/PCbuild/pcbuild.sln,v retrieving revision 1.5 retrieving revision 1.5.2.1 diff -u -d -r1.5 -r1.5.2.1 --- pcbuild.sln 8 Sep 2004 15:57:36 -0000 1.5 +++ pcbuild.sln 25 Aug 2005 07:17:37 -0000 1.5.2.1 @@ -179,8 +179,8 @@ {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.Debug.Build.0 = Debug|Win32 {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.Release.ActiveCfg = Release|Win32 {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.Release.Build.0 = Release|Win32 - {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.ReleaseItanium.ActiveCfg = Release|Win32 - {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.ReleaseItanium.Build.0 = Release|Win32 + {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.ReleaseItanium.ActiveCfg = ReleaseItanium|Win32 + {680CDC79-9CCA-4282-9A8D-927CB0DB55B2}.ReleaseItanium.Build.0 = ReleaseItanium|Win32 EndGlobalSection GlobalSection(SolutionItems) = postSolution readme.txt = readme.txt From birkenfeld at users.sourceforge.net Thu Aug 25 09:32:52 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 09:32:52 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib Cookie.py,1.19,1.20 Message-ID: <20050825073252.4E1F41E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32683/Lib Modified Files: Cookie.py Log Message: Correct test suite for #848017. Index: Cookie.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/Cookie.py,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- Cookie.py 24 Aug 2005 22:34:21 -0000 1.19 +++ Cookie.py 25 Aug 2005 07:32:41 -0000 1.20 @@ -224,6 +224,7 @@ _nulljoin = ''.join _semispacejoin = '; '.join +_spacejoin = ' '.join # # Define an exception visible to External modules @@ -594,7 +595,7 @@ items.sort() for K,V in items: L.append( '%s=%s' % (K,repr(V.value) ) ) - return '<%s: %s>' % (self.__class__.__name__, _semispacejoin(L)) + return '<%s: %s>' % (self.__class__.__name__, _spacejoin(L)) def js_output(self, attrs=None): """Return a string suitable for JavaScript.""" From birkenfeld at users.sourceforge.net Thu Aug 25 09:32:52 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 09:32:52 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_cookie.py, 1.14, 1.15 Message-ID: <20050825073252.A0AFB1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32683/Lib/test Modified Files: test_cookie.py Log Message: Correct test suite for #848017. Index: test_cookie.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_cookie.py,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- test_cookie.py 4 Jan 2004 11:14:51 -0000 1.14 +++ test_cookie.py 25 Aug 2005 07:32:42 -0000 1.15 @@ -12,17 +12,17 @@ cases = [ ('chips=ahoy; vienna=finger', {'chips':'ahoy', 'vienna':'finger'}), - ('keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;";', + ('keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"', {'keebler' : 'E=mc2; L="Loves"; fudge=\012;'}), # Check illegal cookies that have an '=' char in an unquoted value - ('keebler=E=mc2;', {'keebler' : 'E=mc2'}) + ('keebler=E=mc2', {'keebler' : 'E=mc2'}) ] for data, dict in cases: C = Cookie.SimpleCookie() ; C.load(data) print repr(C) - print str(C) + print C.output(sep='\n') for k, v in sorted(dict.iteritems()): print ' ', k, repr( C[k].value ), repr(v) verify(C[k].value == v) From loewis at users.sourceforge.net Thu Aug 25 13:03:48 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 25 Aug 2005 13:03:48 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/encodings idna.py,1.4,1.5 Message-ID: <20050825110348.B54541E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/encodings In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10784/Lib/encodings Modified Files: idna.py Log Message: Make IDNA return an empty string when the input is empty. Fixes #1163178. Will backport to 2.4. Index: idna.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/encodings/idna.py,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- idna.py 23 Mar 2004 23:40:36 -0000 1.4 +++ idna.py 25 Aug 2005 11:03:38 -0000 1.5 @@ -149,6 +149,9 @@ # IDNA is quite clear that implementations must be strict raise UnicodeError, "unsupported error handling "+errors + if not input: + return "", 0 + result = [] labels = dots.split(input) if labels and len(labels[-1])==0: @@ -166,6 +169,9 @@ if errors != 'strict': raise UnicodeError, "Unsupported error handling "+errors + if not input: + return u"", 0 + # IDNA allows decoding to operate on Unicode strings, too. if isinstance(input, unicode): labels = dots.split(input) From loewis at users.sourceforge.net Thu Aug 25 13:03:48 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 25 Aug 2005 13:03:48 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1350,1.1351 Message-ID: <20050825110348.B607F1E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10784/Misc Modified Files: NEWS Log Message: Make IDNA return an empty string when the input is empty. Fixes #1163178. Will backport to 2.4. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1350 retrieving revision 1.1351 diff -u -d -r1.1350 -r1.1351 --- NEWS 24 Aug 2005 22:34:20 -0000 1.1350 +++ NEWS 25 Aug 2005 11:03:38 -0000 1.1351 @@ -193,6 +193,8 @@ Library ------- +- Bug #1163178: Make IDNA return an empty string when the input is empty. + - Patch #848017: Make Cookie more RFC-compliant. Use CRLF as default output separator and do not output trailing semicola. From loewis at users.sourceforge.net Thu Aug 25 13:03:48 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 25 Aug 2005 13:03:48 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_codecs.py, 1.24, 1.25 Message-ID: <20050825110348.B6A1A1E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10784/Lib/test Modified Files: test_codecs.py Log Message: Make IDNA return an empty string when the input is empty. Fixes #1163178. Will backport to 2.4. Index: test_codecs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_codecs.py,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- test_codecs.py 20 Jul 2005 22:15:39 -0000 1.24 +++ test_codecs.py 25 Aug 2005 11:03:38 -0000 1.25 @@ -630,6 +630,12 @@ def test_builtin(self): self.assertEquals(unicode("python.org", "idna"), u"python.org") + def test_stream(self): + import StringIO + r = codecs.getreader("idna")(StringIO.StringIO("abc")) + r.read(3) + self.assertEquals(r.read(), u"") + class CodecsModuleTest(unittest.TestCase): def test_decode(self): From loewis at users.sourceforge.net Thu Aug 25 13:04:14 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 25 Aug 2005 13:04:14 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_codecs.py, 1.15.2.6, 1.15.2.7 Message-ID: <20050825110414.EDDAE1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11298/Lib/test Modified Files: Tag: release24-maint test_codecs.py Log Message: Make IDNA return an empty string when the input is empty. Fixes #1163178. Index: test_codecs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_codecs.py,v retrieving revision 1.15.2.6 retrieving revision 1.15.2.7 diff -u -d -r1.15.2.6 -r1.15.2.7 --- test_codecs.py 20 Jul 2005 22:52:09 -0000 1.15.2.6 +++ test_codecs.py 25 Aug 2005 11:04:04 -0000 1.15.2.7 @@ -632,6 +632,12 @@ def test_builtin(self): self.assertEquals(unicode("python.org", "idna"), u"python.org") + def test_stream(self): + import StringIO + r = codecs.getreader("idna")(StringIO.StringIO("abc")) + r.read(3) + self.assertEquals(r.read(), u"") + class CodecsModuleTest(unittest.TestCase): def test_decode(self): From loewis at users.sourceforge.net Thu Aug 25 13:04:15 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 25 Aug 2005 13:04:15 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/encodings idna.py, 1.4, 1.4.4.1 Message-ID: <20050825110415.104AD1E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/encodings In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11298/Lib/encodings Modified Files: Tag: release24-maint idna.py Log Message: Make IDNA return an empty string when the input is empty. Fixes #1163178. Index: idna.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/encodings/idna.py,v retrieving revision 1.4 retrieving revision 1.4.4.1 diff -u -d -r1.4 -r1.4.4.1 --- idna.py 23 Mar 2004 23:40:36 -0000 1.4 +++ idna.py 25 Aug 2005 11:04:04 -0000 1.4.4.1 @@ -149,6 +149,9 @@ # IDNA is quite clear that implementations must be strict raise UnicodeError, "unsupported error handling "+errors + if not input: + return "", 0 + result = [] labels = dots.split(input) if labels and len(labels[-1])==0: @@ -166,6 +169,9 @@ if errors != 'strict': raise UnicodeError, "Unsupported error handling "+errors + if not input: + return u"", 0 + # IDNA allows decoding to operate on Unicode strings, too. if isinstance(input, unicode): labels = dots.split(input) From loewis at users.sourceforge.net Thu Aug 25 13:04:15 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Thu, 25 Aug 2005 13:04:15 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.84, 1.1193.2.85 Message-ID: <20050825110415.3832D1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11298/Misc Modified Files: Tag: release24-maint NEWS Log Message: Make IDNA return an empty string when the input is empty. Fixes #1163178. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.84 retrieving revision 1.1193.2.85 diff -u -d -r1.1193.2.84 -r1.1193.2.85 --- NEWS 25 Aug 2005 07:17:37 -0000 1.1193.2.84 +++ NEWS 25 Aug 2005 11:04:04 -0000 1.1193.2.85 @@ -68,6 +68,8 @@ Library ------- +- Bug #1163178: Make IDNA return an empty string when the input is empty. + - Bug #1121494: distutils.dir_utils.mkpath now accepts Unicode strings. - Bug #1178484: Return complete lines from codec stream readers From python at dynkin.com Thu Aug 25 13:16:37 2005 From: python at dynkin.com (George Yoshida) Date: Thu, 25 Aug 2005 20:16:37 +0900 Subject: [Python-checkins] python/dist/src/Doc/lib libcookie.tex, 1.12, 1.13 In-Reply-To: <20050824223431.889861E4010@bag.python.org> References: <20050824223431.889861E4010@bag.python.org> Message-ID: <430DA895.4040004@dynkin.com> birkenfeld at users.sourceforge.net wrote: > Index: libcookie.tex > =================================================================== > RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcookie.tex,v > retrieving revision 1.12 > retrieving revision 1.13 > diff -u -d -r1.12 -r1.13 > --- libcookie.tex 31 May 2004 18:22:39 -0000 1.12 > +++ libcookie.tex 24 Aug 2005 22:34:21 -0000 1.13 > @@ -98,7 +98,9 @@ > Return a string representation suitable to be sent as HTTP headers. > \var{attrs} and \var{header} are sent to each \class{Morsel}'s > \method{output()} method. \var{sep} is used to join the headers > -together, and is by default a newline. > +together, and is by default the combination '\r\n' (CRLF). > +\versionchanged[The default separator has been changed from '\n' to match the cookie > +specification]{2.5} > \end{methoddesc} \ has a special meaning in TeX. Use \e (or \textbackslash) instead. http://www.python.org/dev/doc/devel/doc/inline-markup.html -- george Index: libcookie.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcookie.tex,v retrieving revision 1.13 diff -u -r1.13 libcookie.tex --- libcookie.tex 24 Aug 2005 22:34:21 -0000 1.13 +++ libcookie.tex 25 Aug 2005 10:36:14 -0000 @@ -98,8 +98,8 @@ Return a string representation suitable to be sent as HTTP headers. \var{attrs} and \var{header} are sent to each \class{Morsel}'s \method{output()} method. \var{sep} is used to join the headers -together, and is by default the combination '\r\n' (CRLF). -\versionchanged[The default separator has been changed from '\n' to match the cookie +together, and is by default the combination \code{'\e r\e n'} (CRLF). +\versionchanged[The default separator has been changed from \code{'\e n'} to match the cookie specification]{2.5} \end{methoddesc} From birkenfeld at users.sourceforge.net Thu Aug 25 14:51:27 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 14:51:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libcookie.tex,1.13,1.14 Message-ID: <20050825125127.272E81E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv814/Doc/lib Modified Files: libcookie.tex Log Message: Once upon a time, I used to know TeX... Index: libcookie.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libcookie.tex,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- libcookie.tex 24 Aug 2005 22:34:21 -0000 1.13 +++ libcookie.tex 25 Aug 2005 12:51:16 -0000 1.14 @@ -98,9 +98,9 @@ Return a string representation suitable to be sent as HTTP headers. \var{attrs} and \var{header} are sent to each \class{Morsel}'s \method{output()} method. \var{sep} is used to join the headers -together, and is by default the combination '\r\n' (CRLF). -\versionchanged[The default separator has been changed from '\n' to match the cookie -specification]{2.5} +together, and is by default the combination \code{'\e r\e n'} (CRLF). +\versionchanged[The default separator has been changed from \code{'\e n'} +to match the cookie specification]{2.5} \end{methoddesc} \begin{methoddesc}[BaseCookie]{js_output}{\optional{attrs}} From birkenfeld at users.sourceforge.net Thu Aug 25 15:10:52 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 15:10:52 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1351,1.1352 Message-ID: <20050825131052.AEF971E406B@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4953/Misc Modified Files: NEWS Log Message: Correcting my last BZ2 entry. Adding one for #1215928. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1351 retrieving revision 1.1352 diff -u -d -r1.1351 -r1.1352 --- NEWS 25 Aug 2005 11:03:38 -0000 1.1351 +++ NEWS 25 Aug 2005 13:10:41 -0000 1.1352 @@ -130,6 +130,11 @@ Extension Modules ----------------- +- Bug #1191043: Fix bz2.BZ2File.seek() for 64-bit file offsets. + +- Bug #1215928: Fix bz2.BZ2File.(x)readlines for files containing one + line without newlines. + - Bug #728515: mmap.resize() now resizes the file on Unix as it did on Windows. @@ -1601,9 +1606,6 @@ Extension modules ----------------- -- Fix bz2.BZ2File.(x)readlines() for files containing one line without - newlines. - - Added socket.getservbyport(), and make the second argument in getservbyname() and getservbyport() optional. From birkenfeld at users.sourceforge.net Thu Aug 25 15:11:08 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 15:11:08 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.85, 1.1193.2.86 Message-ID: <20050825131108.CC8921E401F@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5002/Misc Modified Files: Tag: release24-maint NEWS Log Message: Backport fixes for bugs #1191043 and #1215928. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.85 retrieving revision 1.1193.2.86 diff -u -d -r1.1193.2.85 -r1.1193.2.86 --- NEWS 25 Aug 2005 11:04:04 -0000 1.1193.2.85 +++ NEWS 25 Aug 2005 13:10:58 -0000 1.1193.2.86 @@ -52,6 +52,11 @@ Extension Modules ----------------- +- Bug #1215928: Fix bz2.BZ2File.seek() for 64-bit file offsets. + +- Bug #1191043: Fix bz2.BZ2File.(x)readlines() for files containing one line + without newlines. + - Bug #728515: mmap.resize() now resizes the file on Unix as it did on Windows. From birkenfeld at users.sourceforge.net Thu Aug 25 15:11:08 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 15:11:08 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_bz2.py, 1.16.2.1, 1.16.2.2 Message-ID: <20050825131108.CEC101E4058@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5002/Lib/test Modified Files: Tag: release24-maint test_bz2.py Log Message: Backport fixes for bugs #1191043 and #1215928. Index: test_bz2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_bz2.py,v retrieving revision 1.16.2.1 retrieving revision 1.16.2.2 diff -u -d -r1.16.2.1 -r1.16.2.2 --- test_bz2.py 3 Jun 2005 19:45:53 -0000 1.16.2.1 +++ test_bz2.py 25 Aug 2005 13:10:58 -0000 1.16.2.2 @@ -37,7 +37,7 @@ return bz2.decompress(data) class BZ2FileTest(BaseTest): - "Test MCRYPT type miscelaneous methods." + "Test BZ2File type miscellaneous methods." def setUp(self): self.filename = TESTFN @@ -245,6 +245,22 @@ self.assertEqual(f.tell(), len(self.DATA)) f.close() + def testBug1191043(self): + # readlines() for files containing no newline + data = 'BZh91AY&SY\xd9b\x89]\x00\x00\x00\x03\x80\x04\x00\x02\x00\x0c\x00 \x00!\x9ah3M\x13<]\xc9\x14\xe1BCe\x8a%t' + f = open(self.filename, "wb") + f.write(data) + f.close() + bz2f = BZ2File(self.filename) + lines = bz2f.readlines() + bz2f.close() + self.assertEqual(lines, ['Test']) + bz2f = BZ2File(self.filename) + xlines = bz2f.xreadlines() + bz2f.close() + self.assertEqual(lines, ['Test']) + + class BZ2CompressorTest(BaseTest): def testCompress(self): # "Test BZ2Compressor.compress()/flush()" From birkenfeld at users.sourceforge.net Thu Aug 25 15:11:09 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 15:11:09 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules bz2module.c, 1.23.2.1, 1.23.2.2 Message-ID: <20050825131109.1156D1E405E@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5002/Modules Modified Files: Tag: release24-maint bz2module.c Log Message: Backport fixes for bugs #1191043 and #1215928. Index: bz2module.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/bz2module.c,v retrieving revision 1.23.2.1 retrieving revision 1.23.2.2 diff -u -d -r1.23.2.1 -r1.23.2.2 --- bz2module.c 3 Jun 2005 19:45:52 -0000 1.23.2.1 +++ bz2module.c 25 Aug 2005 13:10:58 -0000 1.23.2.2 @@ -22,6 +22,18 @@ Gustavo Niemeyer \n\ "; +/* Our very own off_t-like type, 64-bit if possible */ +/* copied from Objects/fileobject.c */ +#if !defined(HAVE_LARGEFILE_SUPPORT) +typedef off_t Py_off_t; +#elif SIZEOF_OFF_T >= 8 +typedef off_t Py_off_t; +#elif SIZEOF_FPOS_T >= 8 +typedef fpos_t Py_off_t; +#else +#error "Large file support, but neither off_t nor fpos_t is large enough." +#endif + #define BUF(v) PyString_AS_STRING((PyStringObject *)v) #define MODE_CLOSED 0 @@ -405,7 +417,9 @@ Util_DropReadAhead(f); } if (f->mode == MODE_READ_EOF) { - return -1; + f->f_bufptr = f->f_buf; + f->f_bufend = f->f_buf; + return 0; } if ((f->f_buf = PyMem_Malloc(bufsize)) == NULL) { return -1; @@ -682,13 +696,13 @@ } totalread += nread; p = memchr(buffer+nfilled, '\n', nread); - if (p == NULL) { + if (!shortread && p == NULL) { /* Need a larger buffer to fit this line */ nfilled += nread; buffersize *= 2; if (buffersize > INT_MAX) { PyErr_SetString(PyExc_OverflowError, - "line is longer than a Python string can hold"); + "line is longer than a Python string can hold"); goto error; } if (big_buffer == NULL) { @@ -709,7 +723,7 @@ } end = buffer+nfilled+nread; q = buffer; - do { + while (p != NULL) { /* Process complete lines */ p++; line = PyString_FromStringAndSize(q, p-q); @@ -721,7 +735,7 @@ goto error; q = p; p = memchr(q, '\n', end-q); - } while (p != NULL); + } /* Move the remaining incomplete line to the start */ nfilled = end-q; memmove(buffer, q, nfilled); @@ -962,7 +976,8 @@ BZ2File_seek(BZ2FileObject *self, PyObject *args) { int where = 0; - long offset; + PyObject *offobj; + Py_off_t offset; char small_buffer[SMALLCHUNK]; char *buffer = small_buffer; size_t buffersize = SMALLCHUNK; @@ -973,7 +988,15 @@ int rewind = 0; PyObject *ret = NULL; - if (!PyArg_ParseTuple(args, "l|i:seek", &offset, &where)) + if (!PyArg_ParseTuple(args, "O|i:seek", &offobj, &where)) + return NULL; +#if !defined(HAVE_LARGEFILE_SUPPORT) + offset = PyInt_AsLong(offobj); +#else + offset = PyLong_Check(offobj) ? + PyLong_AsLongLong(offobj) : PyInt_AsLong(offobj); +#endif + if (PyErr_Occurred()) return NULL; ACQUIRE_LOCK(self); From birkenfeld at users.sourceforge.net Thu Aug 25 22:41:49 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 22:41:49 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Demo/parser README,1.4,1.5 Message-ID: <20050825204149.5A6F01E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Demo/parser In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1148/Demo/parser Modified Files: README Log Message: Minor spelling nit. Index: README =================================================================== RCS file: /cvsroot/python/python/dist/src/Demo/parser/README,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- README 23 Oct 2000 20:50:23 -0000 1.4 +++ README 25 Aug 2005 20:41:38 -0000 1.5 @@ -20,6 +20,6 @@ handle nested constructs easily using the functions and classes in example.py. - test_parser.py program to put the parser module through it's paces. + test_parser.py program to put the parser module through its paces. Enjoy! From birkenfeld at users.sourceforge.net Thu Aug 25 23:56:56 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 23:56:56 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref3.tex,1.126,1.127 Message-ID: <20050825215656.43CEF1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19458/Doc/ref Modified Files: ref3.tex Log Message: bug [ 1261229 ] __new__ is class method Index: ref3.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref3.tex,v retrieving revision 1.126 retrieving revision 1.127 diff -u -d -r1.126 -r1.127 --- ref3.tex 21 Aug 2005 11:26:14 -0000 1.126 +++ ref3.tex 25 Aug 2005 21:56:45 -0000 1.127 @@ -1056,7 +1056,7 @@ \begin{methoddesc}[object]{__new__}{cls\optional{, \moreargs}} Called to create a new instance of class \var{cls}. \method{__new__()} -is a static method (special-cased so you need not declare it as such) +is a class method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument. The remaining arguments are those passed to the object constructor expression (the call to the class). The return value of From birkenfeld at users.sourceforge.net Thu Aug 25 23:57:00 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Thu, 25 Aug 2005 23:57:00 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref3.tex, 1.121.2.5, 1.121.2.6 Message-ID: <20050825215700.353541E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19483/Doc/ref Modified Files: Tag: release24-maint ref3.tex Log Message: backport bug [ 1261229 ] __new__ is class method Index: ref3.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref3.tex,v retrieving revision 1.121.2.5 retrieving revision 1.121.2.6 diff -u -d -r1.121.2.5 -r1.121.2.6 --- ref3.tex 21 Aug 2005 11:27:35 -0000 1.121.2.5 +++ ref3.tex 25 Aug 2005 21:56:49 -0000 1.121.2.6 @@ -1056,7 +1056,7 @@ \begin{methoddesc}[object]{__new__}{cls\optional{, \moreargs}} Called to create a new instance of class \var{cls}. \method{__new__()} -is a static method (special-cased so you need not declare it as such) +is a class method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument. The remaining arguments are those passed to the object constructor expression (the call to the class). The return value of From birkenfeld at users.sourceforge.net Fri Aug 26 00:02:54 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 00:02:54 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/xml/dom minidom.py, 1.52, 1.53 Message-ID: <20050825220254.424B81E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/xml/dom In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21435/Lib/xml/dom Modified Files: minidom.py Log Message: bug [ 1262320 ] minidom.py alternate newl support is broken Index: minidom.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/xml/dom/minidom.py,v retrieving revision 1.52 retrieving revision 1.53 diff -u -d -r1.52 -r1.53 --- minidom.py 12 Feb 2004 17:35:11 -0000 1.52 +++ minidom.py 25 Aug 2005 22:02:43 -0000 1.53 @@ -1278,15 +1278,15 @@ writer.write("\n") + writer.write(">"+newl) class Entity(Identified, Node): attributes = None @@ -1739,9 +1739,9 @@ def writexml(self, writer, indent="", addindent="", newl="", encoding = None): if encoding is None: - writer.write('\n') + writer.write(''+newl) else: - writer.write('\n' % encoding) + writer.write('%s' % (encoding, newl)) for node in self.childNodes: node.writexml(writer, indent, addindent, newl) From birkenfeld at users.sourceforge.net Fri Aug 26 00:02:59 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 00:02:59 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/xml/dom minidom.py, 1.52, 1.52.4.1 Message-ID: <20050825220259.3DC4E1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/xml/dom In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21477/Lib/xml/dom Modified Files: Tag: release24-maint minidom.py Log Message: backport bug [ 1262320 ] minidom.py alternate newl support is broken Index: minidom.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/xml/dom/minidom.py,v retrieving revision 1.52 retrieving revision 1.52.4.1 diff -u -d -r1.52 -r1.52.4.1 --- minidom.py 12 Feb 2004 17:35:11 -0000 1.52 +++ minidom.py 25 Aug 2005 22:02:49 -0000 1.52.4.1 @@ -1278,15 +1278,15 @@ writer.write("\n") + writer.write(">"+newl) class Entity(Identified, Node): attributes = None @@ -1739,9 +1739,9 @@ def writexml(self, writer, indent="", addindent="", newl="", encoding = None): if encoding is None: - writer.write('\n') + writer.write(''+newl) else: - writer.write('\n' % encoding) + writer.write('%s' % (encoding, newl)) for node in self.childNodes: node.writexml(writer, indent, addindent, newl) From birkenfeld at users.sourceforge.net Fri Aug 26 00:14:26 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 00:14:26 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_minidom.py, 1.40, 1.41 Message-ID: <20050825221426.1FEF91E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26217/Lib/test Modified Files: test_minidom.py Log Message: bug [ 1262320 ] minidom.py alternate newl support is broken Index: test_minidom.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_minidom.py,v retrieving revision 1.40 retrieving revision 1.41 diff -u -d -r1.40 -r1.41 --- test_minidom.py 22 Jul 2005 21:49:29 -0000 1.40 +++ test_minidom.py 25 Aug 2005 22:14:15 -0000 1.41 @@ -413,12 +413,19 @@ def testTextNodeRepr(): pass def testWriteXML(): - str = '\n' + str = '' dom = parseString(str) domstr = dom.toxml() dom.unlink() confirm(str == domstr) +def testAltNewline(): + str = '\n\n' + dom = parseString(str) + domstr = dom.toprettyxml(newl="\r\n") + dom.unlink() + confirm(domstr == str.replace("\n", "\r\n")) + def testProcessingInstruction(): dom = parseString('') pi = dom.documentElement.firstChild @@ -878,9 +885,9 @@ def testEncodings(): doc = parseString('') - confirm(doc.toxml() == u'\n\u20ac' - and doc.toxml('utf-8') == '\n\xe2\x82\xac' - and doc.toxml('iso-8859-15') == '\n\xa4', + confirm(doc.toxml() == u'\u20ac' + and doc.toxml('utf-8') == '\xe2\x82\xac' + and doc.toxml('iso-8859-15') == '\xa4', "testEncodings - encoding EURO SIGN") doc.unlink() From birkenfeld at users.sourceforge.net Fri Aug 26 00:14:31 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 00:14:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_minidom.py, 1.39.4.1, 1.39.4.2 Message-ID: <20050825221431.C2DF11E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv26266/Lib/test Modified Files: Tag: release24-maint test_minidom.py Log Message: backport bug [ 1262320 ] minidom.py alternate newl support is broken Index: test_minidom.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_minidom.py,v retrieving revision 1.39.4.1 retrieving revision 1.39.4.2 diff -u -d -r1.39.4.1 -r1.39.4.2 --- test_minidom.py 22 Jul 2005 21:48:49 -0000 1.39.4.1 +++ test_minidom.py 25 Aug 2005 22:14:21 -0000 1.39.4.2 @@ -413,12 +413,19 @@ def testTextNodeRepr(): pass def testWriteXML(): - str = '\n' + str = '' dom = parseString(str) domstr = dom.toxml() dom.unlink() confirm(str == domstr) +def testAltNewline(): + str = '\n\n' + dom = parseString(str) + domstr = dom.toprettyxml(newl="\r\n") + dom.unlink() + confirm(domstr == str.replace("\n", "\r\n")) + def testProcessingInstruction(): dom = parseString('') pi = dom.documentElement.firstChild @@ -878,9 +885,9 @@ def testEncodings(): doc = parseString('') - confirm(doc.toxml() == u'\n\u20ac' - and doc.toxml('utf-8') == '\n\xe2\x82\xac' - and doc.toxml('iso-8859-15') == '\n\xa4', + confirm(doc.toxml() == u'\u20ac' + and doc.toxml('utf-8') == '\xe2\x82\xac' + and doc.toxml('iso-8859-15') == '\xa4', "testEncodings - encoding EURO SIGN") doc.unlink() From birkenfeld at users.sourceforge.net Fri Aug 26 00:40:27 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 00:40:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libshelve.tex,1.22,1.23 Message-ID: <20050825224027.8543D1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31111/Doc/lib Modified Files: libshelve.tex Log Message: bug [ 1248199 ] shelve .sync operation not documented Index: libshelve.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libshelve.tex,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- libshelve.tex 1 Jan 2005 00:28:43 -0000 1.22 +++ libshelve.tex 25 Aug 2005 22:40:16 -0000 1.23 @@ -42,6 +42,14 @@ the transition from dictionary based scripts to those requiring persistent storage. +One additional method is supported: +\begin{methoddesc}[Shelf]{sync}{} +Write back all entries in the cache if the shelf was opened with +\var{writeback} set to \var{True}. Also empty the cache and synchronize +the persistent dictionary on disk, if feasible. This is called automatically +when the shelf is closed with \method{close()}. +\end{methoddesc} + \subsection{Restrictions} \begin{itemize} From birkenfeld at users.sourceforge.net Fri Aug 26 00:40:32 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 00:40:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libshelve.tex, 1.20.16.1, 1.20.16.2 Message-ID: <20050825224032.365C41E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31019/Doc/lib Modified Files: Tag: release24-maint libshelve.tex Log Message: backport bug [ 1248199 ] shelve .sync operation not documented Index: libshelve.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libshelve.tex,v retrieving revision 1.20.16.1 retrieving revision 1.20.16.2 diff -u -d -r1.20.16.1 -r1.20.16.2 --- libshelve.tex 1 Jan 2005 00:34:53 -0000 1.20.16.1 +++ libshelve.tex 25 Aug 2005 22:40:21 -0000 1.20.16.2 @@ -43,6 +43,14 @@ the transition from dictionary based scripts to those requiring persistent storage. +One additional method is supported: +\begin{methoddesc}[Shelf]{sync}{} +Write back all entries in the cache if the shelf was opened with +\var{writeback} set to \var{True}. Also empty the cache and synchronize +the persistent dictionary on disk, if feasible. This is called automatically +when the shelf is closed with \method{close()}. +\end{methoddesc} + \subsection{Restrictions} \begin{itemize} From bcannon at users.sourceforge.net Fri Aug 26 08:01:15 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:01:15 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-0000.txt, 1.342, 1.343 pep-0348.txt, 1.9, 1.10 Message-ID: <20050826060115.7E7651E4003@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11676 Modified Files: pep-0000.txt pep-0348.txt Log Message: PEP 348 has been rejected. Index: pep-0000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v retrieving revision 1.342 retrieving revision 1.343 diff -u -d -r1.342 -r1.343 --- pep-0000.txt 22 Aug 2005 21:12:08 -0000 1.342 +++ pep-0000.txt 26 Aug 2005 06:01:04 -0000 1.343 @@ -104,7 +104,6 @@ S 344 Exception Chaining and Embedded Tracebacks Yee S 345 Metadata for Python Software Packages 1.2 Jones P 347 Migrating the Python CVS to Subversion von Lwis - S 348 Exception Reorganization for Python 3.0 Cannon S 349 Allow str() to return unicode strings Schemenauer S 754 IEEE 754 Floating Point Special Values Warnes @@ -217,6 +216,7 @@ SR 336 Make None Callable McClelland SR 340 Anonymous Block Statements GvR SR 346 User Defined ("with") Statements Coghlan + SR 348 Exception Reorganization for Python 3.0 Cannon SR 666 Reject Foolish Indentation Creighton @@ -392,7 +392,7 @@ S 345 Metadata for Python Software Packages 1.2 Jones SR 346 User Defined ("with") Statements Coghlan P 347 Migrating the Python CVS to Subversion von Lwis - S 348 Exception Reorganization for Python 3.0 Cannon + SR 348 Exception Reorganization for Python 3.0 Cannon S 349 Allow str() to return unicode strings Schemenauer SR 666 Reject Foolish Indentation Creighton S 754 IEEE 754 Floating Point Special Values Warnes Index: pep-0348.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0348.txt,v retrieving revision 1.9 retrieving revision 1.10 diff -u -d -r1.9 -r1.10 --- pep-0348.txt 16 Aug 2005 06:21:51 -0000 1.9 +++ pep-0348.txt 26 Aug 2005 06:01:04 -0000 1.10 @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Brett Cannon -Status: Draft +Status: Rejected Type: Standards Track Content-Type: text/x-rst Created: 28-Jul-2005 @@ -11,6 +11,8 @@ .. |2.x| replace:: 2.5 +.. note:: This PEP as been rejected [#rejected]_. + Abstract ======== @@ -508,6 +510,9 @@ .. [#tutorial] Python Tutorial http://docs.python.org/tut/tut.html +.. [#rejected] python-dev email (Bare except clauses in PEP 348) + http://mail.python.org/pipermail/python-dev/2005-August/055676.html + Copyright ========= From birkenfeld at users.sourceforge.net Fri Aug 26 08:42:40 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:42:40 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Include modsupport.h,2.41,2.42 Message-ID: <20050826064240.E0E5D1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18370/Include Modified Files: modsupport.h Log Message: Disallow keyword arguments for type constructors that don't use them. (fixes bug #1119418) Index: modsupport.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/modsupport.h,v retrieving revision 2.41 retrieving revision 2.42 diff -u -d -r2.41 -r2.42 --- modsupport.h 10 Jul 2004 22:20:17 -0000 2.41 +++ modsupport.h 26 Aug 2005 06:42:30 -0000 2.42 @@ -15,6 +15,7 @@ char *, char **, ...); PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, char *, int, int, ...); PyAPI_FUNC(PyObject *) Py_BuildValue(char *, ...); +PyAPI_FUNC(int) _PyArg_NoKeywords(char *funcname, PyObject *kw); PyAPI_FUNC(int) PyArg_VaParse(PyObject *, char *, va_list); PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, From birkenfeld at users.sourceforge.net Fri Aug 26 08:42:40 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:42:40 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python getargs.c,2.105,2.106 Message-ID: <20050826064240.E36A31E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18370/Python Modified Files: getargs.c Log Message: Disallow keyword arguments for type constructors that don't use them. (fixes bug #1119418) Index: getargs.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/getargs.c,v retrieving revision 2.105 retrieving revision 2.106 diff -u -d -r2.105 -r2.106 --- getargs.c 30 Mar 2005 16:41:55 -0000 2.105 +++ getargs.c 26 Aug 2005 06:42:30 -0000 2.106 @@ -1595,3 +1595,29 @@ va_end(vargs); return 1; } + + +/* For type constructors that don't take keyword args + * + * Sets a TypeError and returns 0 if the kwds dict is + * not emtpy, returns 1 otherwise + */ +int +_PyArg_NoKeywords(char *funcname, PyObject *kw) +{ + if (kw == NULL) + return 1; + if (!PyDict_CheckExact(kw)) { + PyErr_BadInternalCall(); + return 0; + } + if (PyDict_Size(kw) == 0) + return 1; + + PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments", + funcname); + return 0; +} + + + From birkenfeld at users.sourceforge.net Fri Aug 26 08:42:40 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:42:40 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1352,1.1353 Message-ID: <20050826064240.E87F11E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18370/Misc Modified Files: NEWS Log Message: Disallow keyword arguments for type constructors that don't use them. (fixes bug #1119418) Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1352 retrieving revision 1.1353 diff -u -d -r1.1352 -r1.1353 --- NEWS 25 Aug 2005 13:10:41 -0000 1.1352 +++ NEWS 26 Aug 2005 06:42:30 -0000 1.1353 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Disallow keyword arguments for type constructors that don't use it + (fixes bug #1119418). + - Forward UnicodeDecodeError into SyntaxError for source encoding errors. - SF bug #900092: When tracing (e.g. for hotshot), restore 'return' events for From birkenfeld at users.sourceforge.net Fri Aug 26 08:42:41 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:42:41 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects rangeobject.c, 2.54, 2.55 setobject.c, 1.55, 1.56 bufferobject.c, 2.26, 2.27 sliceobject.c, 2.22, 2.23 Message-ID: <20050826064241.27E321E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18370/Objects Modified Files: rangeobject.c setobject.c bufferobject.c sliceobject.c Log Message: Disallow keyword arguments for type constructors that don't use them. (fixes bug #1119418) Index: rangeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/rangeobject.c,v retrieving revision 2.54 retrieving revision 2.55 diff -u -d -r2.54 -r2.55 --- rangeobject.c 3 Dec 2004 11:45:13 -0000 2.54 +++ rangeobject.c 26 Aug 2005 06:42:30 -0000 2.55 @@ -45,6 +45,9 @@ long ilow = 0, ihigh = 0, istep = 1; long n; + if (!_PyArg_NoKeywords("xrange()", kw)) + return NULL; + if (PyTuple_Size(args) <= 1) { if (!PyArg_ParseTuple(args, "l;xrange() requires 1-3 int arguments", Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.55 retrieving revision 1.56 diff -u -d -r1.55 -r1.56 --- setobject.c 24 Aug 2005 00:24:40 -0000 1.55 +++ setobject.c 26 Aug 2005 06:42:30 -0000 1.56 @@ -935,6 +935,9 @@ { PyObject *iterable = NULL, *result; + if (!_PyArg_NoKeywords("frozenset()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable)) return NULL; @@ -976,6 +979,9 @@ static PyObject * set_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + if (!_PyArg_NoKeywords("set()", kwds)) + return NULL; + return make_new_set(type, NULL); } Index: bufferobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/bufferobject.c,v retrieving revision 2.26 retrieving revision 2.27 diff -u -d -r2.26 -r2.27 --- bufferobject.c 24 Sep 2004 19:17:26 -0000 2.26 +++ bufferobject.c 26 Aug 2005 06:42:30 -0000 2.27 @@ -192,7 +192,10 @@ int offset = 0; int size = Py_END_OF_BUFFER; - if ( !PyArg_ParseTuple(args, "O|ii:buffer", &ob, &offset, &size) ) + if (!_PyArg_NoKeywords("buffer()", kw)) + return NULL; + + if (!PyArg_ParseTuple(args, "O|ii:buffer", &ob, &offset, &size)) return NULL; return PyBuffer_FromObject(ob, offset, size); } Index: sliceobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/sliceobject.c,v retrieving revision 2.22 retrieving revision 2.23 diff -u -d -r2.22 -r2.23 --- sliceobject.c 5 Sep 2003 14:27:30 -0000 2.22 +++ sliceobject.c 26 Aug 2005 06:42:30 -0000 2.23 @@ -174,6 +174,9 @@ start = stop = step = NULL; + if (!_PyArg_NoKeywords("slice()", kw)) + return NULL; + if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step)) return NULL; From birkenfeld at users.sourceforge.net Fri Aug 26 08:42:41 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:42:41 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules arraymodule.c, 2.98, 2.99 itertoolsmodule.c, 1.40, 1.41 operator.c, 2.30, 2.31 _randommodule.c, 1.7, 1.8 zipimport.c, 1.18, 1.19 collectionsmodule.c, 1.38, 1.39 Message-ID: <20050826064241.56EFF1E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18370/Modules Modified Files: arraymodule.c itertoolsmodule.c operator.c _randommodule.c zipimport.c collectionsmodule.c Log Message: Disallow keyword arguments for type constructors that don't use them. (fixes bug #1119418) Index: arraymodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/arraymodule.c,v retrieving revision 2.98 retrieving revision 2.99 diff -u -d -r2.98 -r2.99 --- arraymodule.c 16 Dec 2004 16:23:39 -0000 2.98 +++ arraymodule.c 26 Aug 2005 06:42:30 -0000 2.99 @@ -1799,18 +1799,9 @@ char c; PyObject *initial = NULL, *it = NULL; struct arraydescr *descr; - - if (kwds != NULL) { - int i = PyObject_Length(kwds); - if (i < 0) - return NULL; - else if (i > 0) { - PyErr_SetString(PyExc_TypeError, - "array.array constructor takes " - "no keyword arguments"); - return NULL; - } - } + + if (!_PyArg_NoKeywords("array.array()", kwds)) + return NULL; if (!PyArg_ParseTuple(args, "c|O:array", &c, &initial)) return NULL; Index: itertoolsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/itertoolsmodule.c,v retrieving revision 1.40 retrieving revision 1.41 diff -u -d -r1.40 -r1.41 --- itertoolsmodule.c 5 Dec 2004 09:25:51 -0000 1.40 +++ itertoolsmodule.c 26 Aug 2005 06:42:30 -0000 1.41 @@ -618,6 +618,9 @@ PyObject *saved; cycleobject *lz; + if (!_PyArg_NoKeywords("cycle()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "cycle", 1, 1, &iterable)) return NULL; @@ -765,6 +768,9 @@ PyObject *it; dropwhileobject *lz; + if (!_PyArg_NoKeywords("dropwhile()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "dropwhile", 2, 2, &func, &seq)) return NULL; @@ -906,6 +912,9 @@ PyObject *it; takewhileobject *lz; + if (!_PyArg_NoKeywords("takewhile()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "takewhile", 2, 2, &func, &seq)) return NULL; @@ -1048,6 +1057,9 @@ int numargs; isliceobject *lz; + if (!_PyArg_NoKeywords("islice()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "islice", 2, 4, &seq, &a1, &a2, &a3)) return NULL; @@ -1236,6 +1248,9 @@ PyObject *it; starmapobject *lz; + if (!_PyArg_NoKeywords("starmap()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "starmap", 2, 2, &func, &seq)) return NULL; @@ -1365,6 +1380,9 @@ imapobject *lz; int numargs, i; + if (!_PyArg_NoKeywords("imap()", kwds)) + return NULL; + numargs = PyTuple_Size(args); if (numargs < 2) { PyErr_SetString(PyExc_TypeError, @@ -1544,6 +1562,9 @@ int i; PyObject *ittuple; + if (!_PyArg_NoKeywords("chain()", kwds)) + return NULL; + /* obtain iterators */ assert(PyTuple_Check(args)); ittuple = PyTuple_New(tuplesize); @@ -1684,6 +1705,9 @@ PyObject *it; ifilterobject *lz; + if (!_PyArg_NoKeywords("ifilter()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "ifilter", 2, 2, &func, &seq)) return NULL; @@ -1825,6 +1849,9 @@ PyObject *it; ifilterfalseobject *lz; + if (!_PyArg_NoKeywords("ifilterfalse()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "ifilterfalse", 2, 2, &func, &seq)) return NULL; @@ -1964,6 +1991,9 @@ countobject *lz; long cnt = 0; + if (!_PyArg_NoKeywords("count()", kwds)) + return NULL; + if (!PyArg_ParseTuple(args, "|l:count", &cnt)) return NULL; @@ -2060,6 +2090,9 @@ PyObject *result; int tuplesize = PySequence_Length(args); + if (!_PyArg_NoKeywords("izip()", kwds)) + return NULL; + /* args must be a tuple */ assert(PyTuple_Check(args)); @@ -2240,6 +2273,9 @@ PyObject *element; long cnt = -1; + if (!_PyArg_NoKeywords("repeat()", kwds)) + return NULL; + if (!PyArg_ParseTuple(args, "O|l:repeat", &element, &cnt)) return NULL; Index: operator.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/operator.c,v retrieving revision 2.30 retrieving revision 2.31 diff -u -d -r2.30 -r2.31 --- operator.c 9 Mar 2005 16:38:46 -0000 2.30 +++ operator.c 26 Aug 2005 06:42:30 -0000 2.31 @@ -269,6 +269,9 @@ PyObject *item; int nitems; + if (!_PyArg_NoKeywords("itemgetter()", kwds)) + return NULL; + nitems = PyTuple_GET_SIZE(args); if (nitems <= 1) { if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &item)) @@ -405,6 +408,9 @@ PyObject *attr; int nattrs; + if (!_PyArg_NoKeywords("attrgetter()", kwds)) + return NULL; + nattrs = PyTuple_GET_SIZE(args); if (nattrs <= 1) { if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &attr)) Index: _randommodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/_randommodule.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- _randommodule.c 5 Oct 2003 09:09:15 -0000 1.7 +++ _randommodule.c 26 Aug 2005 06:42:30 -0000 1.8 @@ -481,6 +481,9 @@ RandomObject *self; PyObject *tmp; + if (!_PyArg_NoKeywords("Random()", kwds)) + return NULL; + self = (RandomObject *)type->tp_alloc(type, 0); if (self == NULL) return NULL; Index: zipimport.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/zipimport.c,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- zipimport.c 10 Nov 2004 13:08:35 -0000 1.18 +++ zipimport.c 26 Aug 2005 06:42:30 -0000 1.19 @@ -65,6 +65,9 @@ char *path, *p, *prefix, buf[MAXPATHLEN+2]; int len; + if (!_PyArg_NoKeywords("zipimporter()", kwds)) + return -1; + if (!PyArg_ParseTuple(args, "s:zipimporter", &path)) return -1; Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- collectionsmodule.c 19 Mar 2005 00:00:48 -0000 1.38 +++ collectionsmodule.c 26 Aug 2005 06:42:30 -0000 1.39 @@ -95,6 +95,9 @@ dequeobject *deque; block *b; + if (!_PyArg_NoKeywords("deque()", kwds)) + return NULL; + /* create dequeobject structure */ deque = (dequeobject *)type->tp_alloc(type, 0); if (deque == NULL) From birkenfeld at users.sourceforge.net Fri Aug 26 08:43:27 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:43:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Include modsupport.h, 2.41, 2.41.4.1 Message-ID: <20050826064327.412041E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18531/Include Modified Files: Tag: release24-maint modsupport.h Log Message: Disallow keyword arguments for type constructors that don't use them (fixes #1119418). Index: modsupport.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/modsupport.h,v retrieving revision 2.41 retrieving revision 2.41.4.1 diff -u -d -r2.41 -r2.41.4.1 --- modsupport.h 10 Jul 2004 22:20:17 -0000 2.41 +++ modsupport.h 26 Aug 2005 06:43:16 -0000 2.41.4.1 @@ -15,6 +15,7 @@ char *, char **, ...); PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, char *, int, int, ...); PyAPI_FUNC(PyObject *) Py_BuildValue(char *, ...); +PyAPI_FUNC(int) _PyArg_NoKeywords(char *funcname, PyObject *kw); PyAPI_FUNC(int) PyArg_VaParse(PyObject *, char *, va_list); PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *, From birkenfeld at users.sourceforge.net Fri Aug 26 08:43:27 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:43:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python getargs.c, 2.102.2.2, 2.102.2.3 Message-ID: <20050826064327.675D91E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18531/Python Modified Files: Tag: release24-maint getargs.c Log Message: Disallow keyword arguments for type constructors that don't use them (fixes #1119418). Index: getargs.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/getargs.c,v retrieving revision 2.102.2.2 retrieving revision 2.102.2.3 diff -u -d -r2.102.2.2 -r2.102.2.3 --- getargs.c 3 Mar 2005 12:26:20 -0000 2.102.2.2 +++ getargs.c 26 Aug 2005 06:43:16 -0000 2.102.2.3 @@ -1594,3 +1594,29 @@ va_end(vargs); return 1; } + + +/* For type constructors that don't take keyword args + * + * Sets a TypeError and returns 0 if the kwds dict is + * not emtpy, returns 1 otherwise + */ +int +_PyArg_NoKeywords(char *funcname, PyObject *kw) +{ + if (kw == NULL) + return 1; + if (!PyDict_CheckExact(kw)) { + PyErr_BadInternalCall(); + return 0; + } + if (PyDict_Size(kw) == 0) + return 1; + + PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments", + funcname); + return 0; +} + + + From birkenfeld at users.sourceforge.net Fri Aug 26 08:43:27 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:43:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects rangeobject.c, 2.53, 2.53.2.1 setobject.c, 1.31.2.3, 1.31.2.4 bufferobject.c, 2.26, 2.26.2.1 sliceobject.c, 2.22, 2.22.4.1 Message-ID: <20050826064327.469F21E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18531/Objects Modified Files: Tag: release24-maint rangeobject.c setobject.c bufferobject.c sliceobject.c Log Message: Disallow keyword arguments for type constructors that don't use them (fixes #1119418). Index: rangeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/rangeobject.c,v retrieving revision 2.53 retrieving revision 2.53.2.1 diff -u -d -r2.53 -r2.53.2.1 --- rangeobject.c 8 Aug 2004 07:17:39 -0000 2.53 +++ rangeobject.c 26 Aug 2005 06:43:16 -0000 2.53.2.1 @@ -90,6 +90,9 @@ long ilow = 0, ihigh = 0, istep = 1; long n; + if (!_PyArg_NoKeywords("xrange()", kw)) + return NULL; + if (PyTuple_Size(args) <= 1) { if (!PyArg_ParseTuple(args, "l;xrange() requires 1-3 int arguments", Index: setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.31.2.3 retrieving revision 1.31.2.4 diff -u -d -r1.31.2.3 -r1.31.2.4 --- setobject.c 13 Aug 2005 02:28:54 -0000 1.31.2.3 +++ setobject.c 26 Aug 2005 06:43:16 -0000 1.31.2.4 @@ -81,6 +81,9 @@ { PyObject *iterable = NULL; + if (!_PyArg_NoKeywords("frozenset()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable)) return NULL; if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) { @@ -93,6 +96,9 @@ static PyObject * set_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + if (!_PyArg_NoKeywords("set()", kwds)) + return NULL; + return make_new_set(type, NULL); } Index: bufferobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/bufferobject.c,v retrieving revision 2.26 retrieving revision 2.26.2.1 diff -u -d -r2.26 -r2.26.2.1 --- bufferobject.c 24 Sep 2004 19:17:26 -0000 2.26 +++ bufferobject.c 26 Aug 2005 06:43:16 -0000 2.26.2.1 @@ -192,7 +192,10 @@ int offset = 0; int size = Py_END_OF_BUFFER; - if ( !PyArg_ParseTuple(args, "O|ii:buffer", &ob, &offset, &size) ) + if (!_PyArg_NoKeywords("buffer()", kw)) + return NULL; + + if (!PyArg_ParseTuple(args, "O|ii:buffer", &ob, &offset, &size)) return NULL; return PyBuffer_FromObject(ob, offset, size); } Index: sliceobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/sliceobject.c,v retrieving revision 2.22 retrieving revision 2.22.4.1 diff -u -d -r2.22 -r2.22.4.1 --- sliceobject.c 5 Sep 2003 14:27:30 -0000 2.22 +++ sliceobject.c 26 Aug 2005 06:43:16 -0000 2.22.4.1 @@ -174,6 +174,9 @@ start = stop = step = NULL; + if (!_PyArg_NoKeywords("slice()", kw)) + return NULL; + if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step)) return NULL; From birkenfeld at users.sourceforge.net Fri Aug 26 08:43:28 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:43:28 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules arraymodule.c, 2.97, 2.97.2.1 itertoolsmodule.c, 1.39, 1.39.2.1 operator.c, 2.29, 2.29.4.1 _randommodule.c, 1.7, 1.7.4.1 zipimport.c, 1.18, 1.18.2.1 collectionsmodule.c, 1.36, 1.36.2.1 Message-ID: <20050826064328.11CF61E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18531/Modules Modified Files: Tag: release24-maint arraymodule.c itertoolsmodule.c operator.c _randommodule.c zipimport.c collectionsmodule.c Log Message: Disallow keyword arguments for type constructors that don't use them (fixes #1119418). Index: arraymodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/arraymodule.c,v retrieving revision 2.97 retrieving revision 2.97.2.1 diff -u -d -r2.97 -r2.97.2.1 --- arraymodule.c 29 Aug 2004 07:50:42 -0000 2.97 +++ arraymodule.c 26 Aug 2005 06:43:16 -0000 2.97.2.1 @@ -1774,18 +1774,9 @@ char c; PyObject *initial = NULL, *it = NULL; struct arraydescr *descr; - - if (kwds != NULL) { - int i = PyObject_Length(kwds); - if (i < 0) - return NULL; - else if (i > 0) { - PyErr_SetString(PyExc_TypeError, - "array.array constructor takes " - "no keyword arguments"); - return NULL; - } - } + + if (!_PyArg_NoKeywords("array.array()", kwds)) + return NULL; if (!PyArg_ParseTuple(args, "c|O:array", &c, &initial)) return NULL; Index: itertoolsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/itertoolsmodule.c,v retrieving revision 1.39 retrieving revision 1.39.2.1 diff -u -d -r1.39 -r1.39.2.1 --- itertoolsmodule.c 17 Oct 2004 19:36:57 -0000 1.39 +++ itertoolsmodule.c 26 Aug 2005 06:43:16 -0000 1.39.2.1 @@ -618,6 +618,9 @@ PyObject *saved; cycleobject *lz; + if (!_PyArg_NoKeywords("cycle()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "cycle", 1, 1, &iterable)) return NULL; @@ -765,6 +768,9 @@ PyObject *it; dropwhileobject *lz; + if (!_PyArg_NoKeywords("dropwhile()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "dropwhile", 2, 2, &func, &seq)) return NULL; @@ -906,6 +912,9 @@ PyObject *it; takewhileobject *lz; + if (!_PyArg_NoKeywords("takewhile()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "takewhile", 2, 2, &func, &seq)) return NULL; @@ -1048,6 +1057,9 @@ int numargs; isliceobject *lz; + if (!_PyArg_NoKeywords("islice()", kwds)) + return NULL; + numargs = PyTuple_Size(args); if (!PyArg_ParseTuple(args, "OO|Ol:islice", &seq, &a1, &a2, &step)) return NULL; @@ -1234,6 +1246,9 @@ PyObject *it; starmapobject *lz; + if (!_PyArg_NoKeywords("starmap()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "starmap", 2, 2, &func, &seq)) return NULL; @@ -1363,6 +1378,9 @@ imapobject *lz; int numargs, i; + if (!_PyArg_NoKeywords("imap()", kwds)) + return NULL; + numargs = PyTuple_Size(args); if (numargs < 2) { PyErr_SetString(PyExc_TypeError, @@ -1542,6 +1560,9 @@ int i; PyObject *ittuple; + if (!_PyArg_NoKeywords("chain()", kwds)) + return NULL; + /* obtain iterators */ assert(PyTuple_Check(args)); ittuple = PyTuple_New(tuplesize); @@ -1682,6 +1703,9 @@ PyObject *it; ifilterobject *lz; + if (!_PyArg_NoKeywords("ifilter()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "ifilter", 2, 2, &func, &seq)) return NULL; @@ -1823,6 +1847,9 @@ PyObject *it; ifilterfalseobject *lz; + if (!_PyArg_NoKeywords("ifilterfalse()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "ifilterfalse", 2, 2, &func, &seq)) return NULL; @@ -1962,6 +1989,9 @@ countobject *lz; long cnt = 0; + if (!_PyArg_NoKeywords("count()", kwds)) + return NULL; + if (!PyArg_ParseTuple(args, "|l:count", &cnt)) return NULL; @@ -2058,6 +2088,9 @@ PyObject *result; int tuplesize = PySequence_Length(args); + if (!_PyArg_NoKeywords("izip()", kwds)) + return NULL; + /* args must be a tuple */ assert(PyTuple_Check(args)); @@ -2238,6 +2271,9 @@ PyObject *element; long cnt = -1; + if (!_PyArg_NoKeywords("repeat()", kwds)) + return NULL; + if (!PyArg_ParseTuple(args, "O|l:repeat", &element, &cnt)) return NULL; Index: operator.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/operator.c,v retrieving revision 2.29 retrieving revision 2.29.4.1 diff -u -d -r2.29 -r2.29.4.1 --- operator.c 4 Dec 2003 22:17:49 -0000 2.29 +++ operator.c 26 Aug 2005 06:43:16 -0000 2.29.4.1 @@ -267,6 +267,9 @@ itemgetterobject *ig; PyObject *item; + if (!_PyArg_NoKeywords("itemgetter()", kdws)) + return NULL; + if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &item)) return NULL; @@ -374,6 +377,9 @@ attrgetterobject *ag; PyObject *attr; + if (!_PyArg_NoKeywords("attrgetter()", kwds)) + return NULL; + if (!PyArg_UnpackTuple(args, "attrgetter", 1, 1, &attr)) return NULL; Index: _randommodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/_randommodule.c,v retrieving revision 1.7 retrieving revision 1.7.4.1 diff -u -d -r1.7 -r1.7.4.1 --- _randommodule.c 5 Oct 2003 09:09:15 -0000 1.7 +++ _randommodule.c 26 Aug 2005 06:43:16 -0000 1.7.4.1 @@ -481,6 +481,9 @@ RandomObject *self; PyObject *tmp; + if (!_PyArg_NoKeywords("Random()", kwds)) + return NULL; + self = (RandomObject *)type->tp_alloc(type, 0); if (self == NULL) return NULL; Index: zipimport.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/zipimport.c,v retrieving revision 1.18 retrieving revision 1.18.2.1 diff -u -d -r1.18 -r1.18.2.1 --- zipimport.c 10 Nov 2004 13:08:35 -0000 1.18 +++ zipimport.c 26 Aug 2005 06:43:16 -0000 1.18.2.1 @@ -65,6 +65,9 @@ char *path, *p, *prefix, buf[MAXPATHLEN+2]; int len; + if (!_PyArg_NoKeywords("zipimporter()", kwds)) + return -1; + if (!PyArg_ParseTuple(args, "s:zipimporter", &path)) return -1; Index: collectionsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/collectionsmodule.c,v retrieving revision 1.36 retrieving revision 1.36.2.1 diff -u -d -r1.36 -r1.36.2.1 --- collectionsmodule.c 9 Nov 2004 07:27:34 -0000 1.36 +++ collectionsmodule.c 26 Aug 2005 06:43:16 -0000 1.36.2.1 @@ -95,6 +95,9 @@ dequeobject *deque; block *b; + if (!_PyArg_NoKeywords("deque()", kwds)) + return NULL; + /* create dequeobject structure */ deque = (dequeobject *)type->tp_alloc(type, 0); if (deque == NULL) From birkenfeld at users.sourceforge.net Fri Aug 26 08:43:27 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:43:27 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.86, 1.1193.2.87 Message-ID: <20050826064327.40B1B1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18531/Misc Modified Files: Tag: release24-maint NEWS Log Message: Disallow keyword arguments for type constructors that don't use them (fixes #1119418). Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.86 retrieving revision 1.1193.2.87 diff -u -d -r1.1193.2.86 -r1.1193.2.87 --- NEWS 25 Aug 2005 13:10:58 -0000 1.1193.2.86 +++ NEWS 26 Aug 2005 06:43:16 -0000 1.1193.2.87 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Disallow keyword arguments for type constructors that don't use them + (fixes bug #1119418). + - Forward UnicodeDecodeError into SyntaxError for source encoding errors. - SF bug #900092: When tracing (e.g. for hotshot), restore 'return' events for From birkenfeld at users.sourceforge.net Fri Aug 26 08:44:03 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 08:44:03 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1353,1.1354 Message-ID: <20050826064403.393A71E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv18724/Misc Modified Files: NEWS Log Message: typo Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1353 retrieving revision 1.1354 diff -u -d -r1.1353 -r1.1354 --- NEWS 26 Aug 2005 06:42:30 -0000 1.1353 +++ NEWS 26 Aug 2005 06:43:52 -0000 1.1354 @@ -12,7 +12,7 @@ Core and builtins ----------------- -- Disallow keyword arguments for type constructors that don't use it +- Disallow keyword arguments for type constructors that don't use them (fixes bug #1119418). - Forward UnicodeDecodeError into SyntaxError for source encoding errors. From birkenfeld at users.sourceforge.net Fri Aug 26 10:33:39 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:33:39 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_socket.py, 1.77.2.1, 1.77.2.2 Message-ID: <20050826083339.5A4C71E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7366/Lib/test Modified Files: Tag: release24-maint test_socket.py Log Message: backport patch [ 756021 ] Allow socket.inet_aton("255.255.255.255") on Windows Index: test_socket.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_socket.py,v retrieving revision 1.77.2.1 retrieving revision 1.77.2.2 diff -u -d -r1.77.2.1 -r1.77.2.2 --- test_socket.py 12 Mar 2005 06:15:55 -0000 1.77.2.1 +++ test_socket.py 26 Aug 2005 08:33:28 -0000 1.77.2.2 @@ -380,10 +380,12 @@ self.assertEquals('\xff\x00\xff\x00', f('255.0.255.0')) self.assertEquals('\xaa\xaa\xaa\xaa', f('170.170.170.170')) self.assertEquals('\x01\x02\x03\x04', f('1.2.3.4')) + self.assertEquals('\xff\xff\xff\xff', f('255.255.255.255')) self.assertEquals('\x00\x00\x00\x00', g('0.0.0.0')) self.assertEquals('\xff\x00\xff\x00', g('255.0.255.0')) self.assertEquals('\xaa\xaa\xaa\xaa', g('170.170.170.170')) + self.assertEquals('\xff\xff\xff\xff', g('255.255.255.255')) def testIPv6toString(self): if not hasattr(socket, 'inet_pton'): From birkenfeld at users.sourceforge.net Fri Aug 26 10:33:39 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:33:39 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules socketmodule.c, 1.311, 1.311.2.1 Message-ID: <20050826083339.623AB1E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7366/Modules Modified Files: Tag: release24-maint socketmodule.c Log Message: backport patch [ 756021 ] Allow socket.inet_aton("255.255.255.255") on Windows Index: socketmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/socketmodule.c,v retrieving revision 1.311 retrieving revision 1.311.2.1 diff -u -d -r1.311 -r1.311.2.1 --- socketmodule.c 7 Nov 2004 14:24:25 -0000 1.311 +++ socketmodule.c 26 Aug 2005 08:33:28 -0000 1.311.2.1 @@ -3238,14 +3238,19 @@ return NULL; #else /* ! HAVE_INET_ATON */ - /* XXX Problem here: inet_aton('255.255.255.255') raises - an exception while it should be a valid address. */ - packed_addr = inet_addr(ip_addr); + /* special-case this address as inet_addr might return INADDR_NONE + * for this */ + if (strcmp(ip_addr, "255.255.255.255") == 0) { + packed_addr = 0xFFFFFFFF; + } else { + + packed_addr = inet_addr(ip_addr); - if (packed_addr == INADDR_NONE) { /* invalid address */ - PyErr_SetString(socket_error, - "illegal IP address string passed to inet_aton"); - return NULL; + if (packed_addr == INADDR_NONE) { /* invalid address */ + PyErr_SetString(socket_error, + "illegal IP address string passed to inet_aton"); + return NULL; + } } return PyString_FromStringAndSize((char *) &packed_addr, sizeof(packed_addr)); From birkenfeld at users.sourceforge.net Fri Aug 26 10:33:39 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:33:39 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.87, 1.1193.2.88 Message-ID: <20050826083339.706C51E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7366/Misc Modified Files: Tag: release24-maint NEWS Log Message: backport patch [ 756021 ] Allow socket.inet_aton("255.255.255.255") on Windows Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.87 retrieving revision 1.1193.2.88 diff -u -d -r1.1193.2.87 -r1.1193.2.88 --- NEWS 26 Aug 2005 06:43:16 -0000 1.1193.2.87 +++ NEWS 26 Aug 2005 08:33:28 -0000 1.1193.2.88 @@ -55,6 +55,9 @@ Extension Modules ----------------- +- Patch #756021: Special-case socket.inet_aton('255.255.255.255') for + platforms that don't have inet_aton(). + - Bug #1215928: Fix bz2.BZ2File.seek() for 64-bit file offsets. - Bug #1191043: Fix bz2.BZ2File.(x)readlines() for files containing one line From birkenfeld at users.sourceforge.net Fri Aug 26 10:34:10 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:34:10 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1354,1.1355 Message-ID: <20050826083410.4F9681E4010@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7523/Misc Modified Files: NEWS Log Message: patch [ 756021 ] Allow socket.inet_aton("255.255.255.255") on Windows Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1354 retrieving revision 1.1355 diff -u -d -r1.1354 -r1.1355 --- NEWS 26 Aug 2005 06:43:52 -0000 1.1354 +++ NEWS 26 Aug 2005 08:34:00 -0000 1.1355 @@ -133,9 +133,12 @@ Extension Modules ----------------- -- Bug #1191043: Fix bz2.BZ2File.seek() for 64-bit file offsets. +- Patch #756021: Special-case socket.inet_aton('255.255.255.255') for + platforms that don't have inet_aton(). -- Bug #1215928: Fix bz2.BZ2File.(x)readlines for files containing one +- Bug #1215928: Fix bz2.BZ2File.seek() for 64-bit file offsets. + +- Bug #1191043: Fix bz2.BZ2File.(x)readlines for files containing one line without newlines. - Bug #728515: mmap.resize() now resizes the file on Unix as it did From birkenfeld at users.sourceforge.net Fri Aug 26 10:34:10 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:34:10 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules socketmodule.c, 1.311, 1.312 Message-ID: <20050826083410.E5F121E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7523/Modules Modified Files: socketmodule.c Log Message: patch [ 756021 ] Allow socket.inet_aton("255.255.255.255") on Windows Index: socketmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/socketmodule.c,v retrieving revision 1.311 retrieving revision 1.312 diff -u -d -r1.311 -r1.312 --- socketmodule.c 7 Nov 2004 14:24:25 -0000 1.311 +++ socketmodule.c 26 Aug 2005 08:34:00 -0000 1.312 @@ -3238,14 +3238,19 @@ return NULL; #else /* ! HAVE_INET_ATON */ - /* XXX Problem here: inet_aton('255.255.255.255') raises - an exception while it should be a valid address. */ - packed_addr = inet_addr(ip_addr); + /* special-case this address as inet_addr might return INADDR_NONE + * for this */ + if (strcmp(ip_addr, "255.255.255.255") == 0) { + packed_addr = 0xFFFFFFFF; + } else { + + packed_addr = inet_addr(ip_addr); - if (packed_addr == INADDR_NONE) { /* invalid address */ - PyErr_SetString(socket_error, - "illegal IP address string passed to inet_aton"); - return NULL; + if (packed_addr == INADDR_NONE) { /* invalid address */ + PyErr_SetString(socket_error, + "illegal IP address string passed to inet_aton"); + return NULL; + } } return PyString_FromStringAndSize((char *) &packed_addr, sizeof(packed_addr)); From birkenfeld at users.sourceforge.net Fri Aug 26 10:34:10 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:34:10 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_socket.py, 1.79, 1.80 Message-ID: <20050826083410.EC0951E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7523/Lib/test Modified Files: test_socket.py Log Message: patch [ 756021 ] Allow socket.inet_aton("255.255.255.255") on Windows Index: test_socket.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_socket.py,v retrieving revision 1.79 retrieving revision 1.80 diff -u -d -r1.79 -r1.80 --- test_socket.py 17 Jul 2005 02:37:00 -0000 1.79 +++ test_socket.py 26 Aug 2005 08:34:00 -0000 1.80 @@ -380,10 +380,12 @@ self.assertEquals('\xff\x00\xff\x00', f('255.0.255.0')) self.assertEquals('\xaa\xaa\xaa\xaa', f('170.170.170.170')) self.assertEquals('\x01\x02\x03\x04', f('1.2.3.4')) + self.assertEquals('\xff\xff\xff\xff', f('255.255.255.255')) self.assertEquals('\x00\x00\x00\x00', g('0.0.0.0')) self.assertEquals('\xff\x00\xff\x00', g('255.0.255.0')) self.assertEquals('\xaa\xaa\xaa\xaa', g('170.170.170.170')) + self.assertEquals('\xff\xff\xff\xff', g('255.255.255.255')) def testIPv6toString(self): if not hasattr(socket, 'inet_pton'): From rhettinger at users.sourceforge.net Fri Aug 26 10:40:07 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:40:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules structmodule.c, 2.62, 2.63 Message-ID: <20050826084007.162521E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8992 Modified Files: structmodule.c Log Message: SF bug #1072182: bad arg type to isspace in struct module Index: structmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/structmodule.c,v retrieving revision 2.62 retrieving revision 2.63 diff -u -d -r2.62 -r2.63 --- structmodule.c 27 Sep 2004 19:27:51 -0000 2.62 +++ structmodule.c 26 Aug 2005 08:39:56 -0000 2.63 @@ -959,7 +959,7 @@ s = fmt; size = 0; while ((c = *s++) != '\0') { - if (isspace((int)c)) + if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; @@ -1059,7 +1059,7 @@ res = restart = PyString_AsString(result); while ((c = *s++) != '\0') { - if (isspace((int)c)) + if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; @@ -1191,7 +1191,7 @@ str = start; s = fmt; while ((c = *s++) != '\0') { - if (isspace((int)c)) + if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; From rhettinger at users.sourceforge.net Fri Aug 26 10:42:24 2005 From: rhettinger at users.sourceforge.net (rhettinger@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:42:24 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules structmodule.c, 2.62, 2.62.2.1 Message-ID: <20050826084224.598E61E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9577 Modified Files: Tag: release24-maint structmodule.c Log Message: SF bug #1072182: bad arg type to isspace in struct module Index: structmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/structmodule.c,v retrieving revision 2.62 retrieving revision 2.62.2.1 diff -u -d -r2.62 -r2.62.2.1 --- structmodule.c 27 Sep 2004 19:27:51 -0000 2.62 +++ structmodule.c 26 Aug 2005 08:42:13 -0000 2.62.2.1 @@ -959,7 +959,7 @@ s = fmt; size = 0; while ((c = *s++) != '\0') { - if (isspace((int)c)) + if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; @@ -1059,7 +1059,7 @@ res = restart = PyString_AsString(result); while ((c = *s++) != '\0') { - if (isspace((int)c)) + if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; @@ -1191,7 +1191,7 @@ str = start; s = fmt; while ((c = *s++) != '\0') { - if (isspace((int)c)) + if (isspace(Py_CHARMASK(c))) continue; if ('0' <= c && c <= '9') { num = c - '0'; From birkenfeld at users.sourceforge.net Fri Aug 26 10:51:44 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:51:44 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1355,1.1356 Message-ID: <20050826085144.5EE181E40EB@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11533/Misc Modified Files: NEWS Log Message: patch [ 810023 ] Fix for off-by-one bug in urllib.URLopener.retrieve Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1355 retrieving revision 1.1356 diff -u -d -r1.1355 -r1.1356 --- NEWS 26 Aug 2005 08:34:00 -0000 1.1355 +++ NEWS 26 Aug 2005 08:51:34 -0000 1.1356 @@ -204,6 +204,9 @@ Library ------- +- Patch #810023: Fix off-by-one bug in urllib.urlretrieve reporthook + functionality. + - Bug #1163178: Make IDNA return an empty string when the input is empty. - Patch #848017: Make Cookie more RFC-compliant. Use CRLF as default output From birkenfeld at users.sourceforge.net Fri Aug 26 10:51:44 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:51:44 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib urllib.py,1.167,1.168 Message-ID: <20050826085144.7D2FE1E40E0@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11533/Lib Modified Files: urllib.py Log Message: patch [ 810023 ] Fix for off-by-one bug in urllib.URLopener.retrieve Index: urllib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib.py,v retrieving revision 1.167 retrieving revision 1.168 diff -u -d -r1.167 -r1.168 --- urllib.py 24 Aug 2005 18:46:39 -0000 1.167 +++ urllib.py 26 Aug 2005 08:51:34 -0000 1.168 @@ -234,19 +234,17 @@ bs = 1024*8 size = -1 read = 0 - blocknum = 1 + blocknum = 0 if reporthook: if "content-length" in headers: size = int(headers["Content-Length"]) - reporthook(0, bs, size) - block = fp.read(bs) - read += len(block) - if reporthook: - reporthook(1, bs, size) - while block: - tfp.write(block) + reporthook(blocknum, bs, size) + while 1: block = fp.read(bs) + if block == "": + break read += len(block) + tfp.write(block) blocknum += 1 if reporthook: reporthook(blocknum, bs, size) From birkenfeld at users.sourceforge.net Fri Aug 26 10:51:45 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:51:45 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_urllib.py, 1.16, 1.17 Message-ID: <20050826085145.6698D1E40F2@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11533/Lib/test Modified Files: test_urllib.py Log Message: patch [ 810023 ] Fix for off-by-one bug in urllib.URLopener.retrieve Index: test_urllib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_urllib.py,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- test_urllib.py 29 Jun 2004 13:07:53 -0000 1.16 +++ test_urllib.py 26 Aug 2005 08:51:34 -0000 1.17 @@ -6,6 +6,7 @@ from test import test_support import os import mimetools +import tempfile import StringIO def hexescape(char): @@ -125,15 +126,53 @@ """Test urllib.urlretrieve() on local files""" def setUp(self): + # Create a list of temporary files. Each item in the list is a file + # name (absolute path or relative to the current working directory). + # All files in this list will be deleted in the tearDown method. Note, + # this only helps to makes sure temporary files get deleted, but it + # does nothing about trying to close files that may still be open. It + # is the responsibility of the developer to properly close files even + # when exceptional conditions occur. + self.tempFiles = [] + # Create a temporary file. + self.registerFileForCleanUp(test_support.TESTFN) self.text = 'testing urllib.urlretrieve' - FILE = file(test_support.TESTFN, 'wb') - FILE.write(self.text) - FILE.close() + try: + FILE = file(test_support.TESTFN, 'wb') + FILE.write(self.text) + FILE.close() + finally: + try: FILE.close() + except: pass def tearDown(self): - # Delete the temporary file. - os.remove(test_support.TESTFN) + # Delete the temporary files. + for each in self.tempFiles: + try: os.remove(each) + except: pass + + def constructLocalFileUrl(self, filePath): + return "file://%s" % urllib.pathname2url(os.path.abspath(filePath)) + + def createNewTempFile(self, data=""): + """Creates a new temporary file containing the specified data, + registers the file for deletion during the test fixture tear down, and + returns the absolute path of the file.""" + + newFd, newFilePath = tempfile.mkstemp() + try: + self.registerFileForCleanUp(newFilePath) + newFile = os.fdopen(newFd, "wb") + newFile.write(data) + newFile.close() + finally: + try: newFile.close() + except: pass + return newFilePath + + def registerFileForCleanUp(self, fileName): + self.tempFiles.append(fileName) def test_basic(self): # Make sure that a local file just gets its own location returned and @@ -147,15 +186,19 @@ def test_copy(self): # Test that setting the filename argument works. second_temp = "%s.2" % test_support.TESTFN - result = urllib.urlretrieve("file:%s" % test_support.TESTFN, second_temp) + self.registerFileForCleanUp(second_temp) + result = urllib.urlretrieve(self.constructLocalFileUrl( + test_support.TESTFN), second_temp) self.assertEqual(second_temp, result[0]) self.assert_(os.path.exists(second_temp), "copy of the file was not " "made") FILE = file(second_temp, 'rb') try: text = FILE.read() - finally: FILE.close() + finally: + try: FILE.close() + except: pass self.assertEqual(self.text, text) def test_reporthook(self): @@ -167,8 +210,49 @@ self.assertEqual(count, count_holder[0]) count_holder[0] = count_holder[0] + 1 second_temp = "%s.2" % test_support.TESTFN - urllib.urlretrieve(test_support.TESTFN, second_temp, hooktester) - os.remove(second_temp) + self.registerFileForCleanUp(second_temp) + urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN), + second_temp, hooktester) + + def test_reporthook_0_bytes(self): + # Test on zero length file. Should call reporthook only 1 time. + report = [] + def hooktester(count, block_size, total_size, _report=report): + _report.append((count, block_size, total_size)) + srcFileName = self.createNewTempFile() + urllib.urlretrieve(self.constructLocalFileUrl(srcFileName), + test_support.TESTFN, hooktester) + self.assertEqual(len(report), 1) + self.assertEqual(report[0][2], 0) + + def test_reporthook_5_bytes(self): + # Test on 5 byte file. Should call reporthook only 2 times (once when + # the "network connection" is established and once when the block is + # read). Since the block size is 8192 bytes, only one block read is + # required to read the entire file. + report = [] + def hooktester(count, block_size, total_size, _report=report): + _report.append((count, block_size, total_size)) + srcFileName = self.createNewTempFile("x" * 5) + urllib.urlretrieve(self.constructLocalFileUrl(srcFileName), + test_support.TESTFN, hooktester) + self.assertEqual(len(report), 2) + self.assertEqual(report[0][1], 8192) + self.assertEqual(report[0][2], 5) + + def test_reporthook_8193_bytes(self): + # Test on 8193 byte file. Should call reporthook only 3 times (once + # when the "network connection" is established, once for the next 8192 + # bytes, and once for the last byte). + report = [] + def hooktester(count, block_size, total_size, _report=report): + _report.append((count, block_size, total_size)) + srcFileName = self.createNewTempFile("x" * 8193) + urllib.urlretrieve(self.constructLocalFileUrl(srcFileName), + test_support.TESTFN, hooktester) + self.assertEqual(len(report), 3) + self.assertEqual(report[0][1], 8192) + self.assertEqual(report[0][2], 8193) class QuotingTests(unittest.TestCase): """Tests for urllib.quote() and urllib.quote_plus() From birkenfeld at users.sourceforge.net Fri Aug 26 10:51:50 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:51:50 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib urllib.py,1.165,1.165.2.1 Message-ID: <20050826085150.C67FE1E40F0@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11552/Lib Modified Files: Tag: release24-maint urllib.py Log Message: backport patch [ 810023 ] Fix for off-by-one bug in urllib.URLopener.retrieve Index: urllib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib.py,v retrieving revision 1.165 retrieving revision 1.165.2.1 diff -u -d -r1.165 -r1.165.2.1 --- urllib.py 11 Oct 2004 13:53:07 -0000 1.165 +++ urllib.py 26 Aug 2005 08:51:39 -0000 1.165.2.1 @@ -228,18 +228,17 @@ self.tempcache[url] = result bs = 1024*8 size = -1 - blocknum = 1 + blocknum = 0 if reporthook: if "content-length" in headers: size = int(headers["Content-Length"]) - reporthook(0, bs, size) - block = fp.read(bs) - if reporthook: - reporthook(1, bs, size) - while block: - tfp.write(block) + reporthook(blocknum, bs, size) + while 1: block = fp.read(bs) - blocknum = blocknum + 1 + if block == "": + break + tfp.write(block) + blocknum += 1 if reporthook: reporthook(blocknum, bs, size) fp.close() From birkenfeld at users.sourceforge.net Fri Aug 26 10:51:50 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:51:50 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.88, 1.1193.2.89 Message-ID: <20050826085150.C81781E40F3@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11552/Misc Modified Files: Tag: release24-maint NEWS Log Message: backport patch [ 810023 ] Fix for off-by-one bug in urllib.URLopener.retrieve Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.88 retrieving revision 1.1193.2.89 diff -u -d -r1.1193.2.88 -r1.1193.2.89 --- NEWS 26 Aug 2005 08:33:28 -0000 1.1193.2.88 +++ NEWS 26 Aug 2005 08:51:39 -0000 1.1193.2.89 @@ -79,6 +79,9 @@ Library ------- +- Patch #810023: Fix off-by-one bug in urllib.urlretrieve reporthook + functionality. + - Bug #1163178: Make IDNA return an empty string when the input is empty. - Bug #1121494: distutils.dir_utils.mkpath now accepts Unicode strings. From birkenfeld at users.sourceforge.net Fri Aug 26 10:51:51 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 10:51:51 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_urllib.py, 1.16, 1.16.4.1 Message-ID: <20050826085151.3A94C1E4092@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv11552/Lib/test Modified Files: Tag: release24-maint test_urllib.py Log Message: backport patch [ 810023 ] Fix for off-by-one bug in urllib.URLopener.retrieve Index: test_urllib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_urllib.py,v retrieving revision 1.16 retrieving revision 1.16.4.1 diff -u -d -r1.16 -r1.16.4.1 --- test_urllib.py 29 Jun 2004 13:07:53 -0000 1.16 +++ test_urllib.py 26 Aug 2005 08:51:39 -0000 1.16.4.1 @@ -6,6 +6,7 @@ from test import test_support import os import mimetools +import tempfile import StringIO def hexescape(char): @@ -125,15 +126,53 @@ """Test urllib.urlretrieve() on local files""" def setUp(self): + # Create a list of temporary files. Each item in the list is a file + # name (absolute path or relative to the current working directory). + # All files in this list will be deleted in the tearDown method. Note, + # this only helps to makes sure temporary files get deleted, but it + # does nothing about trying to close files that may still be open. It + # is the responsibility of the developer to properly close files even + # when exceptional conditions occur. + self.tempFiles = [] + # Create a temporary file. + self.registerFileForCleanUp(test_support.TESTFN) self.text = 'testing urllib.urlretrieve' - FILE = file(test_support.TESTFN, 'wb') - FILE.write(self.text) - FILE.close() + try: + FILE = file(test_support.TESTFN, 'wb') + FILE.write(self.text) + FILE.close() + finally: + try: FILE.close() + except: pass def tearDown(self): - # Delete the temporary file. - os.remove(test_support.TESTFN) + # Delete the temporary files. + for each in self.tempFiles: + try: os.remove(each) + except: pass + + def constructLocalFileUrl(self, filePath): + return "file://%s" % urllib.pathname2url(os.path.abspath(filePath)) + + def createNewTempFile(self, data=""): + """Creates a new temporary file containing the specified data, + registers the file for deletion during the test fixture tear down, and + returns the absolute path of the file.""" + + newFd, newFilePath = tempfile.mkstemp() + try: + self.registerFileForCleanUp(newFilePath) + newFile = os.fdopen(newFd, "wb") + newFile.write(data) + newFile.close() + finally: + try: newFile.close() + except: pass + return newFilePath + + def registerFileForCleanUp(self, fileName): + self.tempFiles.append(fileName) def test_basic(self): # Make sure that a local file just gets its own location returned and @@ -147,15 +186,19 @@ def test_copy(self): # Test that setting the filename argument works. second_temp = "%s.2" % test_support.TESTFN - result = urllib.urlretrieve("file:%s" % test_support.TESTFN, second_temp) + self.registerFileForCleanUp(second_temp) + result = urllib.urlretrieve(self.constructLocalFileUrl( + test_support.TESTFN), second_temp) self.assertEqual(second_temp, result[0]) self.assert_(os.path.exists(second_temp), "copy of the file was not " "made") FILE = file(second_temp, 'rb') try: text = FILE.read() - finally: FILE.close() + finally: + try: FILE.close() + except: pass self.assertEqual(self.text, text) def test_reporthook(self): @@ -167,8 +210,49 @@ self.assertEqual(count, count_holder[0]) count_holder[0] = count_holder[0] + 1 second_temp = "%s.2" % test_support.TESTFN - urllib.urlretrieve(test_support.TESTFN, second_temp, hooktester) - os.remove(second_temp) + self.registerFileForCleanUp(second_temp) + urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN), + second_temp, hooktester) + + def test_reporthook_0_bytes(self): + # Test on zero length file. Should call reporthook only 1 time. + report = [] + def hooktester(count, block_size, total_size, _report=report): + _report.append((count, block_size, total_size)) + srcFileName = self.createNewTempFile() + urllib.urlretrieve(self.constructLocalFileUrl(srcFileName), + test_support.TESTFN, hooktester) + self.assertEqual(len(report), 1) + self.assertEqual(report[0][2], 0) + + def test_reporthook_5_bytes(self): + # Test on 5 byte file. Should call reporthook only 2 times (once when + # the "network connection" is established and once when the block is + # read). Since the block size is 8192 bytes, only one block read is + # required to read the entire file. + report = [] + def hooktester(count, block_size, total_size, _report=report): + _report.append((count, block_size, total_size)) + srcFileName = self.createNewTempFile("x" * 5) + urllib.urlretrieve(self.constructLocalFileUrl(srcFileName), + test_support.TESTFN, hooktester) + self.assertEqual(len(report), 2) + self.assertEqual(report[0][1], 8192) + self.assertEqual(report[0][2], 5) + + def test_reporthook_8193_bytes(self): + # Test on 8193 byte file. Should call reporthook only 3 times (once + # when the "network connection" is established, once for the next 8192 + # bytes, and once for the last byte). + report = [] + def hooktester(count, block_size, total_size, _report=report): + _report.append((count, block_size, total_size)) + srcFileName = self.createNewTempFile("x" * 8193) + urllib.urlretrieve(self.constructLocalFileUrl(srcFileName), + test_support.TESTFN, hooktester) + self.assertEqual(len(report), 3) + self.assertEqual(report[0][1], 8192) + self.assertEqual(report[0][2], 8193) class QuotingTests(unittest.TestCase): """Tests for urllib.quote() and urllib.quote_plus() From birkenfeld at users.sourceforge.net Fri Aug 26 14:50:48 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 14:50:48 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules operator.c, 2.29.4.1, 2.29.4.2 Message-ID: <20050826125048.DE24C1E40A6@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29960/Modules Modified Files: Tag: release24-maint operator.c Log Message: Important typo Index: operator.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/operator.c,v retrieving revision 2.29.4.1 retrieving revision 2.29.4.2 diff -u -d -r2.29.4.1 -r2.29.4.2 --- operator.c 26 Aug 2005 06:43:16 -0000 2.29.4.1 +++ operator.c 26 Aug 2005 12:50:37 -0000 2.29.4.2 @@ -267,7 +267,7 @@ itemgetterobject *ig; PyObject *item; - if (!_PyArg_NoKeywords("itemgetter()", kdws)) + if (!_PyArg_NoKeywords("itemgetter()", kwds)) return NULL; if (!PyArg_UnpackTuple(args, "itemgetter", 1, 1, &item)) From birkenfeld at users.sourceforge.net Fri Aug 26 14:56:28 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 14:56:28 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref3.tex, 1.121.2.6, 1.121.2.7 Message-ID: <20050826125628.37F1C1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30824/Doc/ref Modified Files: Tag: release24-maint ref3.tex Log Message: __new__ is a static method Index: ref3.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref3.tex,v retrieving revision 1.121.2.6 retrieving revision 1.121.2.7 diff -u -d -r1.121.2.6 -r1.121.2.7 --- ref3.tex 25 Aug 2005 21:56:49 -0000 1.121.2.6 +++ ref3.tex 26 Aug 2005 12:56:17 -0000 1.121.2.7 @@ -1056,7 +1056,7 @@ \begin{methoddesc}[object]{__new__}{cls\optional{, \moreargs}} Called to create a new instance of class \var{cls}. \method{__new__()} -is a class method (special-cased so you need not declare it as such) +is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument. The remaining arguments are those passed to the object constructor expression (the call to the class). The return value of From birkenfeld at users.sourceforge.net Fri Aug 26 14:56:32 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 14:56:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/ref ref3.tex,1.127,1.128 Message-ID: <20050826125632.5B15A1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/ref In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30810/Doc/ref Modified Files: ref3.tex Log Message: __new__ is a static method Index: ref3.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/ref/ref3.tex,v retrieving revision 1.127 retrieving revision 1.128 diff -u -d -r1.127 -r1.128 --- ref3.tex 25 Aug 2005 21:56:45 -0000 1.127 +++ ref3.tex 26 Aug 2005 12:56:22 -0000 1.128 @@ -1056,7 +1056,7 @@ \begin{methoddesc}[object]{__new__}{cls\optional{, \moreargs}} Called to create a new instance of class \var{cls}. \method{__new__()} -is a class method (special-cased so you need not declare it as such) +is a static method (special-cased so you need not declare it as such) that takes the class of which an instance was requested as its first argument. The remaining arguments are those passed to the object constructor expression (the call to the class). The return value of From birkenfeld at users.sourceforge.net Fri Aug 26 15:22:01 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 15:22:01 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test/output test_cookie, 1.8, 1.9 Message-ID: <20050826132201.8F23B1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test/output In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4388/Lib/test/output Modified Files: test_cookie Log Message: Index: test_cookie =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/output/test_cookie,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- test_cookie 27 Jun 2005 05:51:07 -0000 1.8 +++ test_cookie 26 Aug 2005 13:21:50 -0000 1.9 @@ -1,31 +1,31 @@ test_cookie -Set-Cookie: chips=ahoy; -Set-Cookie: vienna=finger; +Set-Cookie: chips=ahoy +Set-Cookie: vienna=finger chips 'ahoy' 'ahoy' -Set-Cookie: chips=ahoy; +Set-Cookie: chips=ahoy vienna 'finger' 'finger' -Set-Cookie: vienna=finger; +Set-Cookie: vienna=finger -Set-Cookie: keebler="E=mc2; L=\"Loves\"; fudge=\012;"; +Set-Cookie: keebler="E=mc2; L=\"Loves\"; fudge=\012;" keebler 'E=mc2; L="Loves"; fudge=\n;' 'E=mc2; L="Loves"; fudge=\n;' -Set-Cookie: keebler="E=mc2; L=\"Loves\"; fudge=\012;"; +Set-Cookie: keebler="E=mc2; L=\"Loves\"; fudge=\012;" -Set-Cookie: keebler=E=mc2; +Set-Cookie: keebler=E=mc2 keebler 'E=mc2' 'E=mc2' -Set-Cookie: keebler=E=mc2; -Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme; +Set-Cookie: keebler=E=mc2 +Set-Cookie: Customer="WILE_E_COYOTE"; Path=/acme From birkenfeld at users.sourceforge.net Fri Aug 26 15:24:05 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 15:24:05 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_bz2.py,1.18,1.19 Message-ID: <20050826132405.30B221E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4822/Lib/test Modified Files: test_bz2.py Log Message: Add list() around xreadlines() Index: test_bz2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_bz2.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- test_bz2.py 21 Aug 2005 14:16:04 -0000 1.18 +++ test_bz2.py 26 Aug 2005 13:23:54 -0000 1.19 @@ -191,7 +191,7 @@ def testSeekBackwardsFromEnd(self): # "Test BZ2File.seek(-150, 2)" self.createTempFile() - bz2f = BZ2File(self.filename) + )bz2f = BZ2File(self.filename) bz2f.seek(-150, 2) self.assertEqual(bz2f.read(), self.TEXT[len(self.TEXT)-150:]) bz2f.close() @@ -256,7 +256,7 @@ bz2f.close() self.assertEqual(lines, ['Test']) bz2f = BZ2File(self.filename) - xlines = bz2f.xreadlines() + xlines = list(bz2f.xreadlines()) bz2f.close() self.assertEqual(lines, ['Test']) From birkenfeld at users.sourceforge.net Fri Aug 26 15:24:19 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Fri, 26 Aug 2005 15:24:19 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_bz2.py, 1.16.2.2, 1.16.2.3 Message-ID: <20050826132419.565F41E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4981/Lib/test Modified Files: Tag: release24-maint test_bz2.py Log Message: Add list() around xreadlines() Index: test_bz2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_bz2.py,v retrieving revision 1.16.2.2 retrieving revision 1.16.2.3 diff -u -d -r1.16.2.2 -r1.16.2.3 --- test_bz2.py 25 Aug 2005 13:10:58 -0000 1.16.2.2 +++ test_bz2.py 26 Aug 2005 13:24:09 -0000 1.16.2.3 @@ -256,7 +256,7 @@ bz2f.close() self.assertEqual(lines, ['Test']) bz2f = BZ2File(self.filename) - xlines = bz2f.xreadlines() + xlines = list(bz2f.xreadlines()) bz2f.close() self.assertEqual(lines, ['Test']) From tim_one at users.sourceforge.net Fri Aug 26 16:34:08 2005 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri, 26 Aug 2005 16:34:08 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_bz2.py,1.19,1.20 Message-ID: <20050826143408.CE51D1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23937/Lib/test Modified Files: test_bz2.py Log Message: testSeekBackwardsFromEnd(): Repair obvious syntax error. Index: test_bz2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_bz2.py,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- test_bz2.py 26 Aug 2005 13:23:54 -0000 1.19 +++ test_bz2.py 26 Aug 2005 14:33:57 -0000 1.20 @@ -191,7 +191,7 @@ def testSeekBackwardsFromEnd(self): # "Test BZ2File.seek(-150, 2)" self.createTempFile() - )bz2f = BZ2File(self.filename) + bz2f = BZ2File(self.filename) bz2f.seek(-150, 2) self.assertEqual(bz2f.read(), self.TEXT[len(self.TEXT)-150:]) bz2f.close() From tim_one at users.sourceforge.net Fri Aug 26 17:20:58 2005 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri, 26 Aug 2005 17:20:58 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/distutils dir_util.py, 1.16, 1.17 Message-ID: <20050826152058.8CD111E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/distutils In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv805/Lib/distutils Modified Files: dir_util.py Log Message: Whitespace normalization (via reindent.py). Index: dir_util.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/distutils/dir_util.py,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- dir_util.py 24 Aug 2005 14:55:22 -0000 1.16 +++ dir_util.py 26 Aug 2005 15:20:47 -0000 1.17 @@ -31,7 +31,7 @@ global _path_created # Detect a common bug -- name is None - if not isinstance(name, StringTypes): + if not isinstance(name, StringTypes): raise DistutilsInternalError, \ "mkpath: 'name' must be a string (got %r)" % (name,) From tim_one at users.sourceforge.net Fri Aug 26 17:20:58 2005 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri, 26 Aug 2005 17:20:58 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib hashlib.py, 1.1, 1.2 random.py, 1.72, 1.73 urllib2.py, 1.86, 1.87 Message-ID: <20050826152058.A3EEC1E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv805/Lib Modified Files: hashlib.py random.py urllib2.py Log Message: Whitespace normalization (via reindent.py). Index: hashlib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/hashlib.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- hashlib.py 21 Aug 2005 18:46:00 -0000 1.1 +++ hashlib.py 26 Aug 2005 15:20:47 -0000 1.2 @@ -107,4 +107,3 @@ sha256 = __get_builtin_constructor('sha256') sha384 = __get_builtin_constructor('sha384') sha512 = __get_builtin_constructor('sha512') - Index: random.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/random.py,v retrieving revision 1.72 retrieving revision 1.73 diff -u -d -r1.72 -r1.73 --- random.py 19 Aug 2005 01:36:35 -0000 1.72 +++ random.py 26 Aug 2005 15:20:47 -0000 1.73 @@ -303,7 +303,7 @@ result = [None] * k setsize = 21 # size of a small set minus size of an empty list if k > 5: - setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets + setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets if n <= setsize: # is an n-length list smaller than a k-length set pool = list(population) for i in xrange(k): # invariant: non-selected at [0,n-i) Index: urllib2.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/urllib2.py,v retrieving revision 1.86 retrieving revision 1.87 diff -u -d -r1.86 -r1.87 --- urllib2.py 24 Aug 2005 22:20:32 -0000 1.86 +++ urllib2.py 26 Aug 2005 15:20:47 -0000 1.87 @@ -1069,7 +1069,7 @@ def parse_http_list(s): """Parse lists as described by RFC 2068 Section 2. - + In particular, parse comma-separated lists where the elements of the list may include quoted-strings. A quoted-string could contain a comma. A non-quoted string could have quotes in the @@ -1101,7 +1101,7 @@ if cur == '"': quote = True - + part += cur # append last part From tim_one at users.sourceforge.net Fri Aug 26 17:20:58 2005 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri, 26 Aug 2005 17:20:58 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test seq_tests.py, 1.5, 1.6 test_generators.py, 1.47, 1.48 test_hashlib_speed.py, 1.1, 1.2 test_mmap.py, 1.33, 1.34 Message-ID: <20050826152058.AF9241E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv805/Lib/test Modified Files: seq_tests.py test_generators.py test_hashlib_speed.py test_mmap.py Log Message: Whitespace normalization (via reindent.py). Index: seq_tests.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/seq_tests.py,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- seq_tests.py 24 Aug 2005 09:08:57 -0000 1.5 +++ seq_tests.py 26 Aug 2005 15:20:48 -0000 1.6 @@ -228,7 +228,7 @@ class StopCompares: def __eq__(self, other): raise DoNotTestEq - + checkfirst = self.type2test([1, StopCompares()]) self.assert_(1 in checkfirst) checklast = self.type2test([StopCompares(), 1]) Index: test_generators.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_generators.py,v retrieving revision 1.47 retrieving revision 1.48 diff -u -d -r1.47 -r1.48 --- test_generators.py 24 Aug 2005 09:02:29 -0000 1.47 +++ test_generators.py 26 Aug 2005 15:20:48 -0000 1.48 @@ -709,18 +709,18 @@ Ye olde Fibonacci generator, tee style. >>> def fib(): -... +... ... def _isum(g, h): ... while 1: ... yield g.next() + h.next() -... +... ... def _fib(): ... yield 1 ... yield 2 ... fibTail.next() # throw first away ... for res in _isum(fibHead, fibTail): ... yield res -... +... ... fibHead, fibTail, fibRes = tee(_fib(), 3) ... return fibRes Index: test_hashlib_speed.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_hashlib_speed.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- test_hashlib_speed.py 21 Aug 2005 18:46:01 -0000 1.1 +++ test_hashlib_speed.py 26 Aug 2005 15:20:48 -0000 1.2 @@ -90,4 +90,3 @@ test_scaled_msg(scale=106, name='[small data]') test_scaled_msg(scale=creatorFunc().digest_size, name='[digest_size data]') test_scaled_msg(scale=10, name='[tiny data]') - Index: test_mmap.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_mmap.py,v retrieving revision 1.33 retrieving revision 1.34 diff -u -d -r1.33 -r1.34 --- test_mmap.py 24 Aug 2005 07:17:40 -0000 1.33 +++ test_mmap.py 26 Aug 2005 15:20:48 -0000 1.34 @@ -126,7 +126,7 @@ f.seek(0, 2) verify(f.tell() == 512, 'Underlying file not truncated') f.close() - verify(m.size() == 512, 'New size not reflected in file') + verify(m.size() == 512, 'New size not reflected in file') m.close() From tim_one at users.sourceforge.net Fri Aug 26 17:20:58 2005 From: tim_one at users.sourceforge.net (tim_one@users.sourceforge.net) Date: Fri, 26 Aug 2005 17:20:58 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Tools/scripts findnocoding.py, 1.1, 1.2 pysource.py, 1.1, 1.2 Message-ID: <20050826152058.E34991E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Tools/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv805/Tools/scripts Modified Files: findnocoding.py pysource.py Log Message: Whitespace normalization (via reindent.py). Index: findnocoding.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Tools/scripts/findnocoding.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- findnocoding.py 24 Aug 2005 18:28:41 -0000 1.1 +++ findnocoding.py 26 Aug 2005 15:20:48 -0000 1.2 @@ -26,8 +26,8 @@ if filename.endswith(".py"): yield os.path.join(root, filename) pysource = pysource() - - + + print >>sys.stderr, ("The pysource module is not available; " "no sophisticated Python source file search will be done.") @@ -56,19 +56,19 @@ line1 = infile.readline() line2 = infile.readline() - + if get_declaration(line1) or get_declaration(line2): # the file does have an encoding declaration, so trust it infile.close() return False - + # check the whole file for non-ASCII characters rest = infile.read() infile.close() - + if has_correct_encoding(line1+line2+rest, "ascii"): return False - + return True @@ -102,5 +102,3 @@ result = needs_declaration(fullpath) if result: print fullpath - - Index: pysource.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Tools/scripts/pysource.py,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- pysource.py 24 Aug 2005 18:28:41 -0000 1.1 +++ pysource.py 26 Aug 2005 15:20:48 -0000 1.2 @@ -57,12 +57,12 @@ line = infile.readline() infile.close() - + if binary_re.search(line): # file appears to be binary print_debug("%s: appears to be binary" % fullpath) return False - + if fullpath.endswith(".py") or fullpath.endswith(".pyw"): return True elif "python" in line: @@ -95,12 +95,12 @@ paths: a list of files and/or directories to be checked. is_python: a function that takes a file name and checks whether it is a Python source file - exclude_dirs: a list of directory base names that should be excluded in + exclude_dirs: a list of directory base names that should be excluded in the search """ if exclude_dirs is None: exclude_dirs=[] - + for path in paths: print_debug("testing: %s" % path) if os.path.isfile(path): From loewis at users.sourceforge.net Sat Aug 27 12:08:07 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sat, 27 Aug 2005 12:08:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib tarfile.py,1.31,1.32 Message-ID: <20050827100807.37A761E400C@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29364/Lib Modified Files: tarfile.py Log Message: Patch #1168594: set sizes of non-regular files to zero. Fixes #1167128. Will backport to 2.4. Index: tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/tarfile.py,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- tarfile.py 24 Aug 2005 06:43:09 -0000 1.31 +++ tarfile.py 27 Aug 2005 10:07:56 -0000 1.32 @@ -1179,17 +1179,16 @@ # Fill the TarInfo object with all # information we can get. - tarinfo.name = arcname - tarinfo.mode = stmd - tarinfo.uid = statres.st_uid - tarinfo.gid = statres.st_gid - if stat.S_ISDIR(stmd): - # For a directory, the size must be 0 - tarinfo.size = 0 - else: + tarinfo.name = arcname + tarinfo.mode = stmd + tarinfo.uid = statres.st_uid + tarinfo.gid = statres.st_gid + if stat.S_ISREG(stmd): tarinfo.size = statres.st_size + else: + tarinfo.size = 0L tarinfo.mtime = statres.st_mtime - tarinfo.type = type + tarinfo.type = type tarinfo.linkname = linkname if pwd: try: @@ -1280,16 +1279,15 @@ self.addfile(tarinfo, f) f.close() - if tarinfo.type in (LNKTYPE, SYMTYPE, FIFOTYPE, CHRTYPE, BLKTYPE): - tarinfo.size = 0L - self.addfile(tarinfo) - - if tarinfo.isdir(): + elif tarinfo.isdir(): self.addfile(tarinfo) if recursive: for f in os.listdir(name): self.add(os.path.join(name, f), os.path.join(arcname, f)) + else: + self.addfile(tarinfo) + def addfile(self, tarinfo, fileobj=None): """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is given, tarinfo.size bytes are read from it and added to the archive. From loewis at users.sourceforge.net Sat Aug 27 12:08:07 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sat, 27 Aug 2005 12:08:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1356,1.1357 Message-ID: <20050827100807.35D281E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29364/Misc Modified Files: NEWS Log Message: Patch #1168594: set sizes of non-regular files to zero. Fixes #1167128. Will backport to 2.4. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1356 retrieving revision 1.1357 diff -u -d -r1.1356 -r1.1357 --- NEWS 26 Aug 2005 08:51:34 -0000 1.1356 +++ NEWS 27 Aug 2005 10:07:56 -0000 1.1357 @@ -204,6 +204,8 @@ Library ------- +- Bug #1167128: Fix size of a symlink in a tarfile to be 0. + - Patch #810023: Fix off-by-one bug in urllib.urlretrieve reporthook functionality. From loewis at users.sourceforge.net Sat Aug 27 12:08:07 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sat, 27 Aug 2005 12:08:07 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_tarfile.py, 1.18, 1.19 Message-ID: <20050827100807.40AAB1E400D@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29364/Lib/test Modified Files: test_tarfile.py Log Message: Patch #1168594: set sizes of non-regular files to zero. Fixes #1167128. Will backport to 2.4. Index: test_tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_tarfile.py,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- test_tarfile.py 5 Mar 2005 12:47:42 -0000 1.18 +++ test_tarfile.py 27 Aug 2005 10:07:56 -0000 1.19 @@ -230,6 +230,40 @@ else: self.dst.addfile(tarinfo, f) +class WriteSize0Test(BaseTest): + mode = 'w' + + def setUp(self): + self.tmpdir = dirname() + self.dstname = tmpname() + self.dst = tarfile.open(self.dstname, "w") + + def tearDown(self): + self.dst.close() + + def test_file(self): + path = os.path.join(self.tmpdir, "file") + file(path, "w") + tarinfo = self.dst.gettarinfo(path) + self.assertEqual(tarinfo.size, 0) + file(path, "w").write("aaa") + tarinfo = self.dst.gettarinfo(path) + self.assertEqual(tarinfo.size, 3) + + def test_directory(self): + path = os.path.join(self.tmpdir, "directory") + os.mkdir(path) + tarinfo = self.dst.gettarinfo(path) + self.assertEqual(tarinfo.size, 0) + + def test_symlink(self): + if hasattr(os, "symlink"): + path = os.path.join(self.tmpdir, "symlink") + os.symlink("link_target", path) + tarinfo = self.dst.gettarinfo(path) + self.assertEqual(tarinfo.size, 0) + + class WriteStreamTest(WriteTest): sep = '|' @@ -399,6 +433,7 @@ ReadAsteriskTest, ReadStreamAsteriskTest, WriteTest, + WriteSize0Test, WriteStreamTest, WriteGNULongTest, ] From loewis at users.sourceforge.net Sat Aug 27 12:08:31 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sat, 27 Aug 2005 12:08:31 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_tarfile.py, 1.16, 1.16.2.1 Message-ID: <20050827100831.EA7611E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29574/Lib/test Modified Files: Tag: release24-maint test_tarfile.py Log Message: Patch #1168594: set sizes of non-regular files to zero. Fixes #1167128. Index: test_tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_tarfile.py,v retrieving revision 1.16 retrieving revision 1.16.2.1 diff -u -d -r1.16 -r1.16.2.1 --- test_tarfile.py 25 Oct 2004 03:19:41 -0000 1.16 +++ test_tarfile.py 27 Aug 2005 10:08:21 -0000 1.16.2.1 @@ -208,6 +208,40 @@ else: self.dst.addfile(tarinfo, f) +class WriteSize0Test(BaseTest): + mode = 'w' + + def setUp(self): + self.tmpdir = dirname() + self.dstname = tmpname() + self.dst = tarfile.open(self.dstname, "w") + + def tearDown(self): + self.dst.close() + + def test_file(self): + path = os.path.join(self.tmpdir, "file") + file(path, "w") + tarinfo = self.dst.gettarinfo(path) + self.assertEqual(tarinfo.size, 0) + file(path, "w").write("aaa") + tarinfo = self.dst.gettarinfo(path) + self.assertEqual(tarinfo.size, 3) + + def test_directory(self): + path = os.path.join(self.tmpdir, "directory") + os.mkdir(path) + tarinfo = self.dst.gettarinfo(path) + self.assertEqual(tarinfo.size, 0) + + def test_symlink(self): + if hasattr(os, "symlink"): + path = os.path.join(self.tmpdir, "symlink") + os.symlink("link_target", path) + tarinfo = self.dst.gettarinfo(path) + self.assertEqual(tarinfo.size, 0) + + class WriteStreamTest(WriteTest): sep = '|' @@ -366,6 +400,7 @@ ReadTest, ReadStreamTest, WriteTest, + WriteSize0Test, WriteStreamTest, WriteGNULongTest, ] From loewis at users.sourceforge.net Sat Aug 27 12:08:32 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sat, 27 Aug 2005 12:08:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.89, 1.1193.2.90 Message-ID: <20050827100832.257241E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29574/Misc Modified Files: Tag: release24-maint NEWS Log Message: Patch #1168594: set sizes of non-regular files to zero. Fixes #1167128. Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.89 retrieving revision 1.1193.2.90 diff -u -d -r1.1193.2.89 -r1.1193.2.90 --- NEWS 26 Aug 2005 08:51:39 -0000 1.1193.2.89 +++ NEWS 27 Aug 2005 10:08:21 -0000 1.1193.2.90 @@ -79,6 +79,8 @@ Library ------- +- Bug #1167128: Fix size of a symlink in a tarfile to be 0. + - Patch #810023: Fix off-by-one bug in urllib.urlretrieve reporthook functionality. From loewis at users.sourceforge.net Sat Aug 27 12:08:32 2005 From: loewis at users.sourceforge.net (loewis@users.sourceforge.net) Date: Sat, 27 Aug 2005 12:08:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib tarfile.py, 1.21.2.4, 1.21.2.5 Message-ID: <20050827100832.5F54A1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29574/Lib Modified Files: Tag: release24-maint tarfile.py Log Message: Patch #1168594: set sizes of non-regular files to zero. Fixes #1167128. Index: tarfile.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/tarfile.py,v retrieving revision 1.21.2.4 retrieving revision 1.21.2.5 diff -u -d -r1.21.2.4 -r1.21.2.5 --- tarfile.py 24 Aug 2005 06:44:55 -0000 1.21.2.4 +++ tarfile.py 27 Aug 2005 10:08:21 -0000 1.21.2.5 @@ -1132,17 +1132,16 @@ # Fill the TarInfo object with all # information we can get. - tarinfo.name = arcname - tarinfo.mode = stmd - tarinfo.uid = statres.st_uid - tarinfo.gid = statres.st_gid - if stat.S_ISDIR(stmd): - # For a directory, the size must be 0 - tarinfo.size = 0 - else: + tarinfo.name = arcname + tarinfo.mode = stmd + tarinfo.uid = statres.st_uid + tarinfo.gid = statres.st_gid + if stat.S_ISREG(stmd): tarinfo.size = statres.st_size + else: + tarinfo.size = 0L tarinfo.mtime = statres.st_mtime - tarinfo.type = type + tarinfo.type = type tarinfo.linkname = linkname if pwd: try: @@ -1233,16 +1232,15 @@ self.addfile(tarinfo, f) f.close() - if tarinfo.type in (LNKTYPE, SYMTYPE, FIFOTYPE, CHRTYPE, BLKTYPE): - tarinfo.size = 0L - self.addfile(tarinfo) - - if tarinfo.isdir(): + elif tarinfo.isdir(): self.addfile(tarinfo) if recursive: for f in os.listdir(name): self.add(os.path.join(name, f), os.path.join(arcname, f)) + else: + self.addfile(tarinfo) + def addfile(self, tarinfo, fileobj=None): """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is given, tarinfo.size bytes are read from it and added to the archive. From birkenfeld at users.sourceforge.net Sat Aug 27 19:05:10 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sat, 27 Aug 2005 19:05:10 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/dist dist.tex,1.96,1.97 Message-ID: <20050827170510.9D8FB1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/dist In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8677/Doc/dist Modified Files: dist.tex Log Message: patch [ 1274630 ] documentation fixes Index: dist.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/dist/dist.tex,v retrieving revision 1.96 retrieving revision 1.97 diff -u -d -r1.96 -r1.97 --- dist.tex 22 Jul 2005 21:49:26 -0000 1.96 +++ dist.tex 27 Aug 2005 17:04:59 -0000 1.97 @@ -1754,7 +1754,7 @@ the \command{upload} command are uploaded. The \command{upload} command uses the username and password stored in -in the file \file{\$HOME/.pypirc}, see section~\ref{pypirc}. +the file \file{\$HOME/.pypirc}, see section~\ref{pypirc}. \chapter{Examples} \label{examples} From birkenfeld at users.sourceforge.net Sat Aug 27 19:05:10 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sat, 27 Aug 2005 19:05:10 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libhttplib.tex, 1.39, 1.40 libgrp.tex, 1.16, 1.17 libspwd.tex, 1.1, 1.2 Message-ID: <20050827170510.C520C1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8677/Doc/lib Modified Files: libhttplib.tex libgrp.tex libspwd.tex Log Message: patch [ 1274630 ] documentation fixes Index: libhttplib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libhttplib.tex,v retrieving revision 1.39 retrieving revision 1.40 diff -u -d -r1.39 -r1.40 --- libhttplib.tex 25 Jun 2005 19:15:48 -0000 1.39 +++ libhttplib.tex 27 Aug 2005 17:04:59 -0000 1.40 @@ -146,7 +146,7 @@ {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1.2}} \lineiii{PROCESSING}{\code{102}} {WEBDAV, \ulink{RFC 2518, Section 10.1} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_102}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_102}} \lineiii{OK}{\code{200}} {HTTP/1.1, \ulink{RFC 2616, Section 10.2.1} @@ -171,7 +171,7 @@ {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.7}} \lineiii{MULTI_STATUS}{\code{207}} {WEBDAV \ulink{RFC 2518, Section 10.2} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_207}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_207}} \lineiii{IM_USED}{\code{226}} {Delta encoding in HTTP, \rfc{3229}, Section 10.4.1} @@ -253,13 +253,13 @@ {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.18}} \lineiii{UNPROCESSABLE_ENTITY}{\code{422}} {WEBDAV, \ulink{RFC 2518, Section 10.3} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_422}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_422}} \lineiii{LOCKED}{\code{423}} {WEBDAV \ulink{RFC 2518, Section 10.4} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_423}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_423}} \lineiii{FAILED_DEPENDENCY}{\code{424}} {WEBDAV, \ulink{RFC 2518, Section 10.5} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_424}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_424}} \lineiii{UPGRADE_REQUIRED}{\code{426}} {HTTP Upgrade to TLS, \rfc{2817}, Section 6} @@ -283,7 +283,7 @@ {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.6}} \lineiii{INSUFFICIENT_STORAGE}{\code{507}} {WEBDAV, \ulink{RFC 2518, Section 10.6} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_507}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_507}} \lineiii{NOT_EXTENDED}{\code{510}} {An HTTP Extension Framework, \rfc{2774}, Section 7} \end{tableiii} Index: libgrp.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libgrp.tex,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- libgrp.tex 1 Mar 2002 10:38:44 -0000 1.16 +++ libgrp.tex 27 Aug 2005 17:04:59 -0000 1.17 @@ -45,4 +45,5 @@ \begin{seealso} \seemodule{pwd}{An interface to the user database, similar to this.} + \seemodule{spwd}{An interface to the shadow password database, similar to this.} \end{seealso} Index: libspwd.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libspwd.tex,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- libspwd.tex 23 Jan 2005 09:27:23 -0000 1.1 +++ libspwd.tex 27 Aug 2005 17:04:59 -0000 1.2 @@ -4,9 +4,10 @@ \declaremodule{builtin}{spwd} \platform{Unix} \modulesynopsis{The shadow password database (\function{getspnam()} and friends).} +\versionadded{2.5} This module provides access to the \UNIX{} shadow password database. -It is available on various Unix versions. +It is available on various \UNIX{} versions. You must have enough privileges to access the shadow password database (this usually means you have to be root). @@ -42,5 +43,6 @@ \begin{seealso} + \seemodule{grp}{An interface to the group database, similar to this.} \seemodule{pwd}{An interface to the normal password database, similar to this.} \end{seealso} From birkenfeld at users.sourceforge.net Sat Aug 27 19:05:53 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sat, 27 Aug 2005 19:05:53 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libhttplib.tex, 1.38.2.1, 1.38.2.2 Message-ID: <20050827170553.97E5E1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9212/Doc/lib Modified Files: Tag: release24-maint libhttplib.tex Log Message: patch [ 1274630 ] documentation fixes Index: libhttplib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libhttplib.tex,v retrieving revision 1.38.2.1 retrieving revision 1.38.2.2 diff -u -d -r1.38.2.1 -r1.38.2.2 --- libhttplib.tex 25 Jun 2005 19:16:58 -0000 1.38.2.1 +++ libhttplib.tex 27 Aug 2005 17:05:43 -0000 1.38.2.2 @@ -146,7 +146,7 @@ {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.1.2}} \lineiii{PROCESSING}{\code{102}} {WEBDAV, \ulink{RFC 2518, Section 10.1} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_102}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_102}} \lineiii{OK}{\code{200}} {HTTP/1.1, \ulink{RFC 2616, Section 10.2.1} @@ -171,7 +171,7 @@ {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.7}} \lineiii{MULTI_STATUS}{\code{207}} {WEBDAV \ulink{RFC 2518, Section 10.2} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_207}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_207}} \lineiii{IM_USED}{\code{226}} {Delta encoding in HTTP, \rfc{3229}, Section 10.4.1} @@ -253,13 +253,13 @@ {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.18}} \lineiii{UNPROCESSABLE_ENTITY}{\code{422}} {WEBDAV, \ulink{RFC 2518, Section 10.3} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_422}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_422}} \lineiii{LOCKED}{\code{423}} {WEBDAV \ulink{RFC 2518, Section 10.4} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_423}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_423}} \lineiii{FAILED_DEPENDENCY}{\code{424}} {WEBDAV, \ulink{RFC 2518, Section 10.5} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_424}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_424}} \lineiii{UPGRADE_REQUIRED}{\code{426}} {HTTP Upgrade to TLS, \rfc{2817}, Section 6} @@ -283,7 +283,7 @@ {http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.5.6}} \lineiii{INSUFFICIENT_STORAGE}{\code{507}} {WEBDAV, \ulink{RFC 2518, Section 10.6} - {http://www.webdav.org/specs/rfc2518.htm#STATUS_507}} + {http://www.webdav.org/specs/rfc2518.html#STATUS_507}} \lineiii{NOT_EXTENDED}{\code{510}} {An HTTP Extension Framework, \rfc{2774}, Section 7} \end{tableiii} From birkenfeld at users.sourceforge.net Sat Aug 27 19:10:45 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sat, 27 Aug 2005 19:10:45 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libtarfile.tex, 1.10, 1.11 Message-ID: <20050827171045.6E79E1E4003@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10553/Doc/lib Modified Files: libtarfile.tex Log Message: patch [ 1274550 ] libtarfile.tex: external URL changed Index: libtarfile.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libtarfile.tex,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- libtarfile.tex 12 Jul 2005 07:28:20 -0000 1.10 +++ libtarfile.tex 27 Aug 2005 17:10:35 -0000 1.11 @@ -128,8 +128,8 @@ \seemodule{zipfile}{Documentation of the \refmodule{zipfile} standard module.} - \seetitle[http://www.gnu.org/manual/tar/html_chapter/tar_8.html\#SEC118] - {GNU tar manual, Standard Section}{Documentation for tar archive files, + \seetitle[http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html\#SEC134] + {GNU tar manual, Basic Tar Format}{Documentation for tar archive files, including GNU tar extensions.} \end{seealso} From birkenfeld at users.sourceforge.net Sat Aug 27 19:10:49 2005 From: birkenfeld at users.sourceforge.net (birkenfeld@users.sourceforge.net) Date: Sat, 27 Aug 2005 19:10:49 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libtarfile.tex, 1.7.2.1, 1.7.2.2 Message-ID: <20050827171049.44A161E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10563/Doc/lib Modified Files: Tag: release24-maint libtarfile.tex Log Message: patch [ 1274550 ] libtarfile.tex: external URL changed Index: libtarfile.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libtarfile.tex,v retrieving revision 1.7.2.1 retrieving revision 1.7.2.2 diff -u -d -r1.7.2.1 -r1.7.2.2 --- libtarfile.tex 12 Jul 2005 07:28:25 -0000 1.7.2.1 +++ libtarfile.tex 27 Aug 2005 17:10:38 -0000 1.7.2.2 @@ -127,8 +127,8 @@ \seemodule{zipfile}{Documentation of the \refmodule{zipfile} standard module.} - \seetitle[http://www.gnu.org/manual/tar/html_chapter/tar_8.html\#SEC118] - {GNU tar manual, Standard Section}{Documentation for tar archive files, + \seetitle[http://www.gnu.org/software/tar/manual/html_chapter/tar_8.html\#SEC134] + {GNU tar manual, Basic Tar Format}{Documentation for tar archive files, including GNU tar extensions.} \end{seealso} From bcannon at users.sourceforge.net Sat Aug 27 20:27:44 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Sat, 27 Aug 2005 20:27:44 +0200 (CEST) Subject: [Python-checkins] python/nondist/peps pep-3000.txt,1.18,1.19 Message-ID: <20050827182744.7FF6B1E4003@bag.python.org> Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25340 Modified Files: pep-3000.txt Log Message: Create new "Atomic Types" section and add mention of removal of basestring.find and friends. Index: pep-3000.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-3000.txt,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- pep-3000.txt 6 Aug 2005 23:13:59 -0000 1.18 +++ pep-3000.txt 27 Aug 2005 18:27:33 -0000 1.19 @@ -73,8 +73,8 @@ * Unbound methods [7]_ -Built-ins -========= +Built-in Namespace +================== * Make built-ins return an iterator where appropriate (e.g. ``range()``, ``zip()``, etc.) @@ -100,6 +100,15 @@ * ``xrange()``: use ``range()`` instead [1]_ +Atomic Types +============ + +To be removed: + +* ``basestring.find()`` and ``basestring.rfind()``; use ``basestring.index()`` + or ``basestring.rindex()`` in a try/except block [15]_ + + Standard library ================ @@ -155,7 +164,10 @@ http://mail.python.org/pipermail/python-dev/2005-April/053060.html .. [14] python-dev email ("PEP 8: exception style") - http://mail.python.org/pipermail/python-dev/2005-August/055190.html + http://mail.python.org/pipermail/python-dev/2005-August/055190.html + +.. [15] python-dev email (Remove str.find in 3.0?) + http://mail.python.org/pipermail/python-dev/2005-August/055705.html Copyright From akuchling at users.sourceforge.net Sat Aug 27 20:45:58 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Sat, 27 Aug 2005 20:45:58 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew25.tex, 1.18, 1.19 Message-ID: <20050827184558.6A9981E401F@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29055 Modified Files: whatsnew25.tex Log Message: Write section on PEP 342 Index: whatsnew25.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew25.tex,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- whatsnew25.tex 23 Aug 2005 00:56:06 -0000 1.18 +++ whatsnew25.tex 27 Aug 2005 18:45:47 -0000 1.19 @@ -117,12 +117,10 @@ As introduced in Python 2.3, generators only produce output; once a generator's code was invoked to create an iterator, there's no way to pass new parameters into the function when its execution is resumed. -(Well, you could make the generator's code look at a global -variable and modify the global value, but this is an unreliable hack -that doesn't work if you have multiple instances of the same generator -alive at the same time.) - -Python 2.5 adds the ability to pass values \emph{into} a generator. +Hackish solutions to this include making the generator's code look at +a global variable and then changing the global variable's value, or +passing in some mutable object that callers then modify. Python +2.5 adds the ability to pass values \emph{into} a generator. To refresh your memory of basic generators, here's a simple example: @@ -134,16 +132,120 @@ i += 1 \end{verbatim} -On executing the \ -When you call \code{counter(10)}, the result is an +When you call \code{counter(10)}, the result is an iterator that +returns the values from 0 up to 9. On encountering the +\keyword{yield} statement, the iterator returns the provided value and +suspends the function's execution, preserving the local variables. +Execution resumes on the following call to the iterator's +\method{next()} method, picking up after the \keyword{yield}. -XXX write this section +In Python 2.3, \keyword{yield} was a statement; it didn't return any +value. In 2.5, \keyword{yield} is now an expression, returning a +value that can be assigned to a variable or otherwise operated on: + +\begin{verbatim} +val = (yield i) +\end{verbatim} + +I recommend that you always put parentheses around a \keyword{yield} +expression when you're doing something with the returned value, as in +the above example. The parentheses aren't always necessary, but it's +easier to always add them instead of having to remember when they're +needed. The exact rules are that a \keyword{yield}-expression must +always be parenthesized except when it occurs at the top-level +expression on the right-hand side of an assignment, meaning +you can to write \code{val = yield i} but \code{val = (yield i) + 12}. + +Values are sent into a generator by calling its +\method{send(\var{value})} method. The generator's code is then +resumed and the \keyword{yield} expression produces \var{value}. +If the regular \method{next()} method is called, the \keyword{yield} +returns \constant{None}. + +Here's the previous example, modified to allow changing the value of +the internal counter. + +\begin{verbatim} +def counter (maximum): + i = 0 + while i < maximum: + val = (yield i) + # If value provided, change counter + if val is not None: + i = val + else: + i += 1 +\end{verbatim} + +And here's an example of changing the counter: + +\begin{verbatim} +>>> it = counter(10) +>>> print it.next() +0 +>>> print it.next() +1 +>>> print it.send(8) +8 +>>> print it.next() +9 +>>> print it.next() +Traceback (most recent call last): + File ``t.py'', line 15, in ? + print it.next() +StopIteration +Because \keyword{yield} will often be returning \constant{None}, +you shouldn't just use its value in expressions unless you're sure +that only the \method{send()} method will be used. + +There are two other new methods on generators in addition to +\method{send()}: + +\begin{itemize} + + \item \method{throw(\var{type}, \var{value}=None, + \var{traceback}=None)} is used to raise an exception inside the + generator; the exception is raised by the \keyword{yield} expression + where the generator's execution is paused. + + \item \method{close()} raises a new \exception{GeneratorExit} + exception inside the generator to terminate the iteration. + On receiving this + exception, the generator's code must either raise + \exception{GeneratorExit} or \exception{StopIteration}; catching the + exception and doing anything else is illegal and will trigger + a \exception{RuntimeError}. \method{close()} will also be called by + Python's garbage collection when the generator is garbage-collected. + + If you need to run cleanup code in case of a \exception{GeneratorExit}, + I suggest using a \code{try: ... finally:} suite instead of + catching \exception{GeneratorExit}. + +\end{itemize} + +The cumulative effect of these changes is to turn generators from +one-way producers of information into both producers and consumers. +Generators also become \emph{coroutines}, a more generalized form of +subroutines; subroutines are entered at one point and exited at +another point (the top of the function, and a \keyword{return +statement}), but coroutines can be entered, exited, and resumed at +many different points (the \keyword{yield} statements).science term + + \begin{seealso} \seepep{342}{Coroutines via Enhanced Generators}{PEP written by Guido van Rossum and Phillip J. Eby; -implemented by Phillip J. Eby.} +implemented by Phillip J. Eby. Includes examples of +some fancier uses of generators as coroutines.} + +\seeurl{http://en.wikipedia.org/wiki/Coroutine}{The Wikipedia entry for +coroutines.} + +\seeurl{http://www.sidhe.org/~dan/blog/archives/000178.html}{An +explanation of coroutines from a Perl point of view, written by Dan +Sugalski.} \end{seealso} From bcannon at users.sourceforge.net Sat Aug 27 21:26:09 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Sat, 27 Aug 2005 21:26:09 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib _strptime.py,1.38,1.39 Message-ID: <20050827192609.635F81E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4749/Lib Modified Files: _strptime.py Log Message: fix bug where str.find() was being misused where __contains__ should have been used. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- _strptime.py 28 Oct 2004 04:49:19 -0000 1.38 +++ _strptime.py 27 Aug 2005 19:25:59 -0000 1.39 @@ -148,7 +148,7 @@ if old: current_format = current_format.replace(old, new) time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0)) - if time.strftime(directive, time_tuple).find('00'): + if '00' in time.strftime(directive, time_tuple): U_W = '%U' else: U_W = '%W' From bcannon at users.sourceforge.net Sat Aug 27 21:29:32 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Sat, 27 Aug 2005 21:29:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.90, 1.1193.2.91 Message-ID: <20050827192932.49A7D1E4006@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5059/Misc Modified Files: Tag: release24-maint NEWS Log Message: Fix bug where __contains__ should have been used over str.find() Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.90 retrieving revision 1.1193.2.91 diff -u -d -r1.1193.2.90 -r1.1193.2.91 --- NEWS 27 Aug 2005 10:08:21 -0000 1.1193.2.90 +++ NEWS 27 Aug 2005 19:29:21 -0000 1.1193.2.91 @@ -79,6 +79,9 @@ Library ------- +- Fix a misuse of str.find() in detection of use of %U or %W in datetime + format. + - Bug #1167128: Fix size of a symlink in a tarfile to be 0. - Patch #810023: Fix off-by-one bug in urllib.urlretrieve reporthook From bcannon at users.sourceforge.net Sat Aug 27 21:29:32 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Sat, 27 Aug 2005 21:29:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib _strptime.py,1.38,1.38.2.1 Message-ID: <20050827192932.2D7D71E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5059/Lib Modified Files: Tag: release24-maint _strptime.py Log Message: Fix bug where __contains__ should have been used over str.find() Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.38 retrieving revision 1.38.2.1 diff -u -d -r1.38 -r1.38.2.1 --- _strptime.py 28 Oct 2004 04:49:19 -0000 1.38 +++ _strptime.py 27 Aug 2005 19:29:21 -0000 1.38.2.1 @@ -148,7 +148,7 @@ if old: current_format = current_format.replace(old, new) time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0)) - if time.strftime(directive, time_tuple).find('00'): + if '00' in time.strftime(directive, time_tuple): U_W = '%U' else: U_W = '%W' From akuchling at users.sourceforge.net Mon Aug 29 15:30:23 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Mon, 29 Aug 2005 15:30:23 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/whatsnew whatsnew25.tex, 1.19, 1.20 Message-ID: <20050829133023.AE6D31E400A@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/whatsnew In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29447 Modified Files: whatsnew25.tex Log Message: Add missing \end, noted by George Yoshida Index: whatsnew25.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/whatsnew/whatsnew25.tex,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- whatsnew25.tex 27 Aug 2005 18:45:47 -0000 1.19 +++ whatsnew25.tex 29 Aug 2005 13:30:12 -0000 1.20 @@ -194,6 +194,7 @@ File ``t.py'', line 15, in ? print it.next() StopIteration +\end{verbatim} Because \keyword{yield} will often be returning \constant{None}, you shouldn't just use its value in expressions unless you're sure From bcannon at users.sourceforge.net Mon Aug 29 20:26:06 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon, 29 Aug 2005 20:26:06 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib _strptime.py,1.39,1.40 Message-ID: <20050829182606.F0A031E406E@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5661/Lib Modified Files: _strptime.py Log Message: Fix logic error introduced in last commit. Also add a comment to explain what the code is doing. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.39 retrieving revision 1.40 diff -u -d -r1.39 -r1.40 --- _strptime.py 27 Aug 2005 19:25:59 -0000 1.39 +++ _strptime.py 29 Aug 2005 18:25:55 -0000 1.40 @@ -147,11 +147,14 @@ # strings (e.g., MacOS 9 having timezone as ('','')). if old: current_format = current_format.replace(old, new) + # If %W is used, then Sunday, 2005-01-03 will fall on week 0 since + # 2005-01-03 occurs before the first Monday of the year. Otherwise + # %U is used. time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0)) if '00' in time.strftime(directive, time_tuple): - U_W = '%U' - else: U_W = '%W' + else: + U_W = '%U' date_time[offset] = current_format.replace('11', U_W) self.LC_date_time = date_time[0] self.LC_date = date_time[1] From bcannon at users.sourceforge.net Mon Aug 29 20:26:59 2005 From: bcannon at users.sourceforge.net (bcannon@users.sourceforge.net) Date: Mon, 29 Aug 2005 20:26:59 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib _strptime.py, 1.38.2.1, 1.38.2.2 Message-ID: <20050829182659.80EA21E42FA@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5944/Lib Modified Files: Tag: release24-maint _strptime.py Log Message: Fix logic error introduced in last commit. Index: _strptime.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/_strptime.py,v retrieving revision 1.38.2.1 retrieving revision 1.38.2.2 diff -u -d -r1.38.2.1 -r1.38.2.2 --- _strptime.py 27 Aug 2005 19:29:21 -0000 1.38.2.1 +++ _strptime.py 29 Aug 2005 18:26:48 -0000 1.38.2.2 @@ -149,9 +149,9 @@ current_format = current_format.replace(old, new) time_tuple = time.struct_time((1999,1,3,1,1,1,6,3,0)) if '00' in time.strftime(directive, time_tuple): - U_W = '%U' - else: U_W = '%W' + else: + U_W = '%U' date_time[offset] = current_format.replace('11', U_W) self.LC_date_time = date_time[0] self.LC_date = date_time[1] From akuchling at users.sourceforge.net Tue Aug 30 03:21:37 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue, 30 Aug 2005 03:21:37 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/howto - New directory Message-ID: <20050830012137.ECC721E400A@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/howto In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31779/howto Log Message: Directory /cvsroot/python/python/dist/src/Doc/howto added to the repository From akuchling at users.sourceforge.net Tue Aug 30 03:25:18 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue, 30 Aug 2005 03:25:18 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/howto Makefile, NONE, 1.1 advocacy.tex, NONE, 1.1 curses.tex, NONE, 1.1 doanddont.tex, NONE, 1.1 regex.tex, NONE, 1.1 rexec.tex, NONE, 1.1 sockets.tex, NONE, 1.1 sorting.tex, NONE, 1.1 unicode.rst, NONE, 1.1 Message-ID: <20050830012518.006261E400A@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/howto In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32499 Added Files: Makefile advocacy.tex curses.tex doanddont.tex regex.tex rexec.tex sockets.tex sorting.tex unicode.rst Log Message: Commit the howto source to the main Python repository, with Fred's approval --- NEW FILE: Makefile --- MKHOWTO=../tools/mkhowto WEBDIR=. RSTARGS = --input-encoding=utf-8 VPATH=.:dvi:pdf:ps:txt # List of HOWTOs that aren't to be processed REMOVE_HOWTO = # Determine list of files to be built HOWTO=$(filter-out $(REMOVE_HOWTO),$(wildcard *.tex)) RST_SOURCES = $(shell echo *.rst) DVI =$(patsubst %.tex,%.dvi,$(HOWTO)) PDF =$(patsubst %.tex,%.pdf,$(HOWTO)) PS =$(patsubst %.tex,%.ps,$(HOWTO)) TXT =$(patsubst %.tex,%.txt,$(HOWTO)) HTML =$(patsubst %.tex,%,$(HOWTO)) # Rules for building various formats %.dvi : %.tex $(MKHOWTO) --dvi $< mv $@ dvi %.pdf : %.tex $(MKHOWTO) --pdf $< mv $@ pdf %.ps : %.tex $(MKHOWTO) --ps $< mv $@ ps %.txt : %.tex $(MKHOWTO) --text $< mv $@ txt % : %.tex $(MKHOWTO) --html --iconserver="." $< tar -zcvf html/$*.tgz $* #zip -r html/$*.zip $* default: @echo "'all' -- build all files" @echo "'dvi', 'pdf', 'ps', 'txt', 'html' -- build one format" all: $(HTML) .PHONY : dvi pdf ps txt html rst dvi: $(DVI) pdf: $(PDF) ps: $(PS) txt: $(TXT) html:$(HTML) # Rule to build collected tar files dist: #all for i in dvi pdf ps txt ; do \ cd $$i ; \ tar -zcf All.tgz *.$$i ;\ cd .. ;\ done # Rule to copy files to the Web tree on AMK's machine web: dist cp dvi/* $(WEBDIR)/dvi cp ps/* $(WEBDIR)/ps cp pdf/* $(WEBDIR)/pdf cp txt/* $(WEBDIR)/txt for dir in $(HTML) ; do cp -rp $$dir $(WEBDIR) ; done for ltx in $(HOWTO) ; do cp -p $$ltx $(WEBDIR)/latex ; done rst: unicode.html %.html: %.rst rst2html $(RSTARGS) $< >$@ clean: rm -f *~ *.log *.ind *.l2h *.aux *.toc *.how rm -f *.dvi *.ps *.pdf *.bkm rm -f unicode.html clobber: rm dvi/* ps/* pdf/* txt/* html/* --- NEW FILE: advocacy.tex --- \documentclass{howto} \title{Python Advocacy HOWTO} \release{0.03} \author{A.M. Kuchling} \authoraddress{\email{amk at amk.ca}} \begin{document} \maketitle \begin{abstract} \noindent It's usually difficult to get your management to accept open source software, and Python is no exception to this rule. This document discusses reasons to use Python, strategies for winning acceptance, facts and arguments you can use, and cases where you \emph{shouldn't} try to use Python. This document is available from the Python HOWTO page at \url{http://www.python.org/doc/howto}. \end{abstract} \tableofcontents \section{Reasons to Use Python} There are several reasons to incorporate a scripting language into your development process, and this section will discuss them, and why Python has some properties that make it a particularly good choice. \subsection{Programmability} Programs are often organized in a modular fashion. Lower-level operations are grouped together, and called by higher-level functions, which may in turn be used as basic operations by still further upper levels. For example, the lowest level might define a very low-level set of functions for accessing a hash table. The next level might use hash tables to store the headers of a mail message, mapping a header name like \samp{Date} to a value such as \samp{Tue, 13 May 1997 20:00:54 -0400}. A yet higher level may operate on message objects, without knowing or caring that message headers are stored in a hash table, and so forth. Often, the lowest levels do very simple things; they implement a data structure such as a binary tree or hash table, or they perform some simple computation, such as converting a date string to a number. The higher levels then contain logic connecting these primitive operations. Using the approach, the primitives can be seen as basic building blocks which are then glued together to produce the complete product. Why is this design approach relevant to Python? Because Python is well suited to functioning as such a glue language. A common approach is to write a Python module that implements the lower level operations; for the sake of speed, the implementation might be in C, Java, or even Fortran. Once the primitives are available to Python programs, the logic underlying higher level operations is written in the form of Python code. The high-level logic is then more understandable, and easier to modify. John Ousterhout wrote a paper that explains this idea at greater length, entitled ``Scripting: Higher Level Programming for the 21st Century''. I recommend that you read this paper; see the references for the URL. Ousterhout is the inventor of the Tcl language, and therefore argues that Tcl should be used for this purpose; he only briefly refers to other languages such as Python, Perl, and Lisp/Scheme, but in reality, Ousterhout's argument applies to scripting languages in general, since you could equally write extensions for any of the languages mentioned above. \subsection{Prototyping} In \emph{The Mythical Man-Month}, Fredrick Brooks suggests the following rule when planning software projects: ``Plan to throw one away; you will anyway.'' Brooks is saying that the first attempt at a software design often turns out to be wrong; unless the problem is very simple or you're an extremely good designer, you'll find that new requirements and features become apparent once development has actually started. If these new requirements can't be cleanly incorporated into the program's structure, you're presented with two unpleasant choices: hammer the new features into the program somehow, or scrap everything and write a new version of the program, taking the new features into account from the beginning. Python provides you with a good environment for quickly developing an initial prototype. That lets you get the overall program structure and logic right, and you can fine-tune small details in the fast development cycle that Python provides. Once you're satisfied with the GUI interface or program output, you can translate the Python code into C++, Fortran, Java, or some other compiled language. Prototyping means you have to be careful not to use too many Python features that are hard to implement in your other language. Using \code{eval()}, or regular expressions, or the \module{pickle} module, means that you're going to need C or Java libraries for formula evaluation, regular expressions, and serialization, for example. But it's not hard to avoid such tricky code, and in the end the translation usually isn't very difficult. The resulting code can be rapidly debugged, because any serious logical errors will have been removed from the prototype, leaving only more minor slip-ups in the translation to track down. This strategy builds on the earlier discussion of programmability. Using Python as glue to connect lower-level components has obvious relevance for constructing prototype systems. In this way Python can help you with development, even if end users never come in contact with Python code at all. If the performance of the Python version is adequate and corporate politics allow it, you may not need to do a translation into C or Java, but it can still be faster to develop a prototype and then translate it, instead of attempting to produce the final version immediately. One example of this development strategy is Microsoft Merchant Server. Version 1.0 was written in pure Python, by a company that subsequently was purchased by Microsoft. Version 2.0 began to translate the code into \Cpp, shipping with some \Cpp code and some Python code. Version 3.0 didn't contain any Python at all; all the code had been translated into \Cpp. Even though the product doesn't contain a Python interpreter, the Python language has still served a useful purpose by speeding up development. This is a very common use for Python. Past conference papers have also described this approach for developing high-level numerical algorithms; see David M. Beazley and Peter S. Lomdahl's paper ``Feeding a Large-scale Physics Application to Python'' in the references for a good example. If an algorithm's basic operations are things like "Take the inverse of this 4000x4000 matrix", and are implemented in some lower-level language, then Python has almost no additional performance cost; the extra time required for Python to evaluate an expression like \code{m.invert()} is dwarfed by the cost of the actual computation. It's particularly good for applications where seemingly endless tweaking is required to get things right. GUI interfaces and Web sites are prime examples. The Python code is also shorter and faster to write (once you're familiar with Python), so it's easier to throw it away if you decide your approach was wrong; if you'd spent two weeks working on it instead of just two hours, you might waste time trying to patch up what you've got out of a natural reluctance to admit that those two weeks were wasted. Truthfully, those two weeks haven't been wasted, since you've learnt something about the problem and the technology you're using to solve it, but it's human nature to view this as a failure of some sort. \subsection{Simplicity and Ease of Understanding} Python is definitely \emph{not} a toy language that's only usable for small tasks. The language features are general and powerful enough to enable it to be used for many different purposes. It's useful at the small end, for 10- or 20-line scripts, but it also scales up to larger systems that contain thousands of lines of code. However, this expressiveness doesn't come at the cost of an obscure or tricky syntax. While Python has some dark corners that can lead to obscure code, there are relatively few such corners, and proper design can isolate their use to only a few classes or modules. It's certainly possible to write confusing code by using too many features with too little concern for clarity, but most Python code can look a lot like a slightly-formalized version of human-understandable pseudocode. In \emph{The New Hacker's Dictionary}, Eric S. Raymond gives the following definition for "compact": \begin{quotation} Compact \emph{adj.} Of a design, describes the valuable property that it can all be apprehended at once in one's head. This generally means the thing created from the design can be used with greater facility and fewer errors than an equivalent tool that is not compact. Compactness does not imply triviality or lack of power; for example, C is compact and FORTRAN is not, but C is more powerful than FORTRAN. Designs become non-compact through accreting features and cruft that don't merge cleanly into the overall design scheme (thus, some fans of Classic C maintain that ANSI C is no longer compact). \end{quotation} (From \url{http://sagan.earthspace.net/jargon/jargon_18.html\#SEC25}) In this sense of the word, Python is quite compact, because the language has just a few ideas, which are used in lots of places. Take namespaces, for example. Import a module with \code{import math}, and you create a new namespace called \samp{math}. Classes are also namespaces that share many of the properties of modules, and have a few of their own; for example, you can create instances of a class. Instances? They're yet another namespace. Namespaces are currently implemented as Python dictionaries, so they have the same methods as the standard dictionary data type: .keys() returns all the keys, and so forth. This simplicity arises from Python's development history. The language syntax derives from different sources; ABC, a relatively obscure teaching language, is one primary influence, and Modula-3 is another. (For more information about ABC and Modula-3, consult their respective Web sites at \url{http://www.cwi.nl/~steven/abc/} and \url{http://www.m3.org}.) Other features have come from C, Icon, Algol-68, and even Perl. Python hasn't really innovated very much, but instead has tried to keep the language small and easy to learn, building on ideas that have been tried in other languages and found useful. Simplicity is a virtue that should not be underestimated. It lets you learn the language more quickly, and then rapidly write code, code that often works the first time you run it. \subsection{Java Integration} If you're working with Java, Jython (\url{http://www.jython.org/}) is definitely worth your attention. Jython is a re-implementation of Python in Java that compiles Python code into Java bytecodes. The resulting environment has very tight, almost seamless, integration with Java. It's trivial to access Java classes from Python, and you can write Python classes that subclass Java classes. Jython can be used for prototyping Java applications in much the same way CPython is used, and it can also be used for test suites for Java code, or embedded in a Java application to add scripting capabilities. \section{Arguments and Rebuttals} Let's say that you've decided upon Python as the best choice for your application. How can you convince your management, or your fellow developers, to use Python? This section lists some common arguments against using Python, and provides some possible rebuttals. \emph{Python is freely available software that doesn't cost anything. How good can it be?} Very good, indeed. These days Linux and Apache, two other pieces of open source software, are becoming more respected as alternatives to commercial software, but Python hasn't had all the publicity. Python has been around for several years, with many users and developers. Accordingly, the interpreter has been used by many people, and has gotten most of the bugs shaken out of it. While bugs are still discovered at intervals, they're usually either quite obscure (they'd have to be, for no one to have run into them before) or they involve interfaces to external libraries. The internals of the language itself are quite stable. Having the source code should be viewed as making the software available for peer review; people can examine the code, suggest (and implement) improvements, and track down bugs. To find out more about the idea of open source code, along with arguments and case studies supporting it, go to \url{http://www.opensource.org}. \emph{Who's going to support it?} Python has a sizable community of developers, and the number is still growing. The Internet community surrounding the language is an active one, and is worth being considered another one of Python's advantages. Most questions posted to the comp.lang.python newsgroup are quickly answered by someone. Should you need to dig into the source code, you'll find it's clear and well-organized, so it's not very difficult to write extensions and track down bugs yourself. If you'd prefer to pay for support, there are companies and individuals who offer commercial support for Python. \emph{Who uses Python for serious work?} Lots of people; one interesting thing about Python is the surprising diversity of applications that it's been used for. People are using Python to: \begin{itemize} \item Run Web sites \item Write GUI interfaces \item Control number-crunching code on supercomputers \item Make a commercial application scriptable by embedding the Python interpreter inside it \item Process large XML data sets \item Build test suites for C or Java code \end{itemize} Whatever your application domain is, there's probably someone who's used Python for something similar. Yet, despite being useable for such high-end applications, Python's still simple enough to use for little jobs. See \url{http://www.python.org/psa/Users.html} for a list of some of the organizations that use Python. \emph{What are the restrictions on Python's use?} They're practically nonexistent. Consult the \file{Misc/COPYRIGHT} file in the source distribution, or \url{http://www.python.org/doc/Copyright.html} for the full language, but it boils down to three conditions. \begin{itemize} \item You have to leave the copyright notice on the software; if you don't include the source code in a product, you have to put the copyright notice in the supporting documentation. \item Don't claim that the institutions that have developed Python endorse your product in any way. \item If something goes wrong, you can't sue for damages. Practically all software licences contain this condition. \end{itemize} Notice that you don't have to provide source code for anything that contains Python or is built with it. Also, the Python interpreter and accompanying documentation can be modified and redistributed in any way you like, and you don't have to pay anyone any licensing fees at all. \emph{Why should we use an obscure language like Python instead of well-known language X?} I hope this HOWTO, and the documents listed in the final section, will help convince you that Python isn't obscure, and has a healthily growing user base. One word of advice: always present Python's positive advantages, instead of concentrating on language X's failings. People want to know why a solution is good, rather than why all the other solutions are bad. So instead of attacking a competing solution on various grounds, simply show how Python's virtues can help. \section{Useful Resources} \begin{definitions} \term{\url{http://www.fsbassociates.com/books/pythonchpt1.htm}} The first chapter of \emph{Internet Programming with Python} also examines some of the reasons for using Python. The book is well worth buying, but the publishers have made the first chapter available on the Web. \term{\url{http://home.pacbell.net/ouster/scripting.html}} John Ousterhout's white paper on scripting is a good argument for the utility of scripting languages, though naturally enough, he emphasizes Tcl, the language he developed. Most of the arguments would apply to any scripting language. \term{\url{http://www.python.org/workshops/1997-10/proceedings/beazley.html}} The authors, David M. Beazley and Peter S. Lomdahl, describe their use of Python at Los Alamos National Laboratory. It's another good example of how Python can help get real work done. This quotation from the paper has been echoed by many people: \begin{quotation} Originally developed as a large monolithic application for massively parallel processing systems, we have used Python to transform our application into a flexible, highly modular, and extremely powerful system for performing simulation, data analysis, and visualization. In addition, we describe how Python has solved a number of important problems related to the development, debugging, deployment, and maintenance of scientific software. \end{quotation} %\term{\url{http://www.pythonjournal.com/volume1/art-interview/}} %This interview with Andy Feit, discussing Infoseek's use of Python, can be %used to show that choosing Python didn't introduce any difficulties %into a company's development process, and provided some substantial benefits. \term{\url{http://www.python.org/psa/Commercial.html}} Robin Friedrich wrote this document on how to support Python's use in commercial projects. \term{\url{http://www.python.org/workshops/1997-10/proceedings/stein.ps}} For the 6th Python conference, Greg Stein presented a paper that traced Python's adoption and usage at a startup called eShop, and later at Microsoft. \term{\url{http://www.opensource.org}} Management may be doubtful of the reliability and usefulness of software that wasn't written commercially. This site presents arguments that show how open source software can have considerable advantages over closed-source software. \term{\url{http://sunsite.unc.edu/LDP/HOWTO/mini/Advocacy.html}} The Linux Advocacy mini-HOWTO was the inspiration for this document, and is also well worth reading for general suggestions on winning acceptance for a new technology, such as Linux or Python. In general, you won't make much progress by simply attacking existing systems and complaining about their inadequacies; this often ends up looking like unfocused whining. It's much better to point out some of the many areas where Python is an improvement over other systems. \end{definitions} \end{document} --- NEW FILE: curses.tex --- \documentclass{howto} \title{Curses Programming with Python} \release{2.01} \author{A.M. Kuchling, Eric S. Raymond} \authoraddress{\email{amk at amk.ca}, \email{esr at thyrsus.com}} \begin{document} \maketitle \begin{abstract} \noindent This document describes how to write text-mode programs with Python 2.x, using the \module{curses} extension module to control the display. This document is available from the Python HOWTO page at \url{http://www.python.org/doc/howto}. \end{abstract} \tableofcontents \section{What is curses?} The curses library supplies a terminal-independent screen-painting and keyboard-handling facility for text-based terminals; such terminals include VT100s, the Linux console, and the simulated terminal provided by X11 programs such as xterm and rxvt. Display terminals support various control codes to perform common operations such as moving the cursor, scrolling the screen, and erasing areas. Different terminals use widely differing codes, and often have their own minor quirks. In a world of X displays, one might ask ``why bother''? It's true that character-cell display terminals are an obsolete technology, but there are niches in which being able to do fancy things with them are still valuable. One is on small-footprint or embedded Unixes that don't carry an X server. Another is for tools like OS installers and kernel configurators that may have to run before X is available. The curses library hides all the details of different terminals, and provides the programmer with an abstraction of a display, containing multiple non-overlapping windows. The contents of a window can be changed in various ways--adding text, erasing it, changing its appearance--and the curses library will automagically figure out what control codes need to be sent to the terminal to produce the right output. The curses library was originally written for BSD Unix; the later System V versions of Unix from AT\&T added many enhancements and new functions. BSD curses is no longer maintained, having been replaced by ncurses, which is an open-source implementation of the AT\&T interface. If you're using an open-source Unix such as Linux or FreeBSD, your system almost certainly uses ncurses. Since most current commercial Unix versions are based on System V code, all the functions described here will probably be available. The older versions of curses carried by some proprietary Unixes may not support everything, though. No one has made a Windows port of the curses module. On a Windows platform, try the Console module written by Fredrik Lundh. The Console module provides cursor-addressable text output, plus full support for mouse and keyboard input, and is available from \url{http://effbot.org/efflib/console}. \subsection{The Python curses module} Thy Python module is a fairly simple wrapper over the C functions provided by curses; if you're already familiar with curses programming in C, it's really easy to transfer that knowledge to Python. The biggest difference is that the Python interface makes things simpler, by merging different C functions such as \function{addstr}, \function{mvaddstr}, \function{mvwaddstr}, into a single \method{addstr()} method. You'll see this covered in more detail later. This HOWTO is simply an introduction to writing text-mode programs with curses and Python. It doesn't attempt to be a complete guide to the curses API; for that, see the Python library guide's serction on ncurses, and the C manual pages for ncurses. It will, however, give you the basic ideas. \section{Starting and ending a curses application} Before doing anything, curses must be initialized. This is done by calling the \function{initscr()} function, which will determine the terminal type, send any required setup codes to the terminal, and create various internal data structures. If successful, \function{initscr()} returns a window object representing the entire screen; this is usually called \code{stdscr}, after the name of the corresponding C variable. \begin{verbatim} import curses stdscr = curses.initscr() \end{verbatim} Usually curses applications turn off automatic echoing of keys to the screen, in order to be able to read keys and only display them under certain circumstances. This requires calling the \function{noecho()} function. \begin{verbatim} curses.noecho() \end{verbatim} Applications will also commonly need to react to keys instantly, without requiring the Enter key to be pressed; this is called cbreak mode, as opposed to the usual buffered input mode. \begin{verbatim} curses.cbreak() \end{verbatim} Terminals usually return special keys, such as the cursor keys or navigation keys such as Page Up and Home, as a multibyte escape sequence. While you could write your application to expect such sequences and process them accordingly, curses can do it for you, returning a special value such as \constant{curses.KEY_LEFT}. To get curses to do the job, you'll have to enable keypad mode. \begin{verbatim} stdscr.keypad(1) \end{verbatim} Terminating a curses application is much easier than starting one. You'll need to call \begin{verbatim} curses.nocbreak(); stdscr.keypad(0); curses.echo() \end{verbatim} to reverse the curses-friendly terminal settings. Then call the \function{endwin()} function to restore the terminal to its original operating mode. \begin{verbatim} curses.endwin() \end{verbatim} A common problem when debugging a curses application is to get your terminal messed up when the application dies without restoring the terminal to its previous state. In Python this commonly happens when your code is buggy and raises an uncaught exception. Keys are no longer be echoed to the screen when you type them, for example, which makes using the shell difficult. In Python you can avoid these complications and make debugging much easier by importing the module \module{curses.wrapper}. It supplies a function \function{wrapper} that takes a hook argument. It does the initializations described above, and also initializes colors if color support is present. It then runs your hook, and then finally deinitializes appropriately. The hook is called inside a try-catch clause which catches exceptions, performs curses deinitialization, and then passes the exception upwards. Thus, your terminal won't be left in a funny state on exception. \section{Windows and Pads} Windows are the basic abstraction in curses. A window object represents a rectangular area of the screen, and supports various methods to display text, erase it, allow the user to input strings, and so forth. The \code{stdscr} object returned by the \function{initscr()} function is a window object that covers the entire screen. Many programs may need only this single window, but you might wish to divide the screen into smaller windows, in order to redraw or clear them separately. The \function{newwin()} function creates a new window of a given size, returning the new window object. \begin{verbatim} begin_x = 20 ; begin_y = 7 height = 5 ; width = 40 win = curses.newwin(height, width, begin_y, begin_x) \end{verbatim} A word about the coordinate system used in curses: coordinates are always passed in the order \emph{y,x}, and the top-left corner of a window is coordinate (0,0). This breaks a common convention for handling coordinates, where the \emph{x} coordinate usually comes first. This is an unfortunate difference from most other computer applications, but it's been part of curses since it was first written, and it's too late to change things now. When you call a method to display or erase text, the effect doesn't immediately show up on the display. This is because curses was originally written with slow 300-baud terminal connections in mind; with these terminals, minimizing the time required to redraw the screen is very important. This lets curses accumulate changes to the screen, and display them in the most efficient manner. For example, if your program displays some characters in a window, and then clears the window, there's no need to send the original characters because they'd never be visible. Accordingly, curses requires that you explicitly tell it to redraw windows, using the \function{refresh()} method of window objects. In practice, this doesn't really complicate programming with curses much. Most programs go into a flurry of activity, and then pause waiting for a keypress or some other action on the part of the user. All you have to do is to be sure that the screen has been redrawn before pausing to wait for user input, by simply calling \code{stdscr.refresh()} or the \function{refresh()} method of some other relevant window. A pad is a special case of a window; it can be larger than the actual display screen, and only a portion of it displayed at a time. Creating a pad simply requires the pad's height and width, while refreshing a pad requires giving the coordinates of the on-screen area where a subsection of the pad will be displayed. \begin{verbatim} pad = curses.newpad(100, 100) # These loops fill the pad with letters; this is # explained in the next section for y in range(0, 100): for x in range(0, 100): try: pad.addch(y,x, ord('a') + (x*x+y*y) % 26 ) except curses.error: pass # Displays a section of the pad in the middle of the screen pad.refresh( 0,0, 5,5, 20,75) \end{verbatim} The \function{refresh()} call displays a section of the pad in the rectangle extending from coordinate (5,5) to coordinate (20,75) on the screen;the upper left corner of the displayed section is coordinate (0,0) on the pad. Beyond that difference, pads are exactly like ordinary windows and support the same methods. If you have multiple windows and pads on screen there is a more efficient way to go, which will prevent annoying screen flicker at refresh time. Use the methods \method{noutrefresh()} and/or \method{noutrefresh()} of each window to update the data structure representing the desired state of the screen; then change the physical screen to match the desired state in one go with the function \function{doupdate()}. The normal \method{refresh()} method calls \function{doupdate()} as its last act. \section{Displaying Text} {}From a C programmer's point of view, curses may sometimes look like a twisty maze of functions, all subtly different. For example, \function{addstr()} displays a string at the current cursor location in the \code{stdscr} window, while \function{mvaddstr()} moves to a given y,x coordinate first before displaying the string. \function{waddstr()} is just like \function{addstr()}, but allows specifying a window to use, instead of using \code{stdscr} by default. \function{mvwaddstr()} follows similarly. Fortunately the Python interface hides all these details; \code{stdscr} is a window object like any other, and methods like \function{addstr()} accept multiple argument forms. Usually there are four different forms. \begin{tableii}{|c|l|}{textrm}{Form}{Description} \lineii{\var{str} or \var{ch}}{Display the string \var{str} or character \var{ch}} \lineii{\var{str} or \var{ch}, \var{attr}}{Display the string \var{str} or character \var{ch}, using attribute \var{attr}} \lineii{\var{y}, \var{x}, \var{str} or \var{ch}} {Move to position \var{y,x} within the window, and display \var{str} or \var{ch}} \lineii{\var{y}, \var{x}, \var{str} or \var{ch}, \var{attr}} {Move to position \var{y,x} within the window, and display \var{str} or \var{ch}, using attribute \var{attr}} \end{tableii} Attributes allow displaying text in highlighted forms, such as in boldface, underline, reverse code, or in color. They'll be explained in more detail in the next subsection. The \function{addstr()} function takes a Python string as the value to be displayed, while the \function{addch()} functions take a character, which can be either a Python string of length 1, or an integer. If it's a string, you're limited to displaying characters between 0 and 255. SVr4 curses provides constants for extension characters; these constants are integers greater than 255. For example, \constant{ACS_PLMINUS} is a +/- symbol, and \constant{ACS_ULCORNER} is the upper left corner of a box (handy for drawing borders). Windows remember where the cursor was left after the last operation, so if you leave out the \var{y,x} coordinates, the string or character will be displayed wherever the last operation left off. You can also move the cursor with the \function{move(\var{y,x})} method. Because some terminals always display a flashing cursor, you may want to ensure that the cursor is positioned in some location where it won't be distracting; it can be confusing to have the cursor blinking at some apparently random location. If your application doesn't need a blinking cursor at all, you can call \function{curs_set(0)} to make it invisible. Equivalently, and for compatibility with older curses versions, there's a \function{leaveok(\var{bool})} function. When \var{bool} is true, the curses library will attempt to suppress the flashing cursor, and you won't need to worry about leaving it in odd locations. \subsection{Attributes and Color} Characters can be displayed in different ways. Status lines in a text-based application are commonly shown in reverse video; a text viewer may need to highlight certain words. curses supports this by allowing you to specify an attribute for each cell on the screen. An attribute is a integer, each bit representing a different attribute. You can try to display text with multiple attribute bits set, but curses doesn't guarantee that all the possible combinations are available, or that they're all visually distinct. That depends on the ability of the terminal being used, so it's safest to stick to the most commonly available attributes, listed here. \begin{tableii}{|c|l|}{constant}{Attribute}{Description} \lineii{A_BLINK}{Blinking text} \lineii{A_BOLD}{Extra bright or bold text} \lineii{A_DIM}{Half bright text} \lineii{A_REVERSE}{Reverse-video text} \lineii{A_STANDOUT}{The best highlighting mode available} \lineii{A_UNDERLINE}{Underlined text} \end{tableii} So, to display a reverse-video status line on the top line of the screen, you could code: \begin{verbatim} stdscr.addstr(0, 0, "Current mode: Typing mode", curses.A_REVERSE) stdscr.refresh() \end{verbatim} The curses library also supports color on those terminals that provide it, The most common such terminal is probably the Linux console, followed by color xterms. To use color, you must call the \function{start_color()} function soon after calling \function{initscr()}, to initialize the default color set (the \function{curses.wrapper.wrapper()} function does this automatically). Once that's done, the \function{has_colors()} function returns TRUE if the terminal in use can actually display color. (Note from AMK: curses uses the American spelling 'color', instead of the Canadian/British spelling 'colour'. If you're like me, you'll have to resign yourself to misspelling it for the sake of these functions.) The curses library maintains a finite number of color pairs, containing a foreground (or text) color and a background color. You can get the attribute value corresponding to a color pair with the \function{color_pair()} function; this can be bitwise-OR'ed with other attributes such as \constant{A_REVERSE}, but again, such combinations are not guaranteed to work on all terminals. An example, which displays a line of text using color pair 1: \begin{verbatim} stdscr.addstr( "Pretty text", curses.color_pair(1) ) stdscr.refresh() \end{verbatim} As I said before, a color pair consists of a foreground and background color. \function{start_color()} initializes 8 basic colors when it activates color mode. They are: 0:black, 1:red, 2:green, 3:yellow, 4:blue, 5:magenta, 6:cyan, and 7:white. The curses module defines named constants for each of these colors: \constant{curses.COLOR_BLACK}, \constant{curses.COLOR_RED}, and so forth. The \function{init_pair(\var{n, f, b})} function changes the definition of color pair \var{n}, to foreground color {f} and background color {b}. Color pair 0 is hard-wired to white on black, and cannot be changed. Let's put all this together. To change color 1 to red text on a white background, you would call: \begin{verbatim} curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE) \end{verbatim} When you change a color pair, any text already displayed using that color pair will change to the new colors. You can also display new text in this color with: \begin{verbatim} stdscr.addstr(0,0, "RED ALERT!", curses.color_pair(1) ) \end{verbatim} Very fancy terminals can change the definitions of the actual colors to a given RGB value. This lets you change color 1, which is usually red, to purple or blue or any other color you like. Unfortunately, the Linux console doesn't support this, so I'm unable to try it out, and can't provide any examples. You can check if your terminal can do this by calling \function{can_change_color()}, which returns TRUE if the capability is there. If you're lucky enough to have such a talented terminal, consult your system's man pages for more information. \section{User Input} The curses library itself offers only very simple input mechanisms. Python's support adds a text-input widget that makes up some of the lack. The most common way to get input to a window is to use its \method{getch()} method. that pauses, and waits for the user to hit a key, displaying it if \function{echo()} has been called earlier. You can optionally specify a coordinate to which the cursor should be moved before pausing. It's possible to change this behavior with the method \method{nodelay()}. After \method{nodelay(1)}, \method{getch()} for the window becomes non-blocking and returns ERR (-1) when no input is ready. There's also a \function{halfdelay()} function, which can be used to (in effect) set a timer on each \method{getch()}; if no input becomes available within the number of milliseconds specified as the argument to \function{halfdelay()}, curses throws an exception. The \method{getch()} method returns an integer; if it's between 0 and 255, it represents the ASCII code of the key pressed. Values greater than 255 are special keys such as Page Up, Home, or the cursor keys. You can compare the value returned to constants such as \constant{curses.KEY_PPAGE}, \constant{curses.KEY_HOME}, or \constant{curses.KEY_LEFT}. Usually the main loop of your program will look something like this: \begin{verbatim} while 1: c = stdscr.getch() if c == ord('p'): PrintDocument() elif c == ord('q'): break # Exit the while() elif c == curses.KEY_HOME: x = y = 0 \end{verbatim} The \module{curses.ascii} module supplies ASCII class membership functions that take either integer or 1-character-string arguments; these may be useful in writing more readable tests for your command interpreters. It also supplies conversion functions that take either integer or 1-character-string arguments and return the same type. For example, \function{curses.ascii.ctrl()} returns the control character corresponding to its argument. There's also a method to retrieve an entire string, \constant{getstr()}. It isn't used very often, because its functionality is quite limited; the only editing keys available are the backspace key and the Enter key, which terminates the string. It can optionally be limited to a fixed number of characters. \begin{verbatim} curses.echo() # Enable echoing of characters # Get a 15-character string, with the cursor on the top line s = stdscr.getstr(0,0, 15) \end{verbatim} The Python \module{curses.textpad} module supplies something better. With it, you can turn a window into a text box that supports an Emacs-like set of keybindings. Various methods of \class{Textbox} class support editing with input validation and gathering the edit results either with or without trailing spaces. See the library documentation on \module{curses.textpad} for the details. \section{For More Information} This HOWTO didn't cover some advanced topics, such as screen-scraping or capturing mouse events from an xterm instance. But the Python library page for the curses modules is now pretty complete. You should browse it next. If you're in doubt about the detailed behavior of any of the ncurses entry points, consult the manual pages for your curses implementation, whether it's ncurses or a proprietary Unix vendor's. The manual pages will document any quirks, and provide complete lists of all the functions, attributes, and \constant{ACS_*} characters available to you. Because the curses API is so large, some functions aren't supported in the Python interface, not because they're difficult to implement, but because no one has needed them yet. Feel free to add them and then submit a patch. Also, we don't yet have support for the menus or panels libraries associated with ncurses; feel free to add that. If you write an interesting little program, feel free to contribute it as another demo. We can always use more of them! The ncurses FAQ: \url{http://dickey.his.com/ncurses/ncurses.faq.html} \end{document} --- NEW FILE: doanddont.tex --- \documentclass{howto} \title{Idioms and Anti-Idioms in Python} \release{0.00} \author{Moshe Zadka} \authoraddress{howto at zadka.site.co.il} \begin{document} \maketitle This document is placed in the public doman. \begin{abstract} \noindent This document can be considered a companion to the tutorial. It shows how to use Python, and even more importantly, how {\em not} to use Python. \end{abstract} \tableofcontents \section{Language Constructs You Should Not Use} While Python has relatively few gotchas compared to other languages, it still has some constructs which are only useful in corner cases, or are plain dangerous. \subsection{from module import *} \subsubsection{Inside Function Definitions} \code{from module import *} is {\em invalid} inside function definitions. While many versions of Python do no check for the invalidity, it does not make it more valid, no more then having a smart lawyer makes a man innocent. Do not use it like that ever. Even in versions where it was accepted, it made the function execution slower, because the compiler could not be certain which names are local and which are global. In Python 2.1 this construct causes warnings, and sometimes even errors. \subsubsection{At Module Level} While it is valid to use \code{from module import *} at module level it is usually a bad idea. For one, this loses an important property Python otherwise has --- you can know where each toplevel name is defined by a simple "search" function in your favourite editor. You also open yourself to trouble in the future, if some module grows additional functions or classes. One of the most awful question asked on the newsgroup is why this code: \begin{verbatim} f = open("www") f.read() \end{verbatim} does not work. Of course, it works just fine (assuming you have a file called "www".) But it does not work if somewhere in the module, the statement \code{from os import *} is present. The \module{os} module has a function called \function{open()} which returns an integer. While it is very useful, shadowing builtins is one of its least useful properties. Remember, you can never know for sure what names a module exports, so either take what you need --- \code{from module import name1, name2}, or keep them in the module and access on a per-need basis --- \code{import module;print module.name}. \subsubsection{When It Is Just Fine} There are situations in which \code{from module import *} is just fine: \begin{itemize} \item The interactive prompt. For example, \code{from math import *} makes Python an amazing scientific calculator. \item When extending a module in C with a module in Python. \item When the module advertises itself as \code{from import *} safe. \end{itemize} \subsection{Unadorned \keyword{exec}, \function{execfile} and friends} The word ``unadorned'' refers to the use without an explicit dictionary, in which case those constructs evaluate code in the {\em current} environment. This is dangerous for the same reasons \code{from import *} is dangerous --- it might step over variables you are counting on and mess up things for the rest of your code. Simply do not do that. Bad examples: \begin{verbatim} >>> for name in sys.argv[1:]: >>> exec "%s=1" % name >>> def func(s, **kw): >>> for var, val in kw.items(): >>> exec "s.%s=val" % var # invalid! >>> execfile("handler.py") >>> handle() \end{verbatim} Good examples: \begin{verbatim} >>> d = {} >>> for name in sys.argv[1:]: >>> d[name] = 1 >>> def func(s, **kw): >>> for var, val in kw.items(): >>> setattr(s, var, val) >>> d={} >>> execfile("handle.py", d, d) >>> handle = d['handle'] >>> handle() \end{verbatim} \subsection{from module import name1, name2} This is a ``don't'' which is much weaker then the previous ``don't''s but is still something you should not do if you don't have good reasons to do that. The reason it is usually bad idea is because you suddenly have an object which lives in two seperate namespaces. When the binding in one namespace changes, the binding in the other will not, so there will be a discrepancy between them. This happens when, for example, one module is reloaded, or changes the definition of a function at runtime. Bad example: \begin{verbatim} # foo.py a = 1 # bar.py from foo import a if something(): a = 2 # danger: foo.a != a \end{verbatim} Good example: \begin{verbatim} # foo.py a = 1 # bar.py import foo if something(): foo.a = 2 \end{verbatim} \subsection{except:} Python has the \code{except:} clause, which catches all exceptions. Since {\em every} error in Python raises an exception, this makes many programming errors look like runtime problems, and hinders the debugging process. The following code shows a great example: \begin{verbatim} try: foo = opne("file") # misspelled "open" except: sys.exit("could not open file!") \end{verbatim} The second line triggers a \exception{NameError} which is caught by the except clause. The program will exit, and you will have no idea that this has nothing to do with the readability of \code{"file"}. The example above is better written \begin{verbatim} try: foo = opne("file") # will be changed to "open" as soon as we run it except IOError: sys.exit("could not open file") \end{verbatim} There are some situations in which the \code{except:} clause is useful: for example, in a framework when running callbacks, it is good not to let any callback disturb the framework. \section{Exceptions} Exceptions are a useful feature of Python. You should learn to raise them whenever something unexpected occurs, and catch them only where you can do something about them. The following is a very popular anti-idiom \begin{verbatim} def get_status(file): if not os.path.exists(file): print "file not found" sys.exit(1) return open(file).readline() \end{verbatim} Consider the case the file gets deleted between the time the call to \function{os.path.exists} is made and the time \function{open} is called. That means the last line will throw an \exception{IOError}. The same would happen if \var{file} exists but has no read permission. Since testing this on a normal machine on existing and non-existing files make it seem bugless, that means in testing the results will seem fine, and the code will get shipped. Then an unhandled \exception{IOError} escapes to the user, who has to watch the ugly traceback. Here is a better way to do it. \begin{verbatim} def get_status(file): try: return open(file).readline() except (IOError, OSError): print "file not found" sys.exit(1) \end{verbatim} In this version, *either* the file gets opened and the line is read (so it works even on flaky NFS or SMB connections), or the message is printed and the application aborted. Still, \function{get_status} makes too many assumptions --- that it will only be used in a short running script, and not, say, in a long running server. Sure, the caller could do something like \begin{verbatim} try: status = get_status(log) except SystemExit: status = None \end{verbatim} So, try to make as few \code{except} clauses in your code --- those will usually be a catch-all in the \function{main}, or inside calls which should always succeed. So, the best version is probably \begin{verbatim} def get_status(file): return open(file).readline() \end{verbatim} The caller can deal with the exception if it wants (for example, if it tries several files in a loop), or just let the exception filter upwards to {\em its} caller. The last version is not very good either --- due to implementation details, the file would not be closed when an exception is raised until the handler finishes, and perhaps not at all in non-C implementations (e.g., Jython). \begin{verbatim} def get_status(file): fp = open(file) try: return fp.readline() finally: fp.close() \end{verbatim} \section{Using the Batteries} Every so often, people seem to be writing stuff in the Python library again, usually poorly. While the occasional module has a poor interface, it is usually much better to use the rich standard library and data types that come with Python then inventing your own. A useful module very few people know about is \module{os.path}. It always has the correct path arithmetic for your operating system, and will usually be much better then whatever you come up with yourself. Compare: \begin{verbatim} # ugh! return dir+"/"+file # better return os.path.join(dir, file) \end{verbatim} More useful functions in \module{os.path}: \function{basename}, \function{dirname} and \function{splitext}. There are also many useful builtin functions people seem not to be aware of for some reason: \function{min()} and \function{max()} can find the minimum/maximum of any sequence with comparable semantics, for example, yet many people write they own max/min. Another highly useful function is \function{reduce()}. Classical use of \function{reduce()} is something like \begin{verbatim} import sys, operator nums = map(float, sys.argv[1:]) print reduce(operator.add, nums)/len(nums) \end{verbatim} This cute little script prints the average of all numbers given on the command line. The \function{reduce()} adds up all the numbers, and the rest is just some pre- and postprocessing. On the same note, note that \function{float()}, \function{int()} and \function{long()} all accept arguments of type string, and so are suited to parsing --- assuming you are ready to deal with the \exception{ValueError} they raise. \section{Using Backslash to Continue Statements} Since Python treats a newline as a statement terminator, and since statements are often more then is comfortable to put in one line, many people do: \begin{verbatim} if foo.bar()['first'][0] == baz.quux(1, 2)[5:9] and \ calculate_number(10, 20) != forbulate(500, 360): pass \end{verbatim} You should realize that this is dangerous: a stray space after the \code{\\} would make this line wrong, and stray spaces are notoriously hard to see in editors. In this case, at least it would be a syntax error, but if the code was: \begin{verbatim} value = foo.bar()['first'][0]*baz.quux(1, 2)[5:9] \ + calculate_number(10, 20)*forbulate(500, 360) \end{verbatim} then it would just be subtly wrong. It is usually much better to use the implicit continuation inside parenthesis: This version is bulletproof: \begin{verbatim} value = (foo.bar()['first'][0]*baz.quux(1, 2)[5:9] + calculate_number(10, 20)*forbulate(500, 360)) \end{verbatim} \end{document} --- NEW FILE: regex.tex --- \documentclass{howto} % TODO: % Document lookbehind assertions % Better way of displaying a RE, a string, and what it matches % Mention optional argument to match.groups() % Unicode (at least a reference) \title{Regular Expression HOWTO} \release{0.05} \author{A.M. Kuchling} \authoraddress{\email{amk at amk.ca}} \begin{document} \maketitle \begin{abstract} [...1427 lines suppressed...] % $ \section{Feedback} Regular expressions are a complicated topic. Did this document help you understand them? Were there parts that were unclear, or Problems you encountered that weren't covered here? If so, please send suggestions for improvements to the author. The most complete book on regular expressions is almost certainly Jeffrey Friedl's \citetitle{Mastering Regular Expressions}, published by O'Reilly. Unfortunately, it exclusively concentrates on Perl and Java's flavours of regular expressions, and doesn't contain any Python material at all, so it won't be useful as a reference for programming in Python. (The first edition covered Python's now-obsolete \module{regex} module, which won't help you much.) Consider checking it out from your library. \end{document} --- NEW FILE: rexec.tex --- \documentclass{howto} \title{Restricted Execution HOWTO} \release{2.1} \author{A.M. Kuchling} \authoraddress{\email{amk at amk.ca}} \begin{document} \maketitle \begin{abstract} \noindent Python 2.2.2 and earlier provided a \module{rexec} module running untrusted code. However, it's never been exhaustively audited for security and it hasn't been updated to take into account recent changes to Python such as new-style classes. Therefore, the \module{rexec} module should not be trusted. To discourage use of \module{rexec}, this HOWTO has been withdrawn. The \module{rexec} and \module{Bastion} modules have been disabled in the Python CVS tree, both on the trunk (which will eventually become Python 2.3alpha2 and later 2.3final) and on the release22-maint branch (which will become Python 2.2.3, if someone ever volunteers to issue 2.2.3). For discussion of the problems with \module{rexec}, see the python-dev threads starting at the following URLs: \url{http://mail.python.org/pipermail/python-dev/2002-December/031160.html}, and \url{http://mail.python.org/pipermail/python-dev/2003-January/031848.html}. \end{abstract} \section{Version History} Sep. 12, 1998: Minor revisions and added the reference to the Janus project. Feb. 26, 1998: First version. Suggestions are welcome. Mar. 16, 1998: Made some revisions suggested by Jeff Rush. Some minor changes and clarifications, and a sizable section on exceptions added. Oct. 4, 2000: Checked with Python 2.0. Minor rewrites and fixes made. Version number increased to 2.0. Dec. 17, 2002: Withdrawn. Jan. 8, 2003: Mention that \module{rexec} will be disabled in Python 2.3, and added links to relevant python-dev threads. \end{document} --- NEW FILE: sockets.tex --- \documentclass{howto} \title{Socket Programming HOWTO} \release{0.00} \author{Gordon McMillan} \authoraddress{\email{gmcm at hypernet.com}} \begin{document} \maketitle \begin{abstract} \noindent Sockets are used nearly everywhere, but are one of the most severely misunderstood technologies around. This is a 10,000 foot overview of sockets. It's not really a tutorial - you'll still have work to do in getting things operational. It doesn't cover the fine points (and there are a lot of them), but I hope it will give you enough background to begin using them decently. This document is available from the Python HOWTO page at \url{http://www.python.org/doc/howto}. \end{abstract} \tableofcontents \section{Sockets} Sockets are used nearly everywhere, but are one of the most severely misunderstood technologies around. This is a 10,000 foot overview of sockets. It's not really a tutorial - you'll still have work to do in getting things working. It doesn't cover the fine points (and there are a lot of them), but I hope it will give you enough background to begin using them decently. I'm only going to talk about INET sockets, but they account for at least 99\% of the sockets in use. And I'll only talk about STREAM sockets - unless you really know what you're doing (in which case this HOWTO isn't for you!), you'll get better behavior and performance from a STREAM socket than anything else. I will try to clear up the mystery of what a socket is, as well as some hints on how to work with blocking and non-blocking sockets. But I'll start by talking about blocking sockets. You'll need to know how they work before dealing with non-blocking sockets. Part of the trouble with understanding these things is that "socket" can mean a number of subtly different things, depending on context. So first, let's make a distinction between a "client" socket - an endpoint of a conversation, and a "server" socket, which is more like a switchboard operator. The client application (your browser, for example) uses "client" sockets exclusively; the web server it's talking to uses both "server" sockets and "client" sockets. \subsection{History} Of the various forms of IPC (\emph{Inter Process Communication}), sockets are by far the most popular. On any given platform, there are likely to be other forms of IPC that are faster, but for cross-platform communication, sockets are about the only game in town. They were invented in Berkeley as part of the BSD flavor of Unix. They spread like wildfire with the Internet. With good reason --- the combination of sockets with INET makes talking to arbitrary machines around the world unbelievably easy (at least compared to other schemes). \section{Creating a Socket} Roughly speaking, when you clicked on the link that brought you to this page, your browser did something like the following: \begin{verbatim} #create an INET, STREAMing socket s = socket.socket( socket.AF_INET, socket.SOCK_STREAM) #now connect to the web server on port 80 # - the normal http port s.connect(("www.mcmillan-inc.com", 80)) \end{verbatim} When the \code{connect} completes, the socket \code{s} can now be used to send in a request for the text of this page. The same socket will read the reply, and then be destroyed. That's right - destroyed. Client sockets are normally only used for one exchange (or a small set of sequential exchanges). What happens in the web server is a bit more complex. First, the web server creates a "server socket". \begin{verbatim} #create an INET, STREAMing socket serversocket = socket.socket( socket.AF_INET, socket.SOCK_STREAM) #bind the socket to a public host, # and a well-known port serversocket.bind((socket.gethostname(), 80)) #become a server socket serversocket.listen(5) \end{verbatim} A couple things to notice: we used \code{socket.gethostname()} so that the socket would be visible to the outside world. If we had used \code{s.bind(('', 80))} or \code{s.bind(('localhost', 80))} or \code{s.bind(('127.0.0.1', 80))} we would still have a "server" socket, but one that was only visible within the same machine. A second thing to note: low number ports are usually reserved for "well known" services (HTTP, SNMP etc). If you're playing around, use a nice high number (4 digits). Finally, the argument to \code{listen} tells the socket library that we want it to queue up as many as 5 connect requests (the normal max) before refusing outside connections. If the rest of the code is written properly, that should be plenty. OK, now we have a "server" socket, listening on port 80. Now we enter the mainloop of the web server: \begin{verbatim} while 1: #accept connections from outside (clientsocket, address) = serversocket.accept() #now do something with the clientsocket #in this case, we'll pretend this is a threaded server ct = client_thread(clientsocket) ct.run() \end{verbatim} There's actually 3 general ways in which this loop could work - dispatching a thread to handle \code{clientsocket}, create a new process to handle \code{clientsocket}, or restructure this app to use non-blocking sockets, and mulitplex between our "server" socket and any active \code{clientsocket}s using \code{select}. More about that later. The important thing to understand now is this: this is \emph{all} a "server" socket does. It doesn't send any data. It doesn't receive any data. It just produces "client" sockets. Each \code{clientsocket} is created in response to some \emph{other} "client" socket doing a \code{connect()} to the host and port we're bound to. As soon as we've created that \code{clientsocket}, we go back to listening for more connections. The two "clients" are free to chat it up - they are using some dynamically allocated port which will be recycled when the conversation ends. \subsection{IPC} If you need fast IPC between two processes on one machine, you should look into whatever form of shared memory the platform offers. A simple protocol based around shared memory and locks or semaphores is by far the fastest technique. If you do decide to use sockets, bind the "server" socket to \code{'localhost'}. On most platforms, this will take a shortcut around a couple of layers of network code and be quite a bit faster. \section{Using a Socket} The first thing to note, is that the web browser's "client" socket and the web server's "client" socket are identical beasts. That is, this is a "peer to peer" conversation. Or to put it another way, \emph{as the designer, you will have to decide what the rules of etiquette are for a conversation}. Normally, the \code{connect}ing socket starts the conversation, by sending in a request, or perhaps a signon. But that's a design decision - it's not a rule of sockets. Now there are two sets of verbs to use for communication. You can use \code{send} and \code{recv}, or you can transform your client socket into a file-like beast and use \code{read} and \code{write}. The latter is the way Java presents their sockets. I'm not going to talk about it here, except to warn you that you need to use \code{flush} on sockets. These are buffered "files", and a common mistake is to \code{write} something, and then \code{read} for a reply. Without a \code{flush} in there, you may wait forever for the reply, because the request may still be in your output buffer. Now we come the major stumbling block of sockets - \code{send} and \code{recv} operate on the network buffers. They do not necessarily handle all the bytes you hand them (or expect from them), because their major focus is handling the network buffers. In general, they return when the associated network buffers have been filled (\code{send}) or emptied (\code{recv}). They then tell you how many bytes they handled. It is \emph{your} responsibility to call them again until your message has been completely dealt with. When a \code{recv} returns 0 bytes, it means the other side has closed (or is in the process of closing) the connection. You will not receive any more data on this connection. Ever. You may be able to send data successfully; I'll talk about that some on the next page. A protocol like HTTP uses a socket for only one transfer. The client sends a request, the reads a reply. That's it. The socket is discarded. This means that a client can detect the end of the reply by receiving 0 bytes. But if you plan to reuse your socket for further transfers, you need to realize that \emph{there is no "EOT" (End of Transfer) on a socket.} I repeat: if a socket \code{send} or \code{recv} returns after handling 0 bytes, the connection has been broken. If the connection has \emph{not} been broken, you may wait on a \code{recv} forever, because the socket will \emph{not} tell you that there's nothing more to read (for now). Now if you think about that a bit, you'll come to realize a fundamental truth of sockets: \emph{messages must either be fixed length} (yuck), \emph{or be delimited} (shrug), \emph{or indicate how long they are} (much better), \emph{or end by shutting down the connection}. The choice is entirely yours, (but some ways are righter than others). Assuming you don't want to end the connection, the simplest solution is a fixed length message: \begin{verbatim} class mysocket: '''demonstration class only - coded for clarity, not efficiency''' def __init__(self, sock=None): if sock is None: self.sock = socket.socket( socket.AF_INET, socket.SOCK_STREAM) else: self.sock = sock def connect(host, port): self.sock.connect((host, port)) def mysend(msg): totalsent = 0 while totalsent < MSGLEN: sent = self.sock.send(msg[totalsent:]) if sent == 0: raise RuntimeError, \\ "socket connection broken" totalsent = totalsent + sent def myreceive(): msg = '' while len(msg) < MSGLEN: chunk = self.sock.recv(MSGLEN-len(msg)) if chunk == '': raise RuntimeError, \\ "socket connection broken" msg = msg + chunk return msg \end{verbatim} The sending code here is usable for almost any messaging scheme - in Python you send strings, and you can use \code{len()} to determine its length (even if it has embedded \code{\e 0} characters). It's mostly the receiving code that gets more complex. (And in C, it's not much worse, except you can't use \code{strlen} if the message has embedded \code{\e 0}s.) The easiest enhancement is to make the first character of the message an indicator of message type, and have the type determine the length. Now you have two \code{recv}s - the first to get (at least) that first character so you can look up the length, and the second in a loop to get the rest. If you decide to go the delimited route, you'll be receiving in some arbitrary chunk size, (4096 or 8192 is frequently a good match for network buffer sizes), and scanning what you've received for a delimiter. One complication to be aware of: if your conversational protocol allows multiple messages to be sent back to back (without some kind of reply), and you pass \code{recv} an arbitrary chunk size, you may end up reading the start of a following message. You'll need to put that aside and hold onto it, until it's needed. Prefixing the message with it's length (say, as 5 numeric characters) gets more complex, because (believe it or not), you may not get all 5 characters in one \code{recv}. In playing around, you'll get away with it; but in high network loads, your code will very quickly break unless you use two \code{recv} loops - the first to determine the length, the second to get the data part of the message. Nasty. This is also when you'll discover that \code{send} does not always manage to get rid of everything in one pass. And despite having read this, you will eventually get bit by it! In the interests of space, building your character, (and preserving my competitive position), these enhancements are left as an exercise for the reader. Lets move on to cleaning up. \subsection{Binary Data} It is perfectly possible to send binary data over a socket. The major problem is that not all machines use the same formats for binary data. For example, a Motorola chip will represent a 16 bit integer with the value 1 as the two hex bytes 00 01. Intel and DEC, however, are byte-reversed - that same 1 is 01 00. Socket libraries have calls for converting 16 and 32 bit integers - \code{ntohl, htonl, ntohs, htons} where "n" means \emph{network} and "h" means \emph{host}, "s" means \emph{short} and "l" means \emph{long}. Where network order is host order, these do nothing, but where the machine is byte-reversed, these swap the bytes around appropriately. In these days of 32 bit machines, the ascii representation of binary data is frequently smaller than the binary representation. That's because a surprising amount of the time, all those longs have the value 0, or maybe 1. The string "0" would be two bytes, while binary is four. Of course, this doesn't fit well with fixed-length messages. Decisions, decisions. \section{Disconnecting} Strictly speaking, you're supposed to use \code{shutdown} on a socket before you \code{close} it. The \code{shutdown} is an advisory to the socket at the other end. Depending on the argument you pass it, it can mean "I'm not going to send anymore, but I'll still listen", or "I'm not listening, good riddance!". Most socket libraries, however, are so used to programmers neglecting to use this piece of etiquette that normally a \code{close} is the same as \code{shutdown(); close()}. So in most situations, an explicit \code{shutdown} is not needed. One way to use \code{shutdown} effectively is in an HTTP-like exchange. The client sends a request and then does a \code{shutdown(1)}. This tells the server "This client is done sending, but can still receive." The server can detect "EOF" by a receive of 0 bytes. It can assume it has the complete request. The server sends a reply. If the \code{send} completes successfully then, indeed, the client was still receiving. Python takes the automatic shutdown a step further, and says that when a socket is garbage collected, it will automatically do a \code{close} if it's needed. But relying on this is a very bad habit. If your socket just disappears without doing a \code{close}, the socket at the other end may hang indefinitely, thinking you're just being slow. \emph{Please} \code{close} your sockets when you're done. \subsection{When Sockets Die} Probably the worst thing about using blocking sockets is what happens when the other side comes down hard (without doing a \code{close}). Your socket is likely to hang. SOCKSTREAM is a reliable protocol, and it will wait a long, long time before giving up on a connection. If you're using threads, the entire thread is essentially dead. There's not much you can do about it. As long as you aren't doing something dumb, like holding a lock while doing a blocking read, the thread isn't really consuming much in the way of resources. Do \emph{not} try to kill the thread - part of the reason that threads are more efficient than processes is that they avoid the overhead associated with the automatic recycling of resources. In other words, if you do manage to kill the thread, your whole process is likely to be screwed up. \section{Non-blocking Sockets} If you've understood the preceeding, you already know most of what you need to know about the mechanics of using sockets. You'll still use the same calls, in much the same ways. It's just that, if you do it right, your app will be almost inside-out. In Python, you use \code{socket.setblocking(0)} to make it non-blocking. In C, it's more complex, (for one thing, you'll need to choose between the BSD flavor \code{O_NONBLOCK} and the almost indistinguishable Posix flavor \code{O_NDELAY}, which is completely different from \code{TCP_NODELAY}), but it's the exact same idea. You do this after creating the socket, but before using it. (Actually, if you're nuts, you can switch back and forth.) The major mechanical difference is that \code{send}, \code{recv}, \code{connect} and \code{accept} can return without having done anything. You have (of course) a number of choices. You can check return code and error codes and generally drive yourself crazy. If you don't believe me, try it sometime. Your app will grow large, buggy and suck CPU. So let's skip the brain-dead solutions and do it right. Use \code{select}. In C, coding \code{select} is fairly complex. In Python, it's a piece of cake, but it's close enough to the C version that if you understand \code{select} in Python, you'll have little trouble with it in C. \begin{verbatim} ready_to_read, ready_to_write, in_error = \\ select.select( potential_readers, potential_writers, potential_errs, timeout) \end{verbatim} You pass \code{select} three lists: the first contains all sockets that you might want to try reading; the second all the sockets you might want to try writing to, and the last (normally left empty) those that you want to check for errors. You should note that a socket can go into more than one list. The \code{select} call is blocking, but you can give it a timeout. This is generally a sensible thing to do - give it a nice long timeout (say a minute) unless you have good reason to do otherwise. In return, you will get three lists. They have the sockets that are actually readable, writable and in error. Each of these lists is a subset (possbily empty) of the corresponding list you passed in. And if you put a socket in more than one input list, it will only be (at most) in one output list. If a socket is in the output readable list, you can be as-close-to-certain-as-we-ever-get-in-this-business that a \code{recv} on that socket will return \emph{something}. Same idea for the writable list. You'll be able to send \emph{something}. Maybe not all you want to, but \emph{something} is better than nothing. (Actually, any reasonably healthy socket will return as writable - it just means outbound network buffer space is available.) If you have a "server" socket, put it in the potential_readers list. If it comes out in the readable list, your \code{accept} will (almost certainly) work. If you have created a new socket to \code{connect} to someone else, put it in the ptoential_writers list. If it shows up in the writable list, you have a decent chance that it has connected. One very nasty problem with \code{select}: if somewhere in those input lists of sockets is one which has died a nasty death, the \code{select} will fail. You then need to loop through every single damn socket in all those lists and do a \code{select([sock],[],[],0)} until you find the bad one. That timeout of 0 means it won't take long, but it's ugly. Actually, \code{select} can be handy even with blocking sockets. It's one way of determining whether you will block - the socket returns as readable when there's something in the buffers. However, this still doesn't help with the problem of determining whether the other end is done, or just busy with something else. \textbf{Portability alert}: On Unix, \code{select} works both with the sockets and files. Don't try this on Windows. On Windows, \code{select} works with sockets only. Also note that in C, many of the more advanced socket options are done differently on Windows. In fact, on Windows I usually use threads (which work very, very well) with my sockets. Face it, if you want any kind of performance, your code will look very different on Windows than on Unix. (I haven't the foggiest how you do this stuff on a Mac.) \subsection{Performance} There's no question that the fastest sockets code uses non-blocking sockets and select to multiplex them. You can put together something that will saturate a LAN connection without putting any strain on the CPU. The trouble is that an app written this way can't do much of anything else - it needs to be ready to shuffle bytes around at all times. Assuming that your app is actually supposed to do something more than that, threading is the optimal solution, (and using non-blocking sockets will be faster than using blocking sockets). Unfortunately, threading support in Unixes varies both in API and quality. So the normal Unix solution is to fork a subprocess to deal with each connection. The overhead for this is significant (and don't do this on Windows - the overhead of process creation is enormous there). It also means that unless each subprocess is completely independent, you'll need to use another form of IPC, say a pipe, or shared memory and semaphores, to communicate between the parent and child processes. Finally, remember that even though blocking sockets are somewhat slower than non-blocking, in many cases they are the "right" solution. After all, if your app is driven by the data it receives over a socket, there's not much sense in complicating the logic just so your app can wait on \code{select} instead of \code{recv}. \end{document} --- NEW FILE: sorting.tex --- \documentclass{howto} \title{Sorting Mini-HOWTO} % Increment the release number whenever significant changes are made. % The author and/or editor can define 'significant' however they like. \release{0.01} \author{Andrew Dalke} \authoraddress{\email{dalke at bioreason.com}} \begin{document} \maketitle \begin{abstract} \noindent This document is a little tutorial showing a half dozen ways to sort a list with the built-in \method{sort()} method. This document is available from the Python HOWTO page at \url{http://www.python.org/doc/howto}. \end{abstract} \tableofcontents Python lists have a built-in \method{sort()} method. There are many ways to use it to sort a list and there doesn't appear to be a single, central place in the various manuals describing them, so I'll do so here. \section{Sorting basic data types} A simple ascending sort is easy; just call the \method{sort()} method of a list. \begin{verbatim} >>> a = [5, 2, 3, 1, 4] >>> a.sort() >>> print a [1, 2, 3, 4, 5] \end{verbatim} Sort takes an optional function which can be called for doing the comparisons. The default sort routine is equivalent to \begin{verbatim} >>> a = [5, 2, 3, 1, 4] >>> a.sort(cmp) >>> print a [1, 2, 3, 4, 5] \end{verbatim} where \function{cmp} is the built-in function which compares two objects, \code{x} and \code{y}, and returns -1, 0 or 1 depending on whether $xy$. During the course of the sort the relationships must stay the same for the final list to make sense. If you want, you can define your own function for the comparison. For integers (and numbers in general) we can do: \begin{verbatim} >>> def numeric_compare(x, y): >>> return x-y >>> >>> a = [5, 2, 3, 1, 4] >>> a.sort(numeric_compare) >>> print a [1, 2, 3, 4, 5] \end{verbatim} By the way, this function won't work if result of the subtraction is out of range, as in \code{sys.maxint - (-1)}. Or, if you don't want to define a new named function you can create an anonymous one using \keyword{lambda}, as in: \begin{verbatim} >>> a = [5, 2, 3, 1, 4] >>> a.sort(lambda x, y: x-y) >>> print a [1, 2, 3, 4, 5] \end{verbatim} If you want the numbers sorted in reverse you can do \begin{verbatim} >>> a = [5, 2, 3, 1, 4] >>> def reverse_numeric(x, y): >>> return y-x >>> >>> a.sort(reverse_numeric) >>> print a [5, 4, 3, 2, 1] \end{verbatim} (a more general implementation could return \code{cmp(y,x)} or \code{-cmp(x,y)}). However, it's faster if Python doesn't have to call a function for every comparison, so if you want a reverse-sorted list of basic data types, do the forward sort first, then use the \method{reverse()} method. \begin{verbatim} >>> a = [5, 2, 3, 1, 4] >>> a.sort() >>> a.reverse() >>> print a [5, 4, 3, 2, 1] \end{verbatim} Here's a case-insensitive string comparison using a \keyword{lambda} function: \begin{verbatim} >>> import string >>> a = string.split("This is a test string from Andrew.") >>> a.sort(lambda x, y: cmp(string.lower(x), string.lower(y))) >>> print a ['a', 'Andrew.', 'from', 'is', 'string', 'test', 'This'] \end{verbatim} This goes through the overhead of converting a word to lower case every time it must be compared. At times it may be faster to compute these once and use those values, and the following example shows how. \begin{verbatim} >>> words = string.split("This is a test string from Andrew.") >>> offsets = [] >>> for i in range(len(words)): >>> offsets.append( (string.lower(words[i]), i) ) >>> >>> offsets.sort() >>> new_words = [] >>> for dontcare, i in offsets: >>> new_words.append(words[i]) >>> >>> print new_words \end{verbatim} The \code{offsets} list is initialized to a tuple of the lower-case string and its position in the \code{words} list. It is then sorted. Python's sort method sorts tuples by comparing terms; given \code{x} and \code{y}, compare \code{x[0]} to \code{y[0]}, then \code{x[1]} to \code{y[1]}, etc. until there is a difference. The result is that the \code{offsets} list is ordered by its first term, and the second term can be used to figure out where the original data was stored. (The \code{for} loop assigns \code{dontcare} and \code{i} to the two fields of each term in the list, but we only need the index value.) Another way to implement this is to store the original data as the second term in the \code{offsets} list, as in: \begin{verbatim} >>> words = string.split("This is a test string from Andrew.") >>> offsets = [] >>> for word in words: >>> offsets.append( (string.lower(word), word) ) >>> >>> offsets.sort() >>> new_words = [] >>> for word in offsets: >>> new_words.append(word[1]) >>> >>> print new_words \end{verbatim} This isn't always appropriate because the second terms in the list (the word, in this example) will be compared when the first terms are the same. If this happens many times, then there will be the unneeded performance hit of comparing the two objects. This can be a large cost if most terms are the same and the objects define their own \method{__cmp__} method, but there will still be some overhead to determine if \method{__cmp__} is defined. Still, for large lists, or for lists where the comparison information is expensive to calculate, the last two examples are likely to be the fastest way to sort a list. It will not work on weakly sorted data, like complex numbers, but if you don't know what that means, you probably don't need to worry about it. \section{Comparing classes} The comparison for two basic data types, like ints to ints or string to string, is built into Python and makes sense. There is a default way to compare class instances, but the default manner isn't usually very useful. You can define your own comparison with the \method{__cmp__} method, as in: \begin{verbatim} >>> class Spam: >>> def __init__(self, spam, eggs): >>> self.spam = spam >>> self.eggs = eggs >>> def __cmp__(self, other): >>> return cmp(self.spam+self.eggs, other.spam+other.eggs) >>> def __str__(self): >>> return str(self.spam + self.eggs) >>> >>> a = [Spam(1, 4), Spam(9, 3), Spam(4,6)] >>> a.sort() >>> for spam in a: >>> print str(spam) 5 10 12 \end{verbatim} Sometimes you may want to sort by a specific attribute of a class. If appropriate you should just define the \method{__cmp__} method to compare those values, but you cannot do this if you want to compare between different attributes at different times. Instead, you'll need to go back to passing a comparison function to sort, as in: \begin{verbatim} >>> a = [Spam(1, 4), Spam(9, 3), Spam(4,6)] >>> a.sort(lambda x, y: cmp(x.eggs, y.eggs)) >>> for spam in a: >>> print spam.eggs, str(spam) 3 12 4 5 6 10 \end{verbatim} If you want to compare two arbitrary attributes (and aren't overly concerned about performance) you can even define your own comparison function object. This uses the ability of a class instance to emulate an function by defining the \method{__call__} method, as in: \begin{verbatim} >>> class CmpAttr: >>> def __init__(self, attr): >>> self.attr = attr >>> def __call__(self, x, y): >>> return cmp(getattr(x, self.attr), getattr(y, self.attr)) >>> >>> a = [Spam(1, 4), Spam(9, 3), Spam(4,6)] >>> a.sort(CmpAttr("spam")) # sort by the "spam" attribute >>> for spam in a: >>> print spam.spam, spam.eggs, str(spam) 1 4 5 4 6 10 9 3 12 >>> a.sort(CmpAttr("eggs")) # re-sort by the "eggs" attribute >>> for spam in a: >>> print spam.spam, spam.eggs, str(spam) 9 3 12 1 4 5 4 6 10 \end{verbatim} Of course, if you want a faster sort you can extract the attributes into an intermediate list and sort that list. So, there you have it; about a half-dozen different ways to define how to sort a list: \begin{itemize} \item sort using the default method \item sort using a comparison function \item reverse sort not using a comparison function \item sort on an intermediate list (two forms) \item sort using class defined __cmp__ method \item sort using a sort function object \end{itemize} \end{document} % LocalWords: maxint --- NEW FILE: unicode.rst --- Unicode HOWTO ================ **Version 1.02** This HOWTO discusses Python's support for Unicode, and explains various problems that people commonly encounter when trying to work with Unicode. Introduction to Unicode ------------------------------ History of Character Codes '''''''''''''''''''''''''''''' In 1968, the American Standard Code for Information Interchange, better known by its acronym ASCII, was standardized. ASCII defined numeric codes for various characters, with the numeric values running from 0 to 127. For example, the lowercase letter 'a' is assigned 97 as its code value. ASCII was an American-developed standard, so it only defined unaccented characters. There was an 'e', but no 'é' or 'Í'. This meant that languages which required accented characters couldn't be faithfully represented in ASCII. (Actually the missing accents matter for English, too, which contains words such as 'naïve' and 'café', and some publications have house styles which require spellings such as 'coöperate'.) For a while people just wrote programs that didn't display accents. I remember looking at Apple ][ BASIC programs, published in French-language publications in the mid-1980s, that had lines like these:: PRINT "FICHER EST COMPLETE." PRINT "CARACTERE NON ACCEPTE." Those messages should contain accents, and they just look wrong to someone who can read French. In the 1980s, almost all personal computers were 8-bit, meaning that bytes could hold values ranging from 0 to 255. ASCII codes only went up to 127, so some machines assigned values between 128 and 255 to accented characters. Different machines had different codes, however, which led to problems exchanging files. Eventually various commonly used sets of values for the 128-255 range emerged. Some were true standards, defined by the International Standards Organization, and some were **de facto** conventions that were invented by one company or another and managed to catch on. 255 characters aren't very many. For example, you can't fit both the accented characters used in Western Europe and the Cyrillic alphabet used for Russian into the 128-255 range because there are more than 127 such characters. You could write files using different codes (all your Russian files in a coding system called KOI8, all your French files in a different coding system called Latin1), but what if you wanted to write a French document that quotes some Russian text? In the 1980s people began to want to solve this problem, and the Unicode standardization effort began. Unicode started out using 16-bit characters instead of 8-bit characters. 16 bits means you have 2^16 = 65,536 distinct values available, making it possible to represent many different characters from many different alphabets; an initial goal was to have Unicode contain the alphabets for every single human language. It turns out that even 16 bits isn't enough to meet that goal, and the modern Unicode specification uses a wider range of codes, 0-1,114,111 (0x10ffff in base-16). There's a related ISO standard, ISO 10646. Unicode and ISO 10646 were originally separate efforts, but the specifications were merged with the 1.1 revision of Unicode. (This discussion of Unicode's history is highly simplified. I don't think the average Python programmer needs to worry about the historical details; consult the Unicode consortium site listed in the References for more information.) Definitions '''''''''''''''''''''''' A **character** is the smallest possible component of a text. 'A', 'B', 'C', etc., are all different characters. So are 'È' and 'Í'. Characters are abstractions, and vary depending on the language or context you're talking about. For example, the symbol for ohms (Ω) is usually drawn much like the capital letter omega (Ω) in the Greek alphabet (they may even be the same in some fonts), but these are two different characters that have different meanings. The Unicode standard describes how characters are represented by **code points**. A code point is an integer value, usually denoted in base 16. In the standard, a code point is written using the notation U+12ca to mean the character with value 0x12ca (4810 decimal). The Unicode standard contains a lot of tables listing characters and their corresponding code points:: 0061 'a'; LATIN SMALL LETTER A 0062 'b'; LATIN SMALL LETTER B 0063 'c'; LATIN SMALL LETTER C ... 007B '{'; LEFT CURLY BRACKET Strictly, these definitions imply that it's meaningless to say 'this is character U+12ca'. U+12ca is a code point, which represents some particular character; in this case, it represents the character 'ETHIOPIC SYLLABLE WI'. In informal contexts, this distinction between code points and characters will sometimes be forgotten. A character is represented on a screen or on paper by a set of graphical elements that's called a **glyph**. The glyph for an uppercase A, for example, is two diagonal strokes and a horizontal stroke, though the exact details will depend on the font being used. Most Python code doesn't need to worry about glyphs; figuring out the correct glyph to display is generally the job of a GUI toolkit or a terminal's font renderer. Encodings ''''''''' To summarize the previous section: a Unicode string is a sequence of code points, which are numbers from 0 to 0x10ffff. This sequence needs to be represented as a set of bytes (meaning, values from 0-255) in memory. The rules for translating a Unicode string into a sequence of bytes are called an **encoding**. The first encoding you might think of is an array of 32-bit integers. In this representation, the string "Python" would look like this:: P y t h o n 0x50 00 00 00 79 00 00 00 74 00 00 00 68 00 00 00 6f 00 00 00 6e 00 00 00 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 This representation is straightforward but using it presents a number of problems. 1. It's not portable; different processors order the bytes differently. 2. It's very wasteful of space. In most texts, the majority of the code points are less than 127, or less than 255, so a lot of space is occupied by zero bytes. The above string takes 24 bytes compared to the 6 bytes needed for an ASCII representation. Increased RAM usage doesn't matter too much (desktop computers have megabytes of RAM, and strings aren't usually that large), but expanding our usage of disk and network bandwidth by a factor of 4 is intolerable. 3. It's not compatible with existing C functions such as ``strlen()``, so a new family of wide string functions would need to be used. 4. Many Internet standards are defined in terms of textual data, and can't handle content with embedded zero bytes. Generally people don't use this encoding, choosing other encodings that are more efficient and convenient. Encodings don't have to handle every possible Unicode character, and most encodings don't. For example, Python's default encoding is the 'ascii' encoding. The rules for converting a Unicode string into the ASCII encoding are are simple; for each code point: 1. If the code point is <128, each byte is the same as the value of the code point. 2. If the code point is 128 or greater, the Unicode string can't be represented in this encoding. (Python raises a ``UnicodeEncodeError`` exception in this case.) Latin-1, also known as ISO-8859-1, is a similar encoding. Unicode code points 0-255 are identical to the Latin-1 values, so converting to this encoding simply requires converting code points to byte values; if a code point larger than 255 is encountered, the string can't be encoded into Latin-1. Encodings don't have to be simple one-to-one mappings like Latin-1. Consider IBM's EBCDIC, which was used on IBM mainframes. Letter values weren't in one block: 'a' through 'i' had values from 129 to 137, but 'j' through 'r' were 145 through 153. If you wanted to use EBCDIC as an encoding, you'd probably use some sort of lookup table to perform the conversion, but this is largely an internal detail. UTF-8 is one of the most commonly used encodings. UTF stands for "Unicode Transformation Format", and the '8' means that 8-bit numbers are used in the encoding. (There's also a UTF-16 encoding, but it's less frequently used than UTF-8.) UTF-8 uses the following rules: 1. If the code point is <128, it's represented by the corresponding byte value. 2. If the code point is between 128 and 0x7ff, it's turned into two byte values between 128 and 255. 3. Code points >0x7ff are turned into three- or four-byte sequences, where each byte of the sequence is between 128 and 255. UTF-8 has several convenient properties: 1. It can handle any Unicode code point. 2. A Unicode string is turned into a string of bytes containing no embedded zero bytes. This avoids byte-ordering issues, and means UTF-8 strings can be processed by C functions such as ``strcpy()`` and sent through protocols that can't handle zero bytes. 3. A string of ASCII text is also valid UTF-8 text. 4. UTF-8 is fairly compact; the majority of code points are turned into two bytes, and values less than 128 occupy only a single byte. 5. If bytes are corrupted or lost, it's possible to determine the start of the next UTF-8-encoded code point and resynchronize. It's also unlikely that random 8-bit data will look like valid UTF-8. References '''''''''''''' The Unicode Consortium site at has character charts, a glossary, and PDF versions of the Unicode specification. Be prepared for some difficult reading. is a chronology of the origin and development of Unicode. To help understand the standard, Jukka Korpela has written an introductory guide to reading the Unicode character tables, available at . Roman Czyborra wrote another explanation of Unicode's basic principles; it's at . Czyborra has written a number of other Unicode-related documentation, available from . Two other good introductory articles were written by Joel Spolsky and Jason Orendorff . If this introduction didn't make things clear to you, you should try reading one of these alternate articles before continuing. Wikipedia entries are often helpful; see the entries for "character encoding" and UTF-8 , for example. Python's Unicode Support ------------------------ Now that you've learned the rudiments of Unicode, we can look at Python's Unicode features. The Unicode Type ''''''''''''''''''' Unicode strings are expressed as instances of the ``unicode`` type, one of Python's repertoire of built-in types. It derives from an abstract type called ``basestring``, which is also an ancestor of the ``str`` type; you can therefore check if a value is a string type with ``isinstance(value, basestring)``. Under the hood, Python represents Unicode strings as either 16- or 32-bit integers, depending on how the Python interpreter was compiled, but this The ``unicode()`` constructor has the signature ``unicode(string[, encoding, errors])``. All of its arguments should be 8-bit strings. The first argument is converted to Unicode using the specified encoding; if you leave off the ``encoding`` argument, the ASCII encoding is used for the conversion, so characters greater than 127 will be treated as errors:: >>> unicode('abcdef') u'abcdef' >>> s = unicode('abcdef') >>> type(s) >>> unicode('abcdef' + chr(255)) Traceback (most recent call last): File "", line 1, in ? UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 6: ordinal not in range(128) The ``errors`` argument specifies the response when the input string can't be converted according to the encoding's rules. Legal values for this argument are 'strict' (raise a ``UnicodeDecodeError`` exception), 'replace' (add U+FFFD, 'REPLACEMENT CHARACTER'), or 'ignore' (just leave the character out of the Unicode result). The following examples show the differences:: >>> unicode('\x80abc', errors='strict') Traceback (most recent call last): File "", line 1, in ? UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0: ordinal not in range(128) >>> unicode('\x80abc', errors='replace') u'\ufffdabc' >>> unicode('\x80abc', errors='ignore') u'abc' Encodings are specified as strings containing the encoding's name. Python 2.4 comes with roughly 100 different encodings; see the Python Library Reference at for a list. Some encodings have multiple names; for example, 'latin-1', 'iso_8859_1' and '8859' are all synonyms for the same encoding. One-character Unicode strings can also be created with the ``unichr()`` built-in function, which takes integers and returns a Unicode string of length 1 that contains the corresponding code point. The reverse operation is the built-in `ord()` function that takes a one-character Unicode string and returns the code point value:: >>> unichr(40960) u'\ua000' >>> ord(u'\ua000') 40960 Instances of the ``unicode`` type have many of the same methods as the 8-bit string type for operations such as searching and formatting:: >>> s = u'Was ever feather so lightly blown to and fro as this multitude?' >>> s.count('e') 5 >>> s.find('feather') 9 >>> s.find('bird') -1 >>> s.replace('feather', 'sand') u'Was ever sand so lightly blown to and fro as this multitude?' >>> s.upper() u'WAS EVER FEATHER SO LIGHTLY BLOWN TO AND FRO AS THIS MULTITUDE?' Note that the arguments to these methods can be Unicode strings or 8-bit strings. 8-bit strings will be converted to Unicode before carrying out the operation; Python's default ASCII encoding will be used, so characters greater than 127 will cause an exception:: >>> s.find('Was\x9f') Traceback (most recent call last): File "", line 1, in ? UnicodeDecodeError: 'ascii' codec can't decode byte 0x9f in position 3: ordinal not in range(128) >>> s.find(u'Was\x9f') -1 Much Python code that operates on strings will therefore work with Unicode strings without requiring any changes to the code. (Input and output code needs more updating for Unicode; more on this later.) Another important method is ``.encode([encoding], [errors='strict'])``, which returns an 8-bit string version of the Unicode string, encoded in the requested encoding. The ``errors`` parameter is the same as the parameter of the ``unicode()`` constructor, with one additional possibility; as well as 'strict', 'ignore', and 'replace', you can also pass 'xmlcharrefreplace' which uses XML's character references. The following example shows the different results:: >>> u = unichr(40960) + u'abcd' + unichr(1972) >>> u.encode('utf-8') '\xea\x80\x80abcd\xde\xb4' >>> u.encode('ascii') Traceback (most recent call last): File "", line 1, in ? UnicodeEncodeError: 'ascii' codec can't encode character '\ua000' in position 0: ordinal not in range(128) >>> u.encode('ascii', 'ignore') 'abcd' >>> u.encode('ascii', 'replace') '?abcd?' >>> u.encode('ascii', 'xmlcharrefreplace') 'ꀀabcd޴' Python's 8-bit strings have a ``.decode([encoding], [errors])`` method that interprets the string using the given encoding:: >>> u = unichr(40960) + u'abcd' + unichr(1972) # Assemble a string >>> utf8_version = u.encode('utf-8') # Encode as UTF-8 >>> type(utf8_version), utf8_version (, '\xea\x80\x80abcd\xde\xb4') >>> u2 = utf8_version.decode('utf-8') # Decode using UTF-8 >>> u == u2 # The two strings match True The low-level routines for registering and accessing the available encodings are found in the ``codecs`` module. However, the encoding and decoding functions returned by this module are usually more low-level than is comfortable, so I'm not going to describe the ``codecs`` module here. If you need to implement a completely new encoding, you'll need to learn about the ``codecs`` module interfaces, but implementing encodings is a specialized task that also won't be covered here. Consult the Python documentation to learn more about this module. The most commonly used part of the ``codecs`` module is the ``codecs.open()`` function which will be discussed in the section on input and output. Unicode Literals in Python Source Code '''''''''''''''''''''''''''''''''''''''''' In Python source code, Unicode literals are written as strings prefixed with the 'u' or 'U' character: ``u'abcdefghijk'``. Specific code points can be written using the ``\u`` escape sequence, which is followed by four hex digits giving the code point. The ``\U`` escape sequence is similar, but expects 8 hex digits, not 4. Unicode literals can also use the same escape sequences as 8-bit strings, including ``\x``, but ``\x`` only takes two hex digits so it can't express an arbitrary code point. Octal escapes can go up to U+01ff, which is octal 777. :: >>> s = u"a\xac\u1234\u20ac\U00008000" ^^^^ two-digit hex escape ^^^^^^ four-digit Unicode escape ^^^^^^^^^^ eight-digit Unicode escape >>> for c in s: print ord(c), ... 97 172 4660 8364 32768 Using escape sequences for code points greater than 127 is fine in small doses, but becomes an annoyance if you're using many accented characters, as you would in a program with messages in French or some other accent-using language. You can also assemble strings using the ``unichr()`` built-in function, but this is even more tedious. Ideally, you'd want to be able to write literals in your language's natural encoding. You could then edit Python source code with your favorite editor which would display the accented characters naturally, and have the right characters used at runtime. Python supports writing Unicode literals in any encoding, but you have to declare the encoding being used. This is done by including a special comment as either the first or second line of the source file:: #!/usr/bin/env python # -*- coding: latin-1 -*- u = u'abcdé' print ord(u[-1]) The syntax is inspired by Emacs's notation for specifying variables local to a file. Emacs supports many different variables, but Python only supports 'coding'. The ``-*-`` symbols indicate that the comment is special; within them, you must supply the name ``coding`` and the name of your chosen encoding, separated by ``':'``. If you don't include such a comment, the default encoding used will be ASCII. Versions of Python before 2.4 were Euro-centric and assumed Latin-1 as a default encoding for string literals; in Python 2.4, characters greater than 127 still work but result in a warning. For example, the following program has no encoding declaration:: #!/usr/bin/env python u = u'abcdé' print ord(u[-1]) When you run it with Python 2.4, it will output the following warning:: amk:~$ python p263.py sys:1: DeprecationWarning: Non-ASCII character '\xe9' in file p263.py on line 2, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details Unicode Properties ''''''''''''''''''' The Unicode specification includes a database of information about code points. For each code point that's defined, the information includes the character's name, its category, the numeric value if applicable (Unicode has characters representing the Roman numerals and fractions such as one-third and four-fifths). There are also properties related to the code point's use in bidirectional text and other display-related properties. The following program displays some information about several characters, and prints the numeric value of one particular character:: import unicodedata u = unichr(233) + unichr(0x0bf2) + unichr(3972) + unichr(6000) + unichr(13231) for i, c in enumerate(u): print i, '%04x' % ord(c), unicodedata.category(c), print unicodedata.name(c) # Get numeric value of second character print unicodedata.numeric(u[1]) When run, this prints:: 0 00e9 Ll LATIN SMALL LETTER E WITH ACUTE 1 0bf2 No TAMIL NUMBER ONE THOUSAND 2 0f84 Mn TIBETAN MARK HALANTA 3 1770 Lo TAGBANWA LETTER SA 4 33af So SQUARE RAD OVER S SQUARED 1000.0 The category codes are abbreviations describing the nature of the character. These are grouped into categories such as "Letter", "Number", "Punctuation", or "Symbol", which in turn are broken up into subcategories. To take the codes from the above output, ``'Ll'`` means 'Letter, lowercase', ``'No'`` means "Number, other", ``'Mn'`` is "Mark, nonspacing", and ``'So'`` is "Symbol, other". See for a list of category codes. References '''''''''''''' The Unicode and 8-bit string types are described in the Python library reference at . The documentation for the ``unicodedata`` module is at . The documentation for the ``codecs`` module is at . Marc-André Lemburg gave a presentation at EuroPython 2002 titled "Python and Unicode". A PDF version of his slides is available at , and is an excellent overview of the design of Python's Unicode features. Reading and Writing Unicode Data ---------------------------------------- Once you've written some code that works with Unicode data, the next problem is input/output. How do you get Unicode strings into your program, and how do you convert Unicode into a form suitable for storage or transmission? It's possible that you may not need to do anything depending on your input sources and output destinations; you should check whether the libraries used in your application support Unicode natively. XML parsers often return Unicode data, for example. Many relational databases also support Unicode-valued columns and can return Unicode values from an SQL query. Unicode data is usually converted to a particular encoding before it gets written to disk or sent over a socket. It's possible to do all the work yourself: open a file, read an 8-bit string from it, and convert the string with ``unicode(str, encoding)``. However, the manual approach is not recommended. One problem is the multi-byte nature of encodings; one Unicode character can be represented by several bytes. If you want to read the file in arbitrary-sized chunks (say, 1K or 4K), you need to write error-handling code to catch the case where only part of the bytes encoding a single Unicode character are read at the end of a chunk. One solution would be to read the entire file into memory and then perform the decoding, but that prevents you from working with files that are extremely large; if you need to read a 2Gb file, you need 2Gb of RAM. (More, really, since for at least a moment you'd need to have both the encoded string and its Unicode version in memory.) The solution would be to use the low-level decoding interface to catch the case of partial coding sequences. The work of implementing this has already been done for you: the ``codecs`` module includes a version of the ``open()`` function that returns a file-like object that assumes the file's contents are in a specified encoding and accepts Unicode parameters for methods such as ``.read()`` and ``.write()``. The function's parameters are ``open(filename, mode='rb', encoding=None, errors='strict', buffering=1)``. ``mode`` can be ``'r'``, ``'w'``, or ``'a'``, just like the corresponding parameter to the regular built-in ``open()`` function; add a ``'+'`` to update the file. ``buffering`` is similarly parallel to the standard function's parameter. ``encoding`` is a string giving the encoding to use; if it's left as ``None``, a regular Python file object that accepts 8-bit strings is returned. Otherwise, a wrapper object is returned, and data written to or read from the wrapper object will be converted as needed. ``errors`` specifies the action for encoding errors and can be one of the usual values of 'strict', 'ignore', and 'replace'. Reading Unicode from a file is therefore simple:: import codecs f = codecs.open('unicode.rst', encoding='utf-8') for line in f: print repr(line) It's also possible to open files in update mode, allowing both reading and writing:: f = codecs.open('test', encoding='utf-8', mode='w+') f.write(u'\u4500 blah blah blah\n') f.seek(0) print repr(f.readline()[:1]) f.close() Unicode character U+FEFF is used as a byte-order mark (BOM), and is often written as the first character of a file in order to assist with autodetection of the file's byte ordering. Some encodings, such as UTF-16, expect a BOM to be present at the start of a file; when such an encoding is used, the BOM will be automatically written as the first character and will be silently dropped when the file is read. There are variants of these encodings, such as 'utf-16-le' and 'utf-16-be' for little-endian and big-endian encodings, that specify one particular byte ordering and don't skip the BOM. Unicode filenames ''''''''''''''''''''''''' Most of the operating systems in common use today support filenames that contain arbitrary Unicode characters. Usually this is implemented by converting the Unicode string into some encoding that varies depending on the system. For example, MacOS X uses UTF-8 while Windows uses a configurable encoding; on Windows, Python uses the name "mbcs" to refer to whatever the currently configured encoding is. On Unix systems, there will only be a filesystem encoding if you've set the ``LANG`` or ``LC_CTYPE`` environment variables; if you haven't, the default encoding is ASCII. The ``sys.getfilesystemencoding()`` function returns the encoding to use on your current system, in case you want to do the encoding manually, but there's not much reason to bother. When opening a file for reading or writing, you can usually just provide the Unicode string as the filename, and it will be automatically converted to the right encoding for you:: filename = u'filename\u4500abc' f = open(filename, 'w') f.write('blah\n') f.close() Functions in the ``os`` module such as ``os.stat()`` will also accept Unicode filenames. ``os.listdir()``, which returns filenames, raises an issue: should it return the Unicode version of filenames, or should it return 8-bit strings containing the encoded versions? ``os.listdir()`` will do both, depending on whether you provided the directory path as an 8-bit string or a Unicode string. If you pass a Unicode string as the path, filenames will be decoded using the filesystem's encoding and a list of Unicode strings will be returned, while passing an 8-bit path will return the 8-bit versions of the filenames. For example, assuming the default filesystem encoding is UTF-8, running the following program:: fn = u'filename\u4500abc' f = open(fn, 'w') f.close() import os print os.listdir('.') print os.listdir(u'.') will produce the following output:: amk:~$ python t.py ['.svn', 'filename\xe4\x94\x80abc', ...] [u'.svn', u'filename\u4500abc', ...] The first list contains UTF-8-encoded filenames, and the second list contains the Unicode versions. Tips for Writing Unicode-aware Programs '''''''''''''''''''''''''''''''''''''''''''' This section provides some suggestions on writing software that deals with Unicode. The most important tip is: Software should only work with Unicode strings internally, converting to a particular encoding on output. If you attempt to write processing functions that accept both Unicode and 8-bit strings, you will find your program vulnerable to bugs wherever you combine the two different kinds of strings. Python's default encoding is ASCII, so whenever a character with an ASCII value >127 is in the input data, you'll get a ``UnicodeDecodeError`` because that character can't be handled by the ASCII encoding. It's easy to miss such problems if you only test your software with data that doesn't contain any accents; everything will seem to work, but there's actually a bug in your program waiting for the first user who attempts to use characters >127. A second tip, therefore, is: Include characters >127 and, even better, characters >255 in your test data. When using data coming from a web browser or some other untrusted source, a common technique is to check for illegal characters in a string before using the string in a generated command line or storing it in a database. If you're doing this, be careful to check the string once it's in the form that will be used or stored; it's possible for encodings to be used to disguise characters. This is especially true if the input data also specifies the encoding; many encodings leave the commonly checked-for characters alone, but Python includes some encodings such as ``'base64'`` that modify every single character. For example, let's say you have a content management system that takes a Unicode filename, and you want to disallow paths with a '/' character. You might write this code:: def read_file (filename, encoding): if '/' in filename: raise ValueError("'/' not allowed in filenames") unicode_name = filename.decode(encoding) f = open(unicode_name, 'r') # ... return contents of file ... However, if an attacker could specify the ``'base64'`` encoding, they could pass ``'L2V0Yy9wYXNzd2Q='``, which is the base-64 encoded form of the string ``'/etc/passwd'``, to read a system file. The above code looks for ``'/'`` characters in the encoded form and misses the dangerous character in the resulting decoded form. References '''''''''''''' The PDF slides for Marc-André Lemburg's presentation "Writing Unicode-aware Applications in Python" are available at and discuss questions of character encodings as well as how to internationalize and localize an application. Revision History and Acknowledgements ------------------------------------------ Thanks to the following people who have noted errors or offered suggestions on this article: Nicholas Bastin, Marius Gedminas, Kent Johnson, Ken Krugler, Marc-André Lemburg, Martin von Löwis. Version 1.0: posted August 5 2005. Version 1.01: posted August 7 2005. Corrects factual and markup errors; adds several links. Version 1.02: posted August 16 2005. Corrects factual errors. .. comment Additional topic: building Python w/ UCS2 or UCS4 support .. comment Describe obscure -U switch somewhere? .. comment Original outline: - [ ] Unicode introduction - [ ] ASCII - [ ] Terms - [ ] Character - [ ] Code point - [ ] Encodings - [ ] Common encodings: ASCII, Latin-1, UTF-8 - [ ] Unicode Python type - [ ] Writing unicode literals - [ ] Obscurity: -U switch - [ ] Built-ins - [ ] unichr() - [ ] ord() - [ ] unicode() constructor - [ ] Unicode type - [ ] encode(), decode() methods - [ ] Unicodedata module for character properties - [ ] I/O - [ ] Reading/writing Unicode data into files - [ ] Byte-order marks - [ ] Unicode filenames - [ ] Writing Unicode programs - [ ] Do everything in Unicode - [ ] Declaring source code encodings (PEP 263) - [ ] Other issues - [ ] Building Python (UCS2, UCS4) From akuchling at users.sourceforge.net Tue Aug 30 03:27:51 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue, 30 Aug 2005 03:27:51 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/howto rexec.tex,1.1,NONE Message-ID: <20050830012751.7F3231E400A@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/howto In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv908 Removed Files: rexec.tex Log Message: Remove rexec howto; it's kind of pointless now --- rexec.tex DELETED --- From akuchling at users.sourceforge.net Tue Aug 30 03:28:26 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Tue, 30 Aug 2005 03:28:26 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/howto TODO,NONE,1.1 Message-ID: <20050830012826.255521E400A@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/howto In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1080 Added Files: TODO Log Message: Add to-do list --- NEW FILE: TODO --- Short-term tasks: Quick revision pass to make HOWTOs match the current state of Python: advocacy curses doanddont regex sockets sorting Medium-term tasks: Revisit the regex howto. * Add exercises with answers for each section * More examples? Long-term tasks: Integrate with other Python docs? From nnorwitz at users.sourceforge.net Tue Aug 30 05:34:57 2005 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Tue, 30 Aug 2005 05:34:57 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/dist dist.tex,1.97,1.98 Message-ID: <20050830033457.3F66A1E400A@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/dist In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24228/Doc/dist Modified Files: dist.tex Log Message: SF #1275796, fix distutils typo "sortcut" -> "shortcut" Index: dist.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/dist/dist.tex,v retrieving revision 1.97 retrieving revision 1.98 diff -u -d -r1.97 -r1.98 --- dist.tex 27 Aug 2005 17:04:59 -0000 1.97 +++ dist.tex 30 Aug 2005 03:34:46 -0000 1.98 @@ -1657,7 +1657,7 @@ iconpath\optional{, iconindex}}}}} This function creates a shortcut. \var{target} is the path to the program to be started by the shortcut. - \var{description} is the description of the sortcut. + \var{description} is the description of the shortcut. \var{filename} is the title of the shortcut that the user will see. \var{arguments} specifies the command line arguments, if any. \var{workdir} is the working directory for the program. From nnorwitz at users.sourceforge.net Tue Aug 30 05:35:29 2005 From: nnorwitz at users.sourceforge.net (nnorwitz@users.sourceforge.net) Date: Tue, 30 Aug 2005 05:35:29 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/dist dist.tex, 1.86.2.6, 1.86.2.7 Message-ID: <20050830033529.EFDBE1E400A@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/dist In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24315/Doc/dist Modified Files: Tag: release24-maint dist.tex Log Message: SF #1275796, fix distutils typo "sortcut" -> "shortcut" Index: dist.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/dist/dist.tex,v retrieving revision 1.86.2.6 retrieving revision 1.86.2.7 diff -u -d -r1.86.2.6 -r1.86.2.7 --- dist.tex 22 Jul 2005 21:48:48 -0000 1.86.2.6 +++ dist.tex 30 Aug 2005 03:35:19 -0000 1.86.2.7 @@ -1581,7 +1581,7 @@ iconpath\optional{, iconindex}}}}} This function creates a shortcut. \var{target} is the path to the program to be started by the shortcut. - \var{description} is the description of the sortcut. + \var{description} is the description of the shortcut. \var{filename} is the title of the shortcut that the user will see. \var{arguments} specifies the command line arguments, if any. \var{workdir} is the working directory for the program. From doerwalter at users.sourceforge.net Tue Aug 30 12:23:25 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:23:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS,1.1357,1.1358 Message-ID: <20050830102325.67B2E1E400A@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1718/Misc Modified Files: NEWS Log Message: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the Nik Haldimann's patch that detects truncated data) Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1357 retrieving revision 1.1358 diff -u -d -r1.1357 -r1.1358 --- NEWS 27 Aug 2005 10:07:56 -0000 1.1357 +++ NEWS 30 Aug 2005 10:23:13 -0000 1.1358 @@ -435,6 +435,10 @@ line ending. Remove the special handling of a "\r\n" that has been split between two lines. +- Bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain + about illegal code points. The codec now supports PEP 293 style error + handlers. + Build ----- From doerwalter at users.sourceforge.net Tue Aug 30 12:23:25 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:23:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules _codecsmodule.c, 2.21, 2.22 Message-ID: <20050830102325.69BEA1E400B@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1718/Modules Modified Files: _codecsmodule.c Log Message: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the Nik Haldimann's patch that detects truncated data) Index: _codecsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/_codecsmodule.c,v retrieving revision 2.21 retrieving revision 2.22 diff -u -d -r2.21 -r2.22 --- _codecsmodule.c 8 Mar 2005 15:03:08 -0000 2.21 +++ _codecsmodule.c 30 Aug 2005 10:23:14 -0000 2.22 @@ -254,8 +254,8 @@ else { if (PyObject_AsReadBuffer(obj, (const void **)&data, &size)) return NULL; - return codec_tuple(PyUnicode_FromUnicode((Py_UNICODE *)data, - size / sizeof(Py_UNICODE)), + + return codec_tuple(_PyUnicode_DecodeUnicodeInternal(data, size, errors), size); } } From doerwalter at users.sourceforge.net Tue Aug 30 12:23:25 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:23:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Include unicodeobject.h, 2.48, 2.49 Message-ID: <20050830102325.77A511E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1718/Include Modified Files: unicodeobject.h Log Message: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the Nik Haldimann's patch that detects truncated data) Index: unicodeobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/unicodeobject.h,v retrieving revision 2.48 retrieving revision 2.49 diff -u -d -r2.48 -r2.49 --- unicodeobject.h 22 Nov 2004 13:02:29 -0000 2.48 +++ unicodeobject.h 30 Aug 2005 10:23:13 -0000 2.49 @@ -797,6 +797,16 @@ int length /* Number of Py_UNICODE chars to encode */ ); +/* --- Unicode Internal Codec --------------------------------------------- + + Only for internal use in _codecsmodule.c */ + +PyObject *_PyUnicode_DecodeUnicodeInternal( + const char *string, + int length, + const char *errors + ); + /* --- Latin-1 Codecs ----------------------------------------------------- Note: Latin-1 corresponds to the first 256 Unicode ordinals. From doerwalter at users.sourceforge.net Tue Aug 30 12:23:25 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:23:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_codeccallbacks.py, 1.17, 1.18 test_codecs.py, 1.25, 1.26 Message-ID: <20050830102325.9D4861E4011@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1718/Lib/test Modified Files: test_codeccallbacks.py test_codecs.py Log Message: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the Nik Haldimann's patch that detects truncated data) Index: test_codeccallbacks.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_codeccallbacks.py,v retrieving revision 1.17 retrieving revision 1.18 diff -u -d -r1.17 -r1.18 --- test_codeccallbacks.py 14 Dec 2004 21:28:07 -0000 1.17 +++ test_codeccallbacks.py 30 Aug 2005 10:23:13 -0000 1.18 @@ -111,7 +111,7 @@ sout += "\\U%08x" % sys.maxunicode self.assertEqual(sin.encode("iso-8859-15", "backslashreplace"), sout) - def test_relaxedutf8(self): + def test_decoderelaxedutf8(self): # This is the test for a decoding callback handler, # that relaxes the UTF-8 minimal encoding restriction. # A null byte that is encoded as "\xc0\x80" will be @@ -158,6 +158,35 @@ charmap[ord("?")] = u"XYZ" self.assertRaises(TypeError, codecs.charmap_encode, sin, "replace", charmap) + def test_decodeunicodeinternal(self): + self.assertRaises( + UnicodeDecodeError, + "\x00\x00\x00\x00\x00".decode, + "unicode-internal", + ) + if sys.maxunicode > 0xffff: + def handler_unicodeinternal(exc): + if not isinstance(exc, UnicodeDecodeError): + raise TypeError("don't know how to handle %r" % exc) + return (u"\x01", 1) + + self.assertEqual( + "\x00\x00\x00\x00\x00".decode("unicode-internal", "ignore"), + u"\u0000" + ) + + self.assertEqual( + "\x00\x00\x00\x00\x00".decode("unicode-internal", "replace"), + u"\u0000\ufffd" + ) + + codecs.register_error("test.hui", handler_unicodeinternal) + + self.assertEqual( + "\x00\x00\x00\x00\x00".decode("unicode-internal", "test.hui"), + u"\u0000\u0001\u0000" + ) + def test_callbacks(self): def handler1(exc): if not isinstance(exc, UnicodeEncodeError) \ @@ -503,7 +532,8 @@ for (enc, bytes) in ( ("ascii", "\xff"), ("utf-8", "\xff"), - ("utf-7", "+x-") + ("utf-7", "+x-"), + ("unicode-internal", "\x00"), ): self.assertRaises( TypeError, Index: test_codecs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_codecs.py,v retrieving revision 1.25 retrieving revision 1.26 diff -u -d -r1.25 -r1.26 --- test_codecs.py 25 Aug 2005 11:03:38 -0000 1.25 +++ test_codecs.py 30 Aug 2005 10:23:13 -0000 1.26 @@ -1,7 +1,7 @@ from test import test_support import unittest import codecs -import StringIO +import sys, StringIO class Queue(object): """ @@ -453,6 +453,54 @@ for uni, puny in punycode_testcases: self.assertEquals(uni, puny.decode("punycode")) +class UnicodeInternalTest(unittest.TestCase): + def test_bug1251300(self): + # Decoding with unicode_internal used to not correctly handle "code + # points" above 0x10ffff on UCS-4 builds. + if sys.maxunicode > 0xffff: + ok = [ + ("\x00\x10\xff\xff", u"\U0010ffff"), + ("\x00\x00\x01\x01", u"\U00000101"), + ("", u""), + ] + not_ok = [ + "\x7f\xff\xff\xff", + "\x80\x00\x00\x00", + "\x81\x00\x00\x00", + "\x00", + "\x00\x00\x00\x00\x00", + ] + for internal, uni in ok: + if sys.byteorder == "little": + internal = "".join(reversed(internal)) + self.assertEquals(uni, internal.decode("unicode_internal")) + for internal in not_ok: + if sys.byteorder == "little": + internal = "".join(reversed(internal)) + self.assertRaises(UnicodeDecodeError, internal.decode, + "unicode_internal") + + def test_decode_error_attributes(self): + if sys.maxunicode > 0xffff: + try: + "\x00\x00\x00\x00\x00\x11\x11\x00".decode("unicode_internal") + except UnicodeDecodeError, ex: + self.assertEquals("unicode_internal", ex.encoding) + self.assertEquals("\x00\x00\x00\x00\x00\x11\x11\x00", ex.object) + self.assertEquals(4, ex.start) + self.assertEquals(8, ex.end) + else: + self.fail() + + def test_decode_callback(self): + if sys.maxunicode > 0xffff: + codecs.register_error("UnicodeInternalTest", codecs.ignore_errors) + decoder = codecs.getdecoder("unicode_internal") + ab = u"ab".encode("unicode_internal") + ignored = decoder("%s\x22\x22\x22\x22%s" % (ab[:4], ab[4:]), + "UnicodeInternalTest") + self.assertEquals((u"ab", 12), ignored) + # From http://www.gnu.org/software/libidn/draft-josefsson-idn-test-vectors.html nameprep_tests = [ # 3.1 Map to nothing. @@ -885,6 +933,7 @@ EscapeDecodeTest, RecodingTest, PunycodeTest, + UnicodeInternalTest, NameprepTest, CodecTest, CodecsModuleTest, From doerwalter at users.sourceforge.net Tue Aug 30 12:23:25 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:23:25 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects unicodeobject.c, 2.230, 2.231 Message-ID: <20050830102325.A9DEF1E400A@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1718/Objects Modified Files: unicodeobject.c Log Message: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the Nik Haldimann's patch that detects truncated data) Index: unicodeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/unicodeobject.c,v retrieving revision 2.230 retrieving revision 2.231 diff -u -d -r2.230 -r2.231 --- unicodeobject.c 22 Nov 2004 13:02:30 -0000 2.230 +++ unicodeobject.c 30 Aug 2005 10:23:14 -0000 2.231 @@ -2273,6 +2273,81 @@ PyUnicode_GET_SIZE(unicode)); } +/* --- Unicode Internal Codec ------------------------------------------- */ + +PyObject *_PyUnicode_DecodeUnicodeInternal(const char *s, + int size, + const char *errors) +{ + const char *starts = s; + int startinpos; + int endinpos; + int outpos; + Py_UNICODE unimax; + PyUnicodeObject *v; + Py_UNICODE *p; + const char *end; + const char *reason; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + + unimax = PyUnicode_GetMax(); + v = _PyUnicode_New((size+Py_UNICODE_SIZE-1)/ Py_UNICODE_SIZE); + if (v == NULL) + goto onError; + if (PyUnicode_GetSize((PyObject *)v) == 0) + return (PyObject *)v; + p = PyUnicode_AS_UNICODE(v); + end = s + size; + + while (s < end) { + *p = *(Py_UNICODE *)s; + /* We have to sanity check the raw data, otherwise doom looms for + some malformed UCS-4 data. */ + if ( + #ifdef Py_UNICODE_WIDE + *p > unimax || *p < 0 || + #endif + end-s < Py_UNICODE_SIZE + ) + { + startinpos = s - starts; + if (end-s < Py_UNICODE_SIZE) { + endinpos = end-starts; + reason = "truncated input"; + } + else { + endinpos = s - starts + Py_UNICODE_SIZE; + reason = "illegal code point (> 0x10FFFF)"; + } + outpos = p - PyUnicode_AS_UNICODE(v); + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "unicode_internal", reason, + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) { + goto onError; + } + } + else { + p++; + s += Py_UNICODE_SIZE; + } + } + + if (_PyUnicode_Resize(&v, (int)(p - PyUnicode_AS_UNICODE(v))) < 0) + goto onError; + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)v; + + onError: + Py_XDECREF(v); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return NULL; +} + /* --- Latin-1 Codec ------------------------------------------------------ */ PyObject *PyUnicode_DecodeLatin1(const char *s, From doerwalter at users.sourceforge.net Tue Aug 30 12:46:16 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:46:16 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Include unicodeobject.h, 2.48, 2.48.2.1 Message-ID: <20050830104616.5AA621E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5498/Include Modified Files: Tag: release24-maint unicodeobject.h Log Message: Backport checkin: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the patch by Nik Haldimann that detects truncated data) Index: unicodeobject.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/unicodeobject.h,v retrieving revision 2.48 retrieving revision 2.48.2.1 diff -u -d -r2.48 -r2.48.2.1 --- unicodeobject.h 22 Nov 2004 13:02:29 -0000 2.48 +++ unicodeobject.h 30 Aug 2005 10:46:05 -0000 2.48.2.1 @@ -797,6 +797,16 @@ int length /* Number of Py_UNICODE chars to encode */ ); +/* --- Unicode Internal Codec --------------------------------------------- + + Only for internal use in _codecsmodule.c */ + +PyObject *_PyUnicode_DecodeUnicodeInternal( + const char *string, + int length, + const char *errors + ); + /* --- Latin-1 Codecs ----------------------------------------------------- Note: Latin-1 corresponds to the first 256 Unicode ordinals. From doerwalter at users.sourceforge.net Tue Aug 30 12:46:16 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:46:16 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.1193.2.91, 1.1193.2.92 Message-ID: <20050830104616.A3D7C1E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5498/Misc Modified Files: Tag: release24-maint NEWS Log Message: Backport checkin: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the patch by Nik Haldimann that detects truncated data) Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.1193.2.91 retrieving revision 1.1193.2.92 diff -u -d -r1.1193.2.91 -r1.1193.2.92 --- NEWS 27 Aug 2005 19:29:21 -0000 1.1193.2.91 +++ NEWS 30 Aug 2005 10:46:06 -0000 1.1193.2.92 @@ -137,6 +137,10 @@ line ending. Remove the special handling of a "\r\n" that has been split between two lines. +- Bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain + about illegal code points. The codec now supports PEP 293 style error + handlers. + Build ----- From doerwalter at users.sourceforge.net Tue Aug 30 12:46:16 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:46:16 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_codeccallbacks.py, 1.16.4.1, 1.16.4.2 test_codecs.py, 1.15.2.7, 1.15.2.8 Message-ID: <20050830104616.AC4EC1E4010@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5498/Lib/test Modified Files: Tag: release24-maint test_codeccallbacks.py test_codecs.py Log Message: Backport checkin: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the patch by Nik Haldimann that detects truncated data) Index: test_codeccallbacks.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_codeccallbacks.py,v retrieving revision 1.16.4.1 retrieving revision 1.16.4.2 diff -u -d -r1.16.4.1 -r1.16.4.2 --- test_codeccallbacks.py 14 Dec 2004 21:33:13 -0000 1.16.4.1 +++ test_codeccallbacks.py 30 Aug 2005 10:46:06 -0000 1.16.4.2 @@ -111,7 +111,7 @@ sout += "\\U%08x" % sys.maxunicode self.assertEqual(sin.encode("iso-8859-15", "backslashreplace"), sout) - def test_relaxedutf8(self): + def test_decoderelaxedutf8(self): # This is the test for a decoding callback handler, # that relaxes the UTF-8 minimal encoding restriction. # A null byte that is encoded as "\xc0\x80" will be @@ -158,6 +158,35 @@ charmap[ord("?")] = u"XYZ" self.assertRaises(TypeError, codecs.charmap_encode, sin, "replace", charmap) + def test_decodeunicodeinternal(self): + self.assertRaises( + UnicodeDecodeError, + "\x00\x00\x00\x00\x00".decode, + "unicode-internal", + ) + if sys.maxunicode > 0xffff: + def handler_unicodeinternal(exc): + if not isinstance(exc, UnicodeDecodeError): + raise TypeError("don't know how to handle %r" % exc) + return (u"\x01", 1) + + self.assertEqual( + "\x00\x00\x00\x00\x00".decode("unicode-internal", "ignore"), + u"\u0000" + ) + + self.assertEqual( + "\x00\x00\x00\x00\x00".decode("unicode-internal", "replace"), + u"\u0000\ufffd" + ) + + codecs.register_error("test.hui", handler_unicodeinternal) + + self.assertEqual( + "\x00\x00\x00\x00\x00".decode("unicode-internal", "test.hui"), + u"\u0000\u0001\u0000" + ) + def test_callbacks(self): def handler1(exc): if not isinstance(exc, UnicodeEncodeError) \ @@ -503,7 +532,8 @@ for (enc, bytes) in ( ("ascii", "\xff"), ("utf-8", "\xff"), - ("utf-7", "+x-") + ("utf-7", "+x-"), + ("unicode-internal", "\x00"), ): self.assertRaises( TypeError, Index: test_codecs.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_codecs.py,v retrieving revision 1.15.2.7 retrieving revision 1.15.2.8 diff -u -d -r1.15.2.7 -r1.15.2.8 --- test_codecs.py 25 Aug 2005 11:04:04 -0000 1.15.2.7 +++ test_codecs.py 30 Aug 2005 10:46:06 -0000 1.15.2.8 @@ -1,7 +1,7 @@ from test import test_support import unittest import codecs -import StringIO +import sys, StringIO class Queue(object): """ @@ -455,6 +455,54 @@ for uni, puny in punycode_testcases: self.assertEquals(uni, puny.decode("punycode")) +class UnicodeInternalTest(unittest.TestCase): + def test_bug1251300(self): + # Decoding with unicode_internal used to not correctly handle "code + # points" above 0x10ffff on UCS-4 builds. + if sys.maxunicode > 0xffff: + ok = [ + ("\x00\x10\xff\xff", u"\U0010ffff"), + ("\x00\x00\x01\x01", u"\U00000101"), + ("", u""), + ] + not_ok = [ + "\x7f\xff\xff\xff", + "\x80\x00\x00\x00", + "\x81\x00\x00\x00", + "\x00", + "\x00\x00\x00\x00\x00", + ] + for internal, uni in ok: + if sys.byteorder == "little": + internal = "".join(reversed(internal)) + self.assertEquals(uni, internal.decode("unicode_internal")) + for internal in not_ok: + if sys.byteorder == "little": + internal = "".join(reversed(internal)) + self.assertRaises(UnicodeDecodeError, internal.decode, + "unicode_internal") + + def test_decode_error_attributes(self): + if sys.maxunicode > 0xffff: + try: + "\x00\x00\x00\x00\x00\x11\x11\x00".decode("unicode_internal") + except UnicodeDecodeError, ex: + self.assertEquals("unicode_internal", ex.encoding) + self.assertEquals("\x00\x00\x00\x00\x00\x11\x11\x00", ex.object) + self.assertEquals(4, ex.start) + self.assertEquals(8, ex.end) + else: + self.fail() + + def test_decode_callback(self): + if sys.maxunicode > 0xffff: + codecs.register_error("UnicodeInternalTest", codecs.ignore_errors) + decoder = codecs.getdecoder("unicode_internal") + ab = u"ab".encode("unicode_internal") + ignored = decoder("%s\x22\x22\x22\x22%s" % (ab[:4], ab[4:]), + "UnicodeInternalTest") + self.assertEquals((u"ab", 12), ignored) + # From http://www.gnu.org/software/libidn/draft-josefsson-idn-test-vectors.html nameprep_tests = [ # 3.1 Map to nothing. @@ -696,6 +744,7 @@ EscapeDecodeTest, RecodingTest, PunycodeTest, + UnicodeInternalTest, NameprepTest, CodecTest, CodecsModuleTest, From doerwalter at users.sourceforge.net Tue Aug 30 12:46:16 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:46:16 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules _codecsmodule.c, 2.20.2.1, 2.20.2.2 Message-ID: <20050830104616.B084D1E4011@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5498/Modules Modified Files: Tag: release24-maint _codecsmodule.c Log Message: Backport checkin: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the patch by Nik Haldimann that detects truncated data) Index: _codecsmodule.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/_codecsmodule.c,v retrieving revision 2.20.2.1 retrieving revision 2.20.2.2 diff -u -d -r2.20.2.1 -r2.20.2.2 --- _codecsmodule.c 8 Mar 2005 15:05:17 -0000 2.20.2.1 +++ _codecsmodule.c 30 Aug 2005 10:46:06 -0000 2.20.2.2 @@ -254,8 +254,8 @@ else { if (PyObject_AsReadBuffer(obj, (const void **)&data, &size)) return NULL; - return codec_tuple(PyUnicode_FromUnicode((Py_UNICODE *)data, - size / sizeof(Py_UNICODE)), + + return codec_tuple(_PyUnicode_DecodeUnicodeInternal(data, size, errors), size); } } From doerwalter at users.sourceforge.net Tue Aug 30 12:46:17 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Tue, 30 Aug 2005 12:46:17 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Objects unicodeobject.c, 2.230, 2.230.2.1 Message-ID: <20050830104617.02E311E400E@bag.python.org> Update of /cvsroot/python/python/dist/src/Objects In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5498/Objects Modified Files: Tag: release24-maint unicodeobject.c Log Message: Backport checkin: SF bug #1251300: On UCS-4 builds the "unicode-internal" codec will now complain about illegal code points. The codec now supports PEP 293 style error handlers. (This is a variant of the patch by Nik Haldimann that detects truncated data) Index: unicodeobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/unicodeobject.c,v retrieving revision 2.230 retrieving revision 2.230.2.1 diff -u -d -r2.230 -r2.230.2.1 --- unicodeobject.c 22 Nov 2004 13:02:30 -0000 2.230 +++ unicodeobject.c 30 Aug 2005 10:46:06 -0000 2.230.2.1 @@ -2273,6 +2273,81 @@ PyUnicode_GET_SIZE(unicode)); } +/* --- Unicode Internal Codec ------------------------------------------- */ + +PyObject *_PyUnicode_DecodeUnicodeInternal(const char *s, + int size, + const char *errors) +{ + const char *starts = s; + int startinpos; + int endinpos; + int outpos; + Py_UNICODE unimax; + PyUnicodeObject *v; + Py_UNICODE *p; + const char *end; + const char *reason; + PyObject *errorHandler = NULL; + PyObject *exc = NULL; + + unimax = PyUnicode_GetMax(); + v = _PyUnicode_New((size+Py_UNICODE_SIZE-1)/ Py_UNICODE_SIZE); + if (v == NULL) + goto onError; + if (PyUnicode_GetSize((PyObject *)v) == 0) + return (PyObject *)v; + p = PyUnicode_AS_UNICODE(v); + end = s + size; + + while (s < end) { + *p = *(Py_UNICODE *)s; + /* We have to sanity check the raw data, otherwise doom looms for + some malformed UCS-4 data. */ + if ( + #ifdef Py_UNICODE_WIDE + *p > unimax || *p < 0 || + #endif + end-s < Py_UNICODE_SIZE + ) + { + startinpos = s - starts; + if (end-s < Py_UNICODE_SIZE) { + endinpos = end-starts; + reason = "truncated input"; + } + else { + endinpos = s - starts + Py_UNICODE_SIZE; + reason = "illegal code point (> 0x10FFFF)"; + } + outpos = p - PyUnicode_AS_UNICODE(v); + if (unicode_decode_call_errorhandler( + errors, &errorHandler, + "unicode_internal", reason, + starts, size, &startinpos, &endinpos, &exc, &s, + (PyObject **)&v, &outpos, &p)) { + goto onError; + } + } + else { + p++; + s += Py_UNICODE_SIZE; + } + } + + if (_PyUnicode_Resize(&v, (int)(p - PyUnicode_AS_UNICODE(v))) < 0) + goto onError; + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return (PyObject *)v; + + onError: + Py_XDECREF(v); + Py_XDECREF(errorHandler); + Py_XDECREF(exc); + return NULL; +} + /* --- Latin-1 Codec ------------------------------------------------------ */ PyObject *PyUnicode_DecodeLatin1(const char *s, From anthonybaxter at users.sourceforge.net Tue Aug 30 14:26:54 2005 From: anthonybaxter at users.sourceforge.net (anthonybaxter@users.sourceforge.net) Date: Tue, 30 Aug 2005 14:26:54 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Include patchlevel.h, 2.83.2.6, 2.83.2.7 Message-ID: <20050830122654.4F1FF1E4009@bag.python.org> Update of /cvsroot/python/python/dist/src/Include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30627/Include Modified Files: Tag: release24-maint patchlevel.h Log Message: Make testing a bit easier Index: patchlevel.h =================================================================== RCS file: /cvsroot/python/python/dist/src/Include/patchlevel.h,v retrieving revision 2.83.2.6 retrieving revision 2.83.2.7 diff -u -d -r2.83.2.6 -r2.83.2.7 --- patchlevel.h 29 Mar 2005 12:33:33 -0000 2.83.2.6 +++ patchlevel.h 30 Aug 2005 12:26:43 -0000 2.83.2.7 @@ -26,7 +26,7 @@ #define PY_RELEASE_SERIAL 0 /* Version as a string */ -#define PY_VERSION "2.4.1" +#define PY_VERSION "2.4.1+" /* 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 nascheme at users.sourceforge.net Wed Aug 31 01:37:56 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Wed, 31 Aug 2005 01:37:56 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python ast.c,1.1.2.63,1.1.2.64 Message-ID: <20050830233756.860271E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24681 Modified Files: Tag: ast-branch ast.c Log Message: Add a high-level comment to ast.c module. Index: ast.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/Attic/ast.c,v retrieving revision 1.1.2.63 retrieving revision 1.1.2.64 diff -u -d -r1.1.2.63 -r1.1.2.64 --- ast.c 2 Jun 2005 05:34:35 -0000 1.1.2.63 +++ ast.c 30 Aug 2005 23:37:45 -0000 1.1.2.64 @@ -1,3 +1,8 @@ +/* + * This file includes functions to transform a concrete syntax tree (CST) to + * an abstract syntax tree (AST). The main function is PyAST_FromNode(). + * + */ #include "Python.h" #include "Python-ast.h" #include "grammar.h" From nascheme at users.sourceforge.net Wed Aug 31 02:25:34 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Wed, 31 Aug 2005 02:25:34 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python symtable.c, 2.10.8.34, 2.10.8.35 Message-ID: <20050831002534.42F2D1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv32155/Python Modified Files: Tag: ast-branch symtable.c Log Message: Don't abort generation of the symtable after issuing a warning about a global declaration. Index: symtable.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/symtable.c,v retrieving revision 2.10.8.34 retrieving revision 2.10.8.35 diff -u -d -r2.10.8.34 -r2.10.8.35 --- symtable.c 11 Jul 2005 03:52:47 -0000 2.10.8.34 +++ symtable.c 31 Aug 2005 00:25:23 -0000 2.10.8.35 @@ -904,7 +904,6 @@ GLOBAL_AFTER_USE, c_name); symtable_warn(st, buf); - return 0; } if (!symtable_add_def(st, name, DEF_GLOBAL)) return 0; From nascheme at users.sourceforge.net Wed Aug 31 03:48:53 2005 From: nascheme at users.sourceforge.net (nascheme@users.sourceforge.net) Date: Wed, 31 Aug 2005 03:48:53 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Python symtable.c, 2.10.8.35, 2.10.8.36 Message-ID: <20050831014853.5F8D71E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Python In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15719/Python Modified Files: Tag: ast-branch symtable.c Log Message: Generate SyntaxWarning for 'import *' at non-module scope. Index: symtable.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Python/symtable.c,v retrieving revision 2.10.8.35 retrieving revision 2.10.8.36 diff -u -d -r2.10.8.35 -r2.10.8.36 --- symtable.c 31 Aug 2005 00:25:23 -0000 2.10.8.35 +++ symtable.c 31 Aug 2005 01:48:41 -0000 2.10.8.36 @@ -903,7 +903,8 @@ PyOS_snprintf(buf, sizeof(buf), GLOBAL_AFTER_USE, c_name); - symtable_warn(st, buf); + if (!symtable_warn(st, buf)) + return 0; } if (!symtable_add_def(st, name, DEF_GLOBAL)) return 0; @@ -1128,6 +1129,11 @@ if (strcmp(PyString_AS_STRING(name), "*")) return symtable_add_def(st, name, DEF_IMPORT); else { + if (st->st_cur->ste_type != ModuleBlock) { + if (!symtable_warn(st, + "import * only allowed at module level")) + return 0; + } st->st_cur->ste_optimized = 0; return 1; } From pierslauder at users.sourceforge.net Wed Aug 31 12:46:44 2005 From: pierslauder at users.sourceforge.net (pierslauder@users.sourceforge.net) Date: Wed, 31 Aug 2005 12:46:44 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib imaplib.py,1.77,1.78 Message-ID: <20050831104644.052D31E4006@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16634/dist/src/Lib Modified Files: imaplib.py Log Message: changed select() so readonly flag is treated as a boolean Index: imaplib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/imaplib.py,v retrieving revision 1.77 retrieving revision 1.78 diff -u -d -r1.77 -r1.78 --- imaplib.py 5 Jul 2005 04:20:07 -0000 1.77 +++ imaplib.py 31 Aug 2005 10:46:29 -0000 1.78 @@ -155,7 +155,7 @@ self.tagged_commands = {} # Tagged commands awaiting response self.untagged_responses = {} # {typ: [data, ...], ...} self.continuation_response = '' # Last continuation response - self.is_readonly = None # READ-ONLY desired state + self.is_readonly = False # READ-ONLY desired state self.tagnum = 0 # Open socket to server. @@ -622,12 +622,12 @@ return self._untagged_response(typ, dat, name) - def select(self, mailbox='INBOX', readonly=None): + def select(self, mailbox='INBOX', readonly=False): """Select a mailbox. Flush all untagged responses. - (typ, [data]) = .select(mailbox='INBOX', readonly=None) + (typ, [data]) = .select(mailbox='INBOX', readonly=False) 'data' is count of messages in mailbox ('EXISTS' response). @@ -636,7 +636,7 @@ """ self.untagged_responses = {} # Flush old responses. self.is_readonly = readonly - if readonly is not None: + if readonly: name = 'EXAMINE' else: name = 'SELECT' From pierslauder at users.sourceforge.net Wed Aug 31 12:50:14 2005 From: pierslauder at users.sourceforge.net (pierslauder@users.sourceforge.net) Date: Wed, 31 Aug 2005 12:50:14 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib imaplib.py,1.78,1.79 Message-ID: <20050831105014.765791E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19378/dist/src/Lib Modified Files: imaplib.py Log Message: updated __version__ Index: imaplib.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/imaplib.py,v retrieving revision 1.78 retrieving revision 1.79 diff -u -d -r1.78 -r1.79 --- imaplib.py 31 Aug 2005 10:46:29 -0000 1.78 +++ imaplib.py 31 Aug 2005 10:50:03 -0000 1.79 @@ -20,7 +20,7 @@ # PROXYAUTH contributed by Rick Holbert November 2002. # GET/SETANNOTATION contributed by Tomas Lindroos June 2005. -__version__ = "2.57" +__version__ = "2.58" import binascii, os, random, re, socket, sys, time From doerwalter at users.sourceforge.net Wed Aug 31 13:03:23 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Wed, 31 Aug 2005 13:03:23 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib liburlparse.tex, 1.22, 1.23 Message-ID: <20050831110323.60D6A1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv29116/Doc/lib Modified Files: liburlparse.tex Log Message: SF bug #1277016: Turn sentence fragment into a complete sentence. Index: liburlparse.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liburlparse.tex,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- liburlparse.tex 17 Oct 2002 19:23:43 -0000 1.22 +++ liburlparse.tex 31 Aug 2005 11:03:12 -0000 1.23 @@ -69,9 +69,9 @@ params from the URL. This should generally be used instead of \function{urlparse()} if the more recent URL syntax allowing parameters to be applied to each segment of the \var{path} portion of -the URL (see \rfc{2396}). A separate function is needed to separate -the path segments and parameters. This function returns a 5-tuple: -(addressing scheme, network location, path, query, fragment +the URL (see \rfc{2396}) is wanted. A separate function is needed to +separate the path segments and parameters. This function returns a +5-tuple: (addressing scheme, network location, path, query, fragment identifier). \versionadded{2.2} \end{funcdesc} From doerwalter at users.sourceforge.net Wed Aug 31 13:05:11 2005 From: doerwalter at users.sourceforge.net (doerwalter@users.sourceforge.net) Date: Wed, 31 Aug 2005 13:05:11 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib liburlparse.tex, 1.22, 1.22.20.1 Message-ID: <20050831110511.CDB631E404A@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30760/Doc/lib Modified Files: Tag: release24-maint liburlparse.tex Log Message: Backport checkin: SF bug #1277016: Turn sentence fragment into a complete sentence. Index: liburlparse.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/liburlparse.tex,v retrieving revision 1.22 retrieving revision 1.22.20.1 diff -u -d -r1.22 -r1.22.20.1 --- liburlparse.tex 17 Oct 2002 19:23:43 -0000 1.22 +++ liburlparse.tex 31 Aug 2005 11:05:01 -0000 1.22.20.1 @@ -69,9 +69,9 @@ params from the URL. This should generally be used instead of \function{urlparse()} if the more recent URL syntax allowing parameters to be applied to each segment of the \var{path} portion of -the URL (see \rfc{2396}). A separate function is needed to separate -the path segments and parameters. This function returns a 5-tuple: -(addressing scheme, network location, path, query, fragment +the URL (see \rfc{2396}) is wanted. A separate function is needed to +separate the path segments and parameters. This function returns a +5-tuple: (addressing scheme, network location, path, query, fragment identifier). \versionadded{2.2} \end{funcdesc} From akuchling at users.sourceforge.net Wed Aug 31 14:55:32 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed, 31 Aug 2005 14:55:32 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Modules pypcre.c, 2.25.16.1, 2.25.16.2 Message-ID: <20050831125532.F21951E4077@bag.python.org> Update of /cvsroot/python/python/dist/src/Modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12325 Modified Files: Tag: release23-maint pypcre.c Log Message: Apply fix for potential heap overflow in PCRE code (CAN-2005-2491) Index: pypcre.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Modules/Attic/pypcre.c,v retrieving revision 2.25.16.1 retrieving revision 2.25.16.2 diff -u -d -r2.25.16.1 -r2.25.16.2 --- pypcre.c 20 Oct 2003 14:34:47 -0000 2.25.16.1 +++ pypcre.c 31 Aug 2005 12:55:21 -0000 2.25.16.2 @@ -1163,7 +1163,18 @@ int min = 0; int max = -1; +/* Read the minimum value and do a paranoid check: a negative value indicates +an integer overflow. */ + while ((pcre_ctypes[*p] & ctype_digit) != 0) min = min * 10 + *p++ - '0'; +if (min < 0 || min > 65535) + { + *errorptr = ERR5; + return p; + } + +/* Read the maximum value if there is one, and again do a paranoid check +on its size. Also, max must not be less than min. */ if (*p == '}') max = min; else { @@ -1171,6 +1182,11 @@ { max = 0; while((pcre_ctypes[*p] & ctype_digit) != 0) max = max * 10 + *p++ - '0'; + if (max < 0 || max > 65535) + { + *errorptr = ERR5; + return p; + } if (max < min) { *errorptr = ERR4; @@ -1179,16 +1195,11 @@ } } -/* Do paranoid checks, then fill in the required variables, and pass back the -pointer to the terminating '}'. */ +/* Fill in the required variables, and pass back the pointer to the terminating +'}'. */ -if (min > 65535 || max > 65535) - *errorptr = ERR5; -else - { - *minp = min; - *maxp = max; - } +*minp = min; +*maxp = max; return p; } From akuchling at users.sourceforge.net Wed Aug 31 14:57:01 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed, 31 Aug 2005 14:57:01 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Lib/test test_re.py, 1.45.6.3, 1.45.6.4 Message-ID: <20050831125701.F008B1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Lib/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13304 Modified Files: Tag: release23-maint test_re.py Log Message: For reference, add tests for PCRE fix; the tests aren't run by default because I wanted to minimize upheaval to the 2.3 test suite Index: test_re.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_re.py,v retrieving revision 1.45.6.3 retrieving revision 1.45.6.4 diff -u -d -r1.45.6.3 -r1.45.6.4 --- test_re.py 20 Apr 2004 21:32:33 -0000 1.45.6.3 +++ test_re.py 31 Aug 2005 12:56:50 -0000 1.45.6.4 @@ -497,6 +497,23 @@ self.assert_(re.compile('bug_926075') is not re.compile(eval("u'bug_926075'"))) +class PreTests(unittest.TestCase): + def test_can_2005_2491(self): + import pre + # min < 0 + self.assertRaises(pre.error, pre.compile, 'a{4544564564646450,}') + # min > 65535 + self.assertRaises(pre.error, pre.compile, + 'a{1231313134536434,}') + # max < 0 + self.assertRaises(pre.error, pre.compile, + 'a{12,4544564564646450}') + # max > 65535 + self.assertRaises(pre.error, pre.compile, + 'a{12,1231313134536434}') + self.assertRaises(pre.error, pre.compile, + 'a{32,14}') + def run_re_tests(): from test.re_tests import benchmarks, tests, SUCCEED, FAIL, SYNTAX_ERROR if verbose: @@ -623,6 +640,7 @@ def test_main(): run_unittest(ReTests) + #run_unittest(PreTests) run_re_tests() if __name__ == "__main__": From akuchling at users.sourceforge.net Wed Aug 31 14:58:20 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed, 31 Aug 2005 14:58:20 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Misc NEWS, 1.831.4.168, 1.831.4.169 Message-ID: <20050831125820.E08C31E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Misc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv14076 Modified Files: Tag: release23-maint NEWS Log Message: Begin 2.3.6 news section; record PCRE fix Index: NEWS =================================================================== RCS file: /cvsroot/python/python/dist/src/Misc/NEWS,v retrieving revision 1.831.4.168 retrieving revision 1.831.4.169 diff -u -d -r1.831.4.168 -r1.831.4.169 --- NEWS 8 Feb 2005 05:57:20 -0000 1.831.4.168 +++ NEWS 31 Aug 2005 12:58:09 -0000 1.831.4.169 @@ -4,6 +4,17 @@ (editors: check NEWS.help for information about editing NEWS using ReST.) +What's New in Python 2.3.6rc1? +============================== + +*Release date: XX-XXX-200X* + +Extension modules +----------------- + +- Apply fix for potential heap overflow in PCRE code (CAN-2005-2491). + + What's New in Python 2.3.5? ============================== From akuchling at users.sourceforge.net Wed Aug 31 15:50:30 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed, 31 Aug 2005 15:50:30 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libos.tex,1.166,1.167 Message-ID: <20050831135030.A48CC1E4184@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv17617 Modified Files: libos.tex Log Message: Explain what file descriptors are; this change has been sitting in my tree for a while Index: libos.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libos.tex,v retrieving revision 1.166 retrieving revision 1.167 diff -u -d -r1.166 -r1.167 --- libos.tex 9 Aug 2005 15:24:05 -0000 1.166 +++ libos.tex 31 Aug 2005 13:50:17 -0000 1.167 @@ -427,8 +427,15 @@ \subsection{File Descriptor Operations \label{os-fd-ops}} -These functions operate on I/O streams referred to -using file descriptors. +These functions operate on I/O streams referenced using file +descriptors. + +File descriptors are small integers corresponding to a file that has +been opened by the current process. For example, standard input is +usually file descriptor 0, standard output is 1, and standard error is +2. Further files opened by a process will then be assigned 3, 4, 5, +and so forth. The name ``file descriptor'' is slightly deceptive; on +{\UNIX} platforms, sockets and pipes are also referenced by file descriptors. \begin{funcdesc}{close}{fd} From akuchling at users.sourceforge.net Wed Aug 31 16:43:23 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed, 31 Aug 2005 16:43:23 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/howto advocacy.tex, 1.1, 1.2 TODO, 1.1, 1.2 Message-ID: <20050831144323.114371E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/howto In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv24368 Modified Files: advocacy.tex TODO Log Message: Update URLs Index: advocacy.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/howto/advocacy.tex,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- advocacy.tex 30 Aug 2005 01:25:06 -0000 1.1 +++ advocacy.tex 31 Aug 2005 14:43:11 -0000 1.2 @@ -181,7 +181,7 @@ of Classic C maintain that ANSI C is no longer compact). \end{quotation} -(From \url{http://sagan.earthspace.net/jargon/jargon_18.html\#SEC25}) +(From \url{http://www.catb.org/~esr/jargon/html/C/compact.html}) In this sense of the word, Python is quite compact, because the language has just a few ideas, which are used in lots of places. Take @@ -285,7 +285,7 @@ such high-end applications, Python's still simple enough to use for little jobs. -See \url{http://www.python.org/psa/Users.html} for a list of some of the +See \url{http://wiki.python.org/moin/OrganizationsUsingPython} for a list of some of the organizations that use Python. \emph{What are the restrictions on Python's use?} @@ -332,12 +332,18 @@ \begin{definitions} -\term{\url{http://www.fsbassociates.com/books/pythonchpt1.htm}} -The first chapter of \emph{Internet Programming with Python} also -examines some of the reasons for using Python. The book is well worth -buying, but the publishers have made the first chapter available on -the Web. +\term{\url{http://www.pythonology.com/success}} + +The Python Success Stories are a collection of stories from successful +users of Python, with the emphasis on business and corporate users. + +%\term{\url{http://www.fsbassociates.com/books/pythonchpt1.htm}} + +%The first chapter of \emph{Internet Programming with Python} also +%examines some of the reasons for using Python. The book is well worth +%buying, but the publishers have made the first chapter available on +%the Web. \term{\url{http://home.pacbell.net/ouster/scripting.html}} @@ -364,16 +370,16 @@ software. \end{quotation} -%\term{\url{http://www.pythonjournal.com/volume1/art-interview/}} +\term{\url{http://pythonjournal.cognizor.com/pyj1/Everitt-Feit_interview98-V1.html}} -%This interview with Andy Feit, discussing Infoseek's use of Python, can be -%used to show that choosing Python didn't introduce any difficulties -%into a company's development process, and provided some substantial benefits. +This interview with Andy Feit, discussing Infoseek's use of Python, can be +used to show that choosing Python didn't introduce any difficulties +into a company's development process, and provided some substantial benefits. -\term{\url{http://www.python.org/psa/Commercial.html}} +%\term{\url{http://www.python.org/psa/Commercial.html}} -Robin Friedrich wrote this document on how to support Python's use in -commercial projects. +%Robin Friedrich wrote this document on how to support Python's use in +%commercial projects. \term{\url{http://www.python.org/workshops/1997-10/proceedings/stein.ps}} Index: TODO =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/howto/TODO,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- TODO 30 Aug 2005 01:28:15 -0000 1.1 +++ TODO 31 Aug 2005 14:43:11 -0000 1.2 @@ -1,7 +1,7 @@ Short-term tasks: Quick revision pass to make HOWTOs match the current state of Python: -advocacy curses doanddont regex sockets sorting +curses doanddont regex sockets sorting Medium-term tasks: Revisit the regex howto. From akuchling at users.sourceforge.net Wed Aug 31 18:52:51 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed, 31 Aug 2005 18:52:51 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/lib libzlib.tex,1.31,1.32 Message-ID: <20050831165251.4253B1E4004@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/lib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12210 Modified Files: libzlib.tex Log Message: >From c.l.py comments: link to zlib manual, and disclaim completeness Index: libzlib.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/lib/libzlib.tex,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- libzlib.tex 20 Dec 2004 06:08:12 -0000 1.31 +++ libzlib.tex 31 Aug 2005 16:52:40 -0000 1.32 @@ -8,11 +8,16 @@ 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/}. +The zlib library has its own home page at \url{http://www.zlib.net}. 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. +zlib's functions have many options and often need to be used in a +particular order. This documentation doesn't attempt to cover all of +the permutations; consult the zlib manual at +\url{http://www.zlib.net/manual.html} for authoritative information. + The available exception and functions in this module are: \begin{excdesc}{error} @@ -171,5 +176,7 @@ \begin{seealso} \seemodule{gzip}{Reading and writing \program{gzip}-format files.} - \seeurl{http://www.gzip.org/zlib/}{The zlib library home page.} + \seeurl{http://www.zlib.net}{The zlib library home page.} + \seeurl{http://www.zlib.net/manual.html}{The zlib manual explains + the semantics and usage of the library's many functions.} \end{seealso} From akuchling at users.sourceforge.net Wed Aug 31 19:49:51 2005 From: akuchling at users.sourceforge.net (akuchling@users.sourceforge.net) Date: Wed, 31 Aug 2005 19:49:51 +0200 (CEST) Subject: [Python-checkins] python/dist/src/Doc/howto regex.tex,1.1,1.2 Message-ID: <20050831174951.3B7181E4005@bag.python.org> Update of /cvsroot/python/python/dist/src/Doc/howto In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv13867 Modified Files: regex.tex Log Message: Typo fix Index: regex.tex =================================================================== RCS file: /cvsroot/python/python/dist/src/Doc/howto/regex.tex,v retrieving revision 1.1 retrieving revision 1.2 diff -u -d -r1.1 -r1.2 --- regex.tex 30 Aug 2005 01:25:06 -0000 1.1 +++ regex.tex 31 Aug 2005 17:49:39 -0000 1.2 @@ -1313,7 +1313,7 @@ from a string or replacing it with another single character. You might do this with something like \code{re.sub('\e n', ' ', S)}, but \method{translate()} is capable of doing both tasks -and will be faster that any regular expression operation can be. +and will be faster than any regular expression operation can be. In short, before turning to the \module{re} module, consider whether your problem can be solved with a faster and simpler string method.