From python-checkins at python.org Thu Mar 1 00:31:22 2007 From: python-checkins at python.org (brett.cannon) Date: Thu, 1 Mar 2007 00:31:22 +0100 (CET) Subject: [Python-checkins] r54046 - in python/branches/p3yk_no_args_on_exc: BROKEN Lib/socket.py Misc/NEWS Modules/_ssl.c Modules/socketmodule.c Python/errors.c Message-ID: <20070228233122.B7A9D1E400C@bag.python.org> Author: brett.cannon Date: Thu Mar 1 00:31:14 2007 New Revision: 54046 Modified: python/branches/p3yk_no_args_on_exc/BROKEN python/branches/p3yk_no_args_on_exc/Lib/socket.py python/branches/p3yk_no_args_on_exc/Misc/NEWS python/branches/p3yk_no_args_on_exc/Modules/_ssl.c python/branches/p3yk_no_args_on_exc/Modules/socketmodule.c python/branches/p3yk_no_args_on_exc/Python/errors.c Log: Fix the BaseException.args removal. Required wrapping tuple arguments to PyErr_SetObject() within another tuple, else PyErr_Fetch() passes the tuple directly to the exception's init function which raising an exception itself since only one argument is allowed. Also had to tweak PyErr_SetFromErrno() to do the same thing. Modified: python/branches/p3yk_no_args_on_exc/BROKEN ============================================================================== --- python/branches/p3yk_no_args_on_exc/BROKEN (original) +++ python/branches/p3yk_no_args_on_exc/BROKEN Thu Mar 1 00:31:14 2007 @@ -1,10 +1,9 @@ -* Construction of exception at C level passing too many arguments? +* socket.error is passed two arguments but just subclasses PyExc_Exception, and + thus constructor gets passed two arguments (thanks to + PyErr_NormalizeException() passing any tuple given to it as a value as the + args tuple, but not when it is any other type of value). + test_bsddb - + test_socket - + test_socket_ssl - + test_timeout - + test_urllib2net - + test_urllibnet + + test_bsddb3 (?) * doctest oddness (need to change how SyntaxError is handled?) + test_xml_etree Modified: python/branches/p3yk_no_args_on_exc/Lib/socket.py ============================================================================== --- python/branches/p3yk_no_args_on_exc/Lib/socket.py (original) +++ python/branches/p3yk_no_args_on_exc/Lib/socket.py Thu Mar 1 00:31:14 2007 @@ -138,7 +138,7 @@ class _closedsocket(object): __slots__ = [] def _dummy(*args): - raise error(EBADF, 'Bad file descriptor') + raise error((EBADF, 'Bad file descriptor')) def close(self): pass # All _delegate_methods must also be initialized here. Modified: python/branches/p3yk_no_args_on_exc/Misc/NEWS ============================================================================== --- python/branches/p3yk_no_args_on_exc/Misc/NEWS (original) +++ python/branches/p3yk_no_args_on_exc/Misc/NEWS Thu Mar 1 00:31:14 2007 @@ -28,6 +28,9 @@ Core and Builtins ----------------- +- PyErr_SetFromErrno() now wraps its value argument in another tuple before + passing it to the exception type's init function. + - SyntaxError now enforces the requirement of having two arguments, second of which is a four-item tuple. Modified: python/branches/p3yk_no_args_on_exc/Modules/_ssl.c ============================================================================== --- python/branches/p3yk_no_args_on_exc/Modules/_ssl.c (original) +++ python/branches/p3yk_no_args_on_exc/Modules/_ssl.c Thu Mar 1 00:31:14 2007 @@ -161,19 +161,18 @@ n = PyInt_FromLong((long) p); if (n == NULL) return NULL; - v = PyTuple_New(2); - if (v == NULL) { - Py_DECREF(n); - return NULL; - } s = PyString_FromString(errstr); if (s == NULL) { - Py_DECREF(v); Py_DECREF(n); } - PyTuple_SET_ITEM(v, 0, n); - PyTuple_SET_ITEM(v, 1, s); + v = Py_BuildValue("((O, O))", n, s); + if (v == NULL) { + Py_DECREF(n); + Py_DECREF(s); + return NULL; + } + PyErr_SetObject(PySSLErrorObject, v); Py_DECREF(v); return NULL; Modified: python/branches/p3yk_no_args_on_exc/Modules/socketmodule.c ============================================================================== --- python/branches/p3yk_no_args_on_exc/Modules/socketmodule.c (original) +++ python/branches/p3yk_no_args_on_exc/Modules/socketmodule.c Thu Mar 1 00:31:14 2007 @@ -531,7 +531,7 @@ } } - v = Py_BuildValue("(is)", err_no, msg); + v = Py_BuildValue("((is))", err_no, msg); if (v != NULL) { PyErr_SetObject(socket_error, v); Py_DECREF(v); @@ -567,7 +567,7 @@ *lastc-- = '\0'; } } - v = Py_BuildValue("(is)", myerrorcode, outbuf); + v = Py_BuildValue("((is))", myerrorcode, outbuf); if (v != NULL) { PyErr_SetObject(socket_error, v); Py_DECREF(v); @@ -580,7 +580,7 @@ #if defined(RISCOS) if (_inet_error.errnum != NULL) { PyObject *v; - v = Py_BuildValue("(is)", errno, _inet_err()); + v = Py_BuildValue("((is))", errno, _inet_err()); if (v != NULL) { PyErr_SetObject(socket_error, v); Py_DECREF(v); @@ -599,9 +599,9 @@ PyObject *v; #ifdef HAVE_HSTRERROR - v = Py_BuildValue("(is)", h_error, (char *)hstrerror(h_error)); + v = Py_BuildValue("((is))", h_error, (char *)hstrerror(h_error)); #else - v = Py_BuildValue("(is)", h_error, "host not found"); + v = Py_BuildValue("((is))", h_error, "host not found"); #endif if (v != NULL) { PyErr_SetObject(socket_herror, v); @@ -624,9 +624,9 @@ #endif #ifdef HAVE_GAI_STRERROR - v = Py_BuildValue("(is)", error, gai_strerror(error)); + v = Py_BuildValue("((is))", error, gai_strerror(error)); #else - v = Py_BuildValue("(is)", error, "getaddrinfo failed"); + v = Py_BuildValue("((is))", error, "getaddrinfo failed"); #endif if (v != NULL) { PyErr_SetObject(socket_gaierror, v); Modified: python/branches/p3yk_no_args_on_exc/Python/errors.c ============================================================================== --- python/branches/p3yk_no_args_on_exc/Python/errors.c (original) +++ python/branches/p3yk_no_args_on_exc/Python/errors.c Thu Mar 1 00:31:14 2007 @@ -335,9 +335,9 @@ #endif /* Unix/Windows */ #endif /* PLAN 9*/ if (filenameObject != NULL) - v = Py_BuildValue("(isO)", i, s, filenameObject); + v = Py_BuildValue("((isO))", i, s, filenameObject); else - v = Py_BuildValue("(is)", i, s); + v = Py_BuildValue("((is))", i, s); if (v != NULL) { PyErr_SetObject(exc, v); Py_DECREF(v); @@ -415,9 +415,9 @@ s[--len] = '\0'; } if (filenameObject != NULL) - v = Py_BuildValue("(isO)", err, s, filenameObject); + v = Py_BuildValue("((isO))", err, s, filenameObject); else - v = Py_BuildValue("(is)", err, s); + v = Py_BuildValue("((is))", err, s); if (v != NULL) { PyErr_SetObject(exc, v); Py_DECREF(v); From python-checkins at python.org Thu Mar 1 00:39:16 2007 From: python-checkins at python.org (brett.cannon) Date: Thu, 1 Mar 2007 00:39:16 +0100 (CET) Subject: [Python-checkins] r54047 - in python/branches/p3yk_no_args_on_exc: BROKEN Modules/_bsddb.c Message-ID: <20070228233916.70AAD1E4002@bag.python.org> Author: brett.cannon Date: Thu Mar 1 00:39:15 2007 New Revision: 54047 Modified: python/branches/p3yk_no_args_on_exc/BROKEN python/branches/p3yk_no_args_on_exc/Modules/_bsddb.c Log: Fix _bsddb for the BaseException.args removal. Modified: python/branches/p3yk_no_args_on_exc/BROKEN ============================================================================== --- python/branches/p3yk_no_args_on_exc/BROKEN (original) +++ python/branches/p3yk_no_args_on_exc/BROKEN Thu Mar 1 00:39:15 2007 @@ -2,7 +2,6 @@ thus constructor gets passed two arguments (thanks to PyErr_NormalizeException() passing any tuple given to it as a value as the args tuple, but not when it is any other type of value). - + test_bsddb + test_bsddb3 (?) * doctest oddness (need to change how SyntaxError is handled?) Modified: python/branches/p3yk_no_args_on_exc/Modules/_bsddb.c ============================================================================== --- python/branches/p3yk_no_args_on_exc/Modules/_bsddb.c (original) +++ python/branches/p3yk_no_args_on_exc/Modules/_bsddb.c Thu Mar 1 00:39:15 2007 @@ -323,7 +323,7 @@ #define _CHECK_OBJECT_NOT_CLOSED(nonNull, pyErrObj, name) \ if ((nonNull) == NULL) { \ PyObject *errTuple = NULL; \ - errTuple = Py_BuildValue("(is)", 0, #name " object has been closed"); \ + errTuple = Py_BuildValue("((is))", 0, #name " object has been closed"); \ PyErr_SetObject((pyErrObj), errTuple); \ Py_DECREF(errTuple); \ return NULL; \ @@ -602,7 +602,7 @@ } _db_errmsg[0] = 0; - errTuple = Py_BuildValue("(is)", err, errTxt); + errTuple = Py_BuildValue("((is))", err, errTxt); PyErr_SetObject(errObj, errTuple); Py_DECREF(errTuple); } @@ -1931,7 +1931,7 @@ #endif if (NULL == self->db) { - PyObject *t = Py_BuildValue("(is)", 0, + PyObject *t = Py_BuildValue("((is))", 0, "Cannot call open() twice for DB object"); PyErr_SetObject(DBError, t); Py_DECREF(t); @@ -2703,7 +2703,7 @@ DBObject* self = (DBObject*)_self; if (self->db == NULL) { - PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed"); + PyObject *t = Py_BuildValue("((is))", 0, "DB object has been closed"); PyErr_SetObject(DBError, t); Py_DECREF(t); return -1; @@ -2795,7 +2795,7 @@ int flags = 0; if (self->db == NULL) { - PyObject *t = Py_BuildValue("(is)", 0, "DB object has been closed"); + PyObject *t = Py_BuildValue("((is))", 0, "DB object has been closed"); PyErr_SetObject(DBError, t); Py_DECREF(t); return -1; @@ -4686,7 +4686,7 @@ return NULL; if (!self->txn) { - PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " + PyObject *t = Py_BuildValue("((is))", 0, "DBTxn must not be used " "after txn_commit or txn_abort"); PyErr_SetObject(DBError, t); Py_DECREF(t); @@ -4723,7 +4723,7 @@ } if (!self->txn) { - PyObject *t = Py_BuildValue("(is)", 0,"DBTxn must not be used " + PyObject *t = Py_BuildValue("((is))", 0,"DBTxn must not be used " "after txn_commit or txn_abort"); PyErr_SetObject(DBError, t); Py_DECREF(t); @@ -4745,7 +4745,7 @@ return NULL; if (!self->txn) { - PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " + PyObject *t = Py_BuildValue("((is))", 0, "DBTxn must not be used " "after txn_commit or txn_abort"); PyErr_SetObject(DBError, t); Py_DECREF(t); @@ -4770,7 +4770,7 @@ return NULL; if (!self->txn) { - PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " + PyObject *t = Py_BuildValue("((is))", 0, "DBTxn must not be used " "after txn_commit or txn_abort"); PyErr_SetObject(DBError, t); Py_DECREF(t); @@ -4799,7 +4799,7 @@ return NULL; if (!self->txn) { - PyObject *t = Py_BuildValue("(is)", 0, "DBTxn must not be used " + PyObject *t = Py_BuildValue("((is))", 0, "DBTxn must not be used " "after txn_commit or txn_abort"); PyErr_SetObject(DBError, t); Py_DECREF(t); From python-checkins at python.org Thu Mar 1 00:51:13 2007 From: python-checkins at python.org (brett.cannon) Date: Thu, 1 Mar 2007 00:51:13 +0100 (CET) Subject: [Python-checkins] r54048 - in python/branches/p3yk_no_args_on_exc: BROKEN Objects/exceptions.c Message-ID: <20070228235113.4101D1E4003@bag.python.org> Author: brett.cannon Date: Thu Mar 1 00:51:06 2007 New Revision: 54048 Modified: python/branches/p3yk_no_args_on_exc/BROKEN python/branches/p3yk_no_args_on_exc/Objects/exceptions.c Log: Clean up the output from IOError. Allows test_xml_etree to pass after the BaseException.args removal. Modified: python/branches/p3yk_no_args_on_exc/BROKEN ============================================================================== --- python/branches/p3yk_no_args_on_exc/BROKEN (original) +++ python/branches/p3yk_no_args_on_exc/BROKEN Thu Mar 1 00:51:06 2007 @@ -3,6 +3,3 @@ PyErr_NormalizeException() passing any tuple given to it as a value as the args tuple, but not when it is any other type of value). + test_bsddb3 (?) - -* doctest oddness (need to change how SyntaxError is handled?) - + test_xml_etree Modified: python/branches/p3yk_no_args_on_exc/Objects/exceptions.c ============================================================================== --- python/branches/p3yk_no_args_on_exc/Objects/exceptions.c (original) +++ python/branches/p3yk_no_args_on_exc/Objects/exceptions.c Thu Mar 1 00:51:06 2007 @@ -524,7 +524,7 @@ { PyObject *rtnval = NULL; - if (self->filename) { + if (self->filename != Py_None) { PyObject *fmt; PyObject *repr; PyObject *tuple; @@ -558,7 +558,7 @@ Py_DECREF(fmt); Py_DECREF(tuple); } - else if (self->myerrno && self->strerror) { + else if (self->myerrno != Py_None && self->strerror != Py_None) { PyObject *fmt; PyObject *tuple; From python-checkins at python.org Thu Mar 1 01:28:28 2007 From: python-checkins at python.org (brett.cannon) Date: Thu, 1 Mar 2007 01:28:28 +0100 (CET) Subject: [Python-checkins] r54049 - in python/branches/p3yk_no_args_on_exc: BROKEN Lib/bsddb/dbtables.py Lib/bsddb/test/test_basics.py Lib/bsddb/test/test_recno.py Python/errors.c Message-ID: <20070301002828.D70721E4004@bag.python.org> Author: brett.cannon Date: Thu Mar 1 01:28:20 2007 New Revision: 54049 Modified: python/branches/p3yk_no_args_on_exc/BROKEN python/branches/p3yk_no_args_on_exc/Lib/bsddb/dbtables.py python/branches/p3yk_no_args_on_exc/Lib/bsddb/test/test_basics.py python/branches/p3yk_no_args_on_exc/Lib/bsddb/test/test_recno.py python/branches/p3yk_no_args_on_exc/Python/errors.c Log: Fix test_bsddb and test_bsddb3 (still one failure, but it doesn't look like it is from this work). Had to revert part of r54046 where PyErr_SetFromErrno() was being wrapped in another tuple since it messed up IOError. This means that socket.error needs to be rewritten so that it takes up to two arguments and does the right thing when calling Exception.__init__. See _bsddb for possible inspiration on how to do this in Python code within a C extension module. Modified: python/branches/p3yk_no_args_on_exc/BROKEN ============================================================================== --- python/branches/p3yk_no_args_on_exc/BROKEN (original) +++ python/branches/p3yk_no_args_on_exc/BROKEN Thu Mar 1 01:28:20 2007 @@ -2,4 +2,8 @@ thus constructor gets passed two arguments (thanks to PyErr_NormalizeException() passing any tuple given to it as a value as the args tuple, but not when it is any other type of value). - + test_bsddb3 (?) + + test_socket + + test_socket_ssl + + test_timeout + + test_urllib2net + + test_urllibnet Modified: python/branches/p3yk_no_args_on_exc/Lib/bsddb/dbtables.py ============================================================================== --- python/branches/p3yk_no_args_on_exc/Lib/bsddb/dbtables.py (original) +++ python/branches/p3yk_no_args_on_exc/Lib/bsddb/dbtables.py Thu Mar 1 01:28:20 2007 @@ -244,7 +244,7 @@ columnlist_key = _columns_key(table) if self.db.has_key(columnlist_key): - raise TableAlreadyExists, "table already exists" + raise TableAlreadyExists("table already exists") txn = self.env.txn_begin() # store the table's column info @@ -263,7 +263,7 @@ except DBError as dberror: if txn: txn.abort() - raise TableDBError, dberror[1] + raise TableDBError(dberror.message[1]) def ListTableColumns(self, table): @@ -272,7 +272,7 @@ """ assert isinstance(table, StringType) if contains_metastrings(table): - raise ValueError, "bad table name: contains reserved metastrings" + raise ValueError("bad table name: contains reserved metastrings") columnlist_key = _columns_key(table) if not self.db.has_key(columnlist_key): @@ -341,7 +341,7 @@ except DBError as dberror: if txn: txn.abort() - raise TableDBError, dberror[1] + raise TableDBError(dberror.message[1]) def __load_column_info(self, table) : @@ -350,9 +350,9 @@ try: tcolpickles = self.db.get(_columns_key(table)) except DBNotFoundError: - raise TableDBError, "unknown table: %r" % (table,) + raise TableDBError("unknown table: %r" % (table,)) if not tcolpickles: - raise TableDBError, "unknown table: %r" % (table,) + raise TableDBError("unknown table: %r" % (table,)) self.__tablecolumns[table] = pickle.loads(tcolpickles) def __new_rowid(self, table, txn) : @@ -416,7 +416,7 @@ if txn: txn.abort() self.db.delete(_rowid_key(table, rowid)) - raise TableDBError, dberror[1], info[2] + raise TableDBError((dberror.message[1], info[2])) def Modify(self, table, conditions={}, mappings={}): @@ -467,7 +467,7 @@ raise except DBError as dberror: - raise TableDBError, dberror[1] + raise TableDBError(dberror.message[1]) def Delete(self, table, conditions={}): """Delete(table, conditions) - Delete items matching the given @@ -507,7 +507,7 @@ txn.abort() raise except DBError as dberror: - raise TableDBError, dberror[1] + raise TableDBError(dberror.message[1]) def Select(self, table, columns, conditions={}): @@ -527,7 +527,7 @@ columns = self.__tablecolumns[table] matching_rowids = self.__Select(table, columns, conditions) except DBError as dberror: - raise TableDBError, dberror[1] + raise TableDBError(dberror.message[1]) # return the matches as a list of dictionaries return matching_rowids.values() @@ -617,7 +617,7 @@ key, data = cur.next() except DBError as dberror: - if dberror[0] != DB_NOTFOUND: + if dberror.message != DB_NOTFOUND: raise continue @@ -703,4 +703,4 @@ except DBError as dberror: if txn: txn.abort() - raise TableDBError, dberror[1] + raise TableDBError(dberror.message[1]) Modified: python/branches/p3yk_no_args_on_exc/Lib/bsddb/test/test_basics.py ============================================================================== --- python/branches/p3yk_no_args_on_exc/Lib/bsddb/test/test_basics.py (original) +++ python/branches/p3yk_no_args_on_exc/Lib/bsddb/test/test_basics.py Thu Mar 1 01:28:20 2007 @@ -163,7 +163,7 @@ try: d.delete('abcd') except db.DBNotFoundError as val: - assert val[0] == db.DB_NOTFOUND + assert val.message[0] == db.DB_NOTFOUND if verbose: print(val) else: self.fail("expected exception") @@ -182,7 +182,7 @@ try: d.put('abcd', 'this should fail', flags=db.DB_NOOVERWRITE) except db.DBKeyExistError as val: - assert val[0] == db.DB_KEYEXIST + assert val.message[0] == db.DB_KEYEXIST if verbose: print(val) else: self.fail("expected exception") @@ -315,7 +315,7 @@ rec = c.next() except db.DBNotFoundError as val: if get_raises_error: - assert val[0] == db.DB_NOTFOUND + assert val.message[0] == db.DB_NOTFOUND if verbose: print(val) rec = None else: @@ -335,7 +335,7 @@ rec = c.prev() except db.DBNotFoundError as val: if get_raises_error: - assert val[0] == db.DB_NOTFOUND + assert val.message[0] == db.DB_NOTFOUND if verbose: print(val) rec = None else: @@ -358,7 +358,7 @@ try: n = c.set('bad key') except db.DBNotFoundError as val: - assert val[0] == db.DB_NOTFOUND + assert val.message[0] == db.DB_NOTFOUND if verbose: print(val) else: if set_raises_error: @@ -372,7 +372,7 @@ try: n = c.get_both('0404', 'bad data') except db.DBNotFoundError as val: - assert val[0] == db.DB_NOTFOUND + assert val.message[0] == db.DB_NOTFOUND if verbose: print(val) else: if get_raises_error: @@ -401,7 +401,7 @@ rec = c.current() except db.DBKeyEmptyError as val: if get_raises_error: - assert val[0] == db.DB_KEYEMPTY + assert val.message[0] == db.DB_KEYEMPTY if verbose: print(val) else: self.fail("unexpected DBKeyEmptyError") @@ -446,7 +446,7 @@ # a bug may cause a NULL pointer dereference... getattr(c, method)(*args) except db.DBError as val: - assert val[0] == 0 + assert val.message[0] == 0 if verbose: print(val) else: self.fail("no exception raised when using a buggy cursor's" Modified: python/branches/p3yk_no_args_on_exc/Lib/bsddb/test/test_recno.py ============================================================================== --- python/branches/p3yk_no_args_on_exc/Lib/bsddb/test/test_recno.py (original) +++ python/branches/p3yk_no_args_on_exc/Lib/bsddb/test/test_recno.py Thu Mar 1 01:28:20 2007 @@ -64,7 +64,7 @@ try: data = d[0] # This should raise a KeyError!?!?! except db.DBInvalidArgError as val: - assert val[0] == db.EINVAL + assert val.message[0] == db.EINVAL if verbose: print(val) else: self.fail("expected exception") @@ -268,7 +268,7 @@ try: # this one will fail d.append('bad' * 20) except db.DBInvalidArgError as val: - assert val[0] == db.EINVAL + assert val.message[0] == db.EINVAL if verbose: print(val) else: self.fail("expected exception") Modified: python/branches/p3yk_no_args_on_exc/Python/errors.c ============================================================================== --- python/branches/p3yk_no_args_on_exc/Python/errors.c (original) +++ python/branches/p3yk_no_args_on_exc/Python/errors.c Thu Mar 1 01:28:20 2007 @@ -335,9 +335,9 @@ #endif /* Unix/Windows */ #endif /* PLAN 9*/ if (filenameObject != NULL) - v = Py_BuildValue("((isO))", i, s, filenameObject); + v = Py_BuildValue("(isO)", i, s, filenameObject); else - v = Py_BuildValue("((is))", i, s); + v = Py_BuildValue("(is)", i, s); if (v != NULL) { PyErr_SetObject(exc, v); Py_DECREF(v); @@ -415,9 +415,9 @@ s[--len] = '\0'; } if (filenameObject != NULL) - v = Py_BuildValue("((isO))", err, s, filenameObject); + v = Py_BuildValue("(isO)", err, s, filenameObject); else - v = Py_BuildValue("((is))", err, s); + v = Py_BuildValue("(is)", err, s); if (v != NULL) { PyErr_SetObject(exc, v); Py_DECREF(v); From python-checkins at python.org Thu Mar 1 04:33:20 2007 From: python-checkins at python.org (brett.cannon) Date: Thu, 1 Mar 2007 04:33:20 +0100 (CET) Subject: [Python-checkins] r54050 - python/branches/p3yk_no_args_on_exc/Modules/socketmodule.c Message-ID: <20070301033320.2789B1E4002@bag.python.org> Author: brett.cannon Date: Thu Mar 1 04:33:15 2007 New Revision: 54050 Modified: python/branches/p3yk_no_args_on_exc/Modules/socketmodule.c Log: Re-implement socket.error to add support for taking two arguments. Fixes (again) all of the failing networking tests. Modified: python/branches/p3yk_no_args_on_exc/Modules/socketmodule.c ============================================================================== --- python/branches/p3yk_no_args_on_exc/Modules/socketmodule.c (original) +++ python/branches/p3yk_no_args_on_exc/Modules/socketmodule.c Thu Mar 1 04:33:15 2007 @@ -4240,6 +4240,7 @@ init_socket(void) { PyObject *m, *has_ipv6; + PyObject *module_dict; if (!os_init()) return; @@ -4251,30 +4252,23 @@ if (m == NULL) return; - socket_error = PyErr_NewException("socket.error", NULL, NULL); - if (socket_error == NULL) - return; - PySocketModuleAPI.error = socket_error; - Py_INCREF(socket_error); - PyModule_AddObject(m, "error", socket_error); - socket_herror = PyErr_NewException("socket.herror", - socket_error, NULL); - if (socket_herror == NULL) - return; - Py_INCREF(socket_herror); - PyModule_AddObject(m, "herror", socket_herror); - socket_gaierror = PyErr_NewException("socket.gaierror", socket_error, - NULL); - if (socket_gaierror == NULL) - return; - Py_INCREF(socket_gaierror); - PyModule_AddObject(m, "gaierror", socket_gaierror); - socket_timeout = PyErr_NewException("socket.timeout", - socket_error, NULL); - if (socket_timeout == NULL) - return; - Py_INCREF(socket_timeout); - PyModule_AddObject(m, "timeout", socket_timeout); + module_dict = PyModule_GetDict(m); + PyDict_SetItemString(module_dict, "Exception", PyExc_Exception); + + PyRun_String("class error(Exception):\n" + " def __init__(self, message='', errno=None):\n" + " Exception.__init__(self, message)\n" + " if errno:\n" + " self.errno = errno\n" + "class herror(error): pass\n" + "class gaierror(error): pass\n" + "class timeout(error): pass\n", + Py_file_input, module_dict, module_dict); + socket_error = PyDict_GetItemString(module_dict, "error"); + socket_herror = PyDict_GetItemString(module_dict, "herror"); + socket_gaierror = PyDict_GetItemString(module_dict, "gaierror"); + socket_timeout = PyDict_GetItemString(module_dict, "timeout"); + Py_INCREF((PyObject *)&sock_type); if (PyModule_AddObject(m, "SocketType", (PyObject *)&sock_type) != 0) From python-checkins at python.org Thu Mar 1 04:34:43 2007 From: python-checkins at python.org (brett.cannon) Date: Thu, 1 Mar 2007 04:34:43 +0100 (CET) Subject: [Python-checkins] r54051 - in python/branches/p3yk_no_args_on_exc: BROKEN Lib/test/test_compiler.py Message-ID: <20070301033443.1DBF41E4002@bag.python.org> Author: brett.cannon Date: Thu Mar 1 04:34:39 2007 New Revision: 54051 Modified: python/branches/p3yk_no_args_on_exc/BROKEN python/branches/p3yk_no_args_on_exc/Lib/test/test_compiler.py Log: Make test_compiler not fail because of str concatentation. Test still fails, though under -uall execution. Modified: python/branches/p3yk_no_args_on_exc/BROKEN ============================================================================== --- python/branches/p3yk_no_args_on_exc/BROKEN (original) +++ python/branches/p3yk_no_args_on_exc/BROKEN Thu Mar 1 04:34:39 2007 @@ -1,9 +1 @@ -* socket.error is passed two arguments but just subclasses PyExc_Exception, and - thus constructor gets passed two arguments (thanks to - PyErr_NormalizeException() passing any tuple given to it as a value as the - args tuple, but not when it is any other type of value). - + test_socket - + test_socket_ssl - + test_timeout - + test_urllib2net - + test_urllibnet +test_bsddb3 test_compiler (with -uall) Modified: python/branches/p3yk_no_args_on_exc/Lib/test/test_compiler.py ============================================================================== --- python/branches/p3yk_no_args_on_exc/Lib/test/test_compiler.py (original) +++ python/branches/p3yk_no_args_on_exc/Lib/test/test_compiler.py Thu Mar 1 04:34:39 2007 @@ -50,7 +50,7 @@ try: compiler.compile(buf, basename, "exec") except Exception as e: - e.message += "[in file %s]" % basename + e.message = str(e.message) + " [in file %s]" % basename raise def testNewClassSyntax(self): From python-checkins at python.org Thu Mar 1 04:41:05 2007 From: python-checkins at python.org (brett.cannon) Date: Thu, 1 Mar 2007 04:41:05 +0100 (CET) Subject: [Python-checkins] r54052 - python/branches/p3yk_no_args_on_exc/Misc/NEWS Message-ID: <20070301034105.73E961E4002@bag.python.org> Author: brett.cannon Date: Thu Mar 1 04:41:02 2007 New Revision: 54052 Modified: python/branches/p3yk_no_args_on_exc/Misc/NEWS Log: Add info about things that have changed. Modified: python/branches/p3yk_no_args_on_exc/Misc/NEWS ============================================================================== --- python/branches/p3yk_no_args_on_exc/Misc/NEWS (original) +++ python/branches/p3yk_no_args_on_exc/Misc/NEWS Thu Mar 1 04:41:02 2007 @@ -150,6 +150,10 @@ Extension Modules ----------------- +- socket.error binds its second argument to 'errno'. + +- bsddb.DBError binds all arguments as a tuple to 'message'. + Library ------- From python-checkins at python.org Thu Mar 1 07:16:45 2007 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 1 Mar 2007 07:16:45 +0100 (CET) Subject: [Python-checkins] r54053 - in python/trunk: Doc/lib/libcollections.tex Lib/collections.py Lib/test/test_collections.py Misc/NEWS Message-ID: <20070301061645.26AE41E4009@bag.python.org> Author: raymond.hettinger Date: Thu Mar 1 07:16:43 2007 New Revision: 54053 Added: python/trunk/Lib/test/test_collections.py Modified: python/trunk/Doc/lib/libcollections.tex python/trunk/Lib/collections.py python/trunk/Misc/NEWS Log: Add collections.NamedTuple Modified: python/trunk/Doc/lib/libcollections.tex ============================================================================== --- python/trunk/Doc/lib/libcollections.tex (original) +++ python/trunk/Doc/lib/libcollections.tex Thu Mar 1 07:16:43 2007 @@ -9,14 +9,16 @@ This module implements high-performance container datatypes. Currently, -there are two datatypes, deque and defaultdict. +there are two datatypes, deque and defaultdict, and one datatype factory +function, \function{NamedTuple}. Future additions may include balanced trees and ordered dictionaries. \versionchanged[Added defaultdict]{2.5} +\versionchanged[Added NamedTuple]{2.6} \subsection{\class{deque} objects \label{deque-objects}} \begin{funcdesc}{deque}{\optional{iterable}} - Returns a new deque objected initialized left-to-right (using + Returns a new deque object initialized left-to-right (using \method{append()}) with data from \var{iterable}. If \var{iterable} is not specified, the new deque is empty. @@ -339,3 +341,50 @@ >>> d.items() [('blue', set([2, 4])), ('red', set([1, 3]))] \end{verbatim} + + + +\subsection{\function{NamedTuple} datatype factory function \label{named-tuple-factory}} + +\begin{funcdesc}{NamedTuple}{typename, fieldnames} + Returns a new tuple subclass named \var{typename}. The new subclass is used + to create tuple-like objects that have fields accessable by attribute + lookup as well as being indexable and iterable. Instances of the subclass + also have a helpful docstring (with typename and fieldnames) and a helpful + \method{__repr__()} method which lists the tuple contents in a \code{name=value} + format. + \versionadded{2.6} + + The \var{fieldnames} are specified in a single string and are separated by spaces. + Any valid Python identifier may be used for a field name. + + Example: + \begin{verbatim} + >>> Point = NamedTuple('Point', 'x y') + >>> Point.__doc__ # docstring for the new datatype + 'Point(x, y)' + >>> p = Point(11, y=22) # instantiate with positional or keyword arguments + >>> p[0] + p[1] # works just like the tuple (11, 22) + 33 + >>> x, y = p # unpacks just like a tuple + >>> x, y + (11, 22) + >>> p.x + p.y # fields also accessable by name + 33 + >>> p # readable __repr__ with name=value style + Point(x=11, y=22) + \end{verbatim} + + The use cases are the same as those for tuples. The named factories + assign meaning to each tuple position and allow for more readable, + self-documenting code. Can also be used to assign field names to tuples + returned by the \module{csv} or \module{sqlite3} modules. For example: + + \begin{verbatim} + import csv + EmployeeRecord = NamedTuple('EmployeeRecord', 'name age title deparment paygrade') + for tup in csv.reader(open("employees.csv", "rb")): + print EmployeeRecord(*tup) + \end{verbatim} + +\end{funcdesc} Modified: python/trunk/Lib/collections.py ============================================================================== --- python/trunk/Lib/collections.py (original) +++ python/trunk/Lib/collections.py Thu Mar 1 07:16:43 2007 @@ -1,3 +1,62 @@ -__all__ = ['deque', 'defaultdict'] +__all__ = ['deque', 'defaultdict', 'NamedTuple'] from _collections import deque, defaultdict +from operator import itemgetter as _itemgetter +import sys as _sys + +def NamedTuple(typename, s): + """Returns a new subclass of tuple with named fields. + + >>> Point = NamedTuple('Point', 'x y') + >>> Point.__doc__ # docstring for the new class + 'Point(x, y)' + >>> p = Point(11, y=22) # instantiate with positional args or keywords + >>> p[0] + p[1] # works just like the tuple (11, 22) + 33 + >>> x, y = p # unpacks just like a tuple + >>> x, y + (11, 22) + >>> p.x + p.y # fields also accessable by name + 33 + >>> p # readable __repr__ with name=value style + Point(x=11, y=22) + + """ + + field_names = s.split() + nargs = len(field_names) + + def __new__(cls, *args, **kwds): + if kwds: + try: + args += tuple(kwds[name] for name in field_names[len(args):]) + except KeyError, name: + raise TypeError('%s missing required argument: %s' % (typename, name)) + if len(args) != nargs: + raise TypeError('%s takes exactly %d arguments (%d given)' % (typename, nargs, len(args))) + return tuple.__new__(cls, args) + + repr_template = '%s(%s)' % (typename, ', '.join('%s=%%r' % name for name in field_names)) + + m = dict(vars(tuple)) # pre-lookup superclass methods (for faster lookup) + m.update(__doc__= '%s(%s)' % (typename, ', '.join(field_names)), + __slots__ = (), # no per-instance dict (so instances are same size as tuples) + __new__ = __new__, + __repr__ = lambda self, _format=repr_template.__mod__: _format(self), + __module__ = _sys._getframe(1).f_globals['__name__'], + ) + m.update((name, property(_itemgetter(index))) for index, name in enumerate(field_names)) + + return type(typename, (tuple,), m) + + +if __name__ == '__main__': + # verify that instances are pickable + from cPickle import loads, dumps + Point = NamedTuple('Point', 'x y') + p = Point(x=10, y=20) + assert p == loads(dumps(p)) + + import doctest + TestResults = NamedTuple('TestResults', 'failed attempted') + print TestResults(*doctest.testmod()) Added: python/trunk/Lib/test/test_collections.py ============================================================================== --- (empty file) +++ python/trunk/Lib/test/test_collections.py Thu Mar 1 07:16:43 2007 @@ -0,0 +1,57 @@ +import unittest +from test import test_support +from collections import NamedTuple + +class TestNamedTuple(unittest.TestCase): + + def test_factory(self): + Point = NamedTuple('Point', 'x y') + self.assertEqual(Point.__name__, 'Point') + self.assertEqual(Point.__doc__, 'Point(x, y)') + self.assertEqual(Point.__slots__, ()) + self.assertEqual(Point.__module__, __name__) + self.assertEqual(Point.__getitem__, tuple.__getitem__) + self.assert_('__getitem__' in Point.__dict__) # superclass methods localized + + def test_instance(self): + Point = NamedTuple('Point', 'x y') + p = Point(11, 22) + self.assertEqual(p, Point(x=11, y=22)) + self.assertEqual(p, Point(11, y=22)) + self.assertEqual(p, Point(y=22, x=11)) + self.assertEqual(p, Point(*(11, 22))) + self.assertEqual(p, Point(**dict(x=11, y=22))) + self.assertRaises(TypeError, Point, 1) # too few args + self.assertRaises(TypeError, Point, 1, 2, 3) # too many args + self.assertRaises(TypeError, eval, 'Point(XXX=1, y=2)', locals()) # wrong keyword argument + self.assertRaises(TypeError, eval, 'Point(x=1)', locals()) # missing keyword argument + self.assertEqual(repr(p), 'Point(x=11, y=22)') + self.assert_('__dict__' not in dir(p)) # verify instance has no dict + self.assert_('__weakref__' not in dir(p)) + + def test_tupleness(self): + Point = NamedTuple('Point', 'x y') + p = Point(11, 22) + + self.assert_(isinstance(p, tuple)) + self.assertEqual(p, (11, 22)) # matches a real tuple + self.assertEqual(tuple(p), (11, 22)) # coercable to a real tuple + self.assertEqual(list(p), [11, 22]) # coercable to a list + self.assertEqual(max(p), 22) # iterable + self.assertEqual(max(*p), 22) # star-able + x, y = p + self.assertEqual(p, (x, y)) # unpacks like a tuple + self.assertEqual((p[0], p[1]), (11, 22)) # indexable like a tuple + self.assertRaises(IndexError, p.__getitem__, 3) + + self.assertEqual(p.x, x) + self.assertEqual(p.y, y) + self.assertRaises(AttributeError, eval, 'p.z', locals()) + + +def test_main(verbose=None): + test_classes = [TestNamedTuple] + test_support.run_unittest(*test_classes) + +if __name__ == "__main__": + test_main(verbose=True) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Thu Mar 1 07:16:43 2007 @@ -138,6 +138,8 @@ - Added heapq.merge() for merging sorted input streams. +- Added collections.NamedTuple() for assigning field names to tuples. + - Added itertools.izip_longest(). - Have the encoding package's search function dynamically import using absolute From python-checkins at python.org Thu Mar 1 08:04:42 2007 From: python-checkins at python.org (neal.norwitz) Date: Thu, 1 Mar 2007 08:04:42 +0100 (CET) Subject: [Python-checkins] r54054 - python/trunk/Misc/developers.txt Message-ID: <20070301070442.735CB1E4002@bag.python.org> Author: neal.norwitz Date: Thu Mar 1 08:04:41 2007 New Revision: 54054 Modified: python/trunk/Misc/developers.txt Log: Add Pat and Eric for work on PEP 3101 in the sandbox Modified: python/trunk/Misc/developers.txt ============================================================================== --- python/trunk/Misc/developers.txt (original) +++ python/trunk/Misc/developers.txt Thu Mar 1 08:04:41 2007 @@ -17,6 +17,9 @@ Permissions History ------------------- +- Pat Maupin and Eric V. Smith were given SVN access on 28 Feb 2007 by NCN, + for PEP 3101 work in the sandbox. + - Steven Bethard (SF name "bediviere") added to the SourceForge Python project 26 Feb 2007, by NCN, as a tracker tech. From python-checkins at python.org Thu Mar 1 09:00:05 2007 From: python-checkins at python.org (patrick.maupin) Date: Thu, 1 Mar 2007 09:00:05 +0100 (CET) Subject: [Python-checkins] r54055 - sandbox/trunk/pep3101 Message-ID: <20070301080005.B15161E4003@bag.python.org> Author: patrick.maupin Date: Thu Mar 1 09:00:03 2007 New Revision: 54055 Added: sandbox/trunk/pep3101/ Log: Added directory for development of PEP3101 and related code From python-checkins at python.org Thu Mar 1 09:22:28 2007 From: python-checkins at python.org (patrick.maupin) Date: Thu, 1 Mar 2007 09:22:28 +0100 (CET) Subject: [Python-checkins] r54056 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/pep3101.c sandbox/trunk/pep3101/pep3101.h sandbox/trunk/pep3101/setup.py sandbox/trunk/pep3101/stringformat.c sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070301082228.55D7B1E4002@bag.python.org> Author: patrick.maupin Date: Thu Mar 1 09:22:25 2007 New Revision: 54056 Added: sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/pep3101.c sandbox/trunk/pep3101/pep3101.h sandbox/trunk/pep3101/setup.py sandbox/trunk/pep3101/stringformat.c sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Initial version of pep3101 sandbox code committed Added: sandbox/trunk/pep3101/README.txt ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/README.txt Thu Mar 1 09:22:25 2007 @@ -0,0 +1,70 @@ + +PEP 3101 + +This directory is where sample code to support PEP 3101 and do +related things is being developed. + +Current developers: + + Patrick Maupin (pmaupin at gmail.com) + Eric V. Smith + Pete Shinner + +The code is only half-baked at present +(development was started at PyCon 2007 and is in progress). + +Although the PEP3101 goal is a (unicode) string format method, since +this is a sandbox, we might do a few more ambitious things as well, +to see if people like them. + +The current plan of record is to make a pep3101 extension module. +It will have at least the following features: + + - contains a format function which takes a string and parameters, + (but which is easily portable to a string method for Py3k) + - can be compiled against 2.4, 2.5, and Py3K + - Works with the string object as well as unicode + +The current code has a module which is progressing nicely, and some +unittests for the current version. + +Files: + + - unicodeformat.c is designed to be easily added to Python + as a method of the unicode object. + - stringformat.c is a wrapper around unicodeformat.c, which + "templatizes" the entire file to make it easy to add to Python + as a method of the string object. + - pep3101.h contains definitions for the functions in stringformat + and unicodeformat + - pep3101.c contains a module implementation which can be linked + with these method files for testing and/or use with earlier + Python versions. + - setup.py -- Use "build" option to make the extension module + - test_simpleformat.py -- initial unittests + +Todo: + + - finish up format specifier handling + - document differences between PEP and implementation + - Add docstrings to module + - print string offset information on certain errors + - Add _flags options + - Play with possible implementations for formatting + strings against dictionaries as well as the format + (dangerous) + - Play with possible implementations for exposing + lowest level format specifier handler for use in + compatible template systems. + - Play with possible options for specifying additional + escape syntaxes + +_flags options to consider adding: + + - useall=1 means all arguments should be used + - allow_leading_under means leading underbars allowed + - syntax=0,1,2,3 -- different syntaxes + - hook=object -- callback hook as described in PEP + - informational mode to dump exceptions into string + (as described in pep) + - max_recursion=xxx (default 4) Added: sandbox/trunk/pep3101/pep3101.c ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/pep3101.c Thu Mar 1 09:22:25 2007 @@ -0,0 +1,64 @@ +#include "Python.h" + +/* XXX -- remove this include if integrated into Python.h ??? */ +#include "pep3101.h" + + +/* ----------------------------------------------------- */ + +static char pep3101_format__doc__[] = +"" +; + +static PyObject * +pep3101_format(PyObject *self, PyObject *args, PyObject *keywords) +{ + PyObject *newargs, *newself, *result; + newself = PyTuple_GetItem(args, 0); /* borrowed reference */ + if (newself == NULL) + return NULL; + newargs = PyTuple_GetSlice(args, 1, PyTuple_Size(args) + 1); + if (newargs == NULL) + return NULL; + if (PyUnicode_Check(newself)) + result = PyUnicode_FormatMethod(newself, newargs, keywords); + else if (PyString_Check(newself)) + result = PyString_FormatMethod(newself, newargs, keywords); + else { + result = NULL; + PyErr_SetString(PyExc_TypeError, + "First parameter to format must be string or unicode object"); + } + Py_DECREF(newargs); + return result; +} + +/* List of methods defined in the module */ + +static struct PyMethodDef pep3101_methods[] = { + {"format", (PyCFunction)pep3101_format, METH_VARARGS | METH_KEYWORDS, pep3101_format__doc__}, + + {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ +}; + + +/* Initialization function for the module (*must* be called initpep3101) */ + +static char pep3101_module_documentation[] = +"" +; + +void +initpep3101(void) +{ + PyObject *m; + + /* Create the module and add the functions */ + m = Py_InitModule4("pep3101", pep3101_methods, + pep3101_module_documentation, + (PyObject*)NULL,PYTHON_API_VERSION); + + /* Check for errors */ + if (PyErr_Occurred()) + Py_FatalError("can't initialize module pep3101"); +} Added: sandbox/trunk/pep3101/pep3101.h ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/pep3101.h Thu Mar 1 09:22:25 2007 @@ -0,0 +1,12 @@ +#ifndef Py_PEP3101_H +#define Py_PEP3101_H + +/* XXX -- need #ifdefs to remove Unicode if not using it, and remove String on Py3K */ + +PyObject * +PyString_FormatMethod(PyObject *self, PyObject *args, PyObject *keywords); + +PyObject * +PyUnicode_FormatMethod(PyObject *self, PyObject *args, PyObject *keywords); + +#endif Added: sandbox/trunk/pep3101/setup.py ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/setup.py Thu Mar 1 09:22:25 2007 @@ -0,0 +1,11 @@ +from distutils.core import setup, Extension + +module1 = Extension('pep3101', + sources = ['pep3101.c', 'unicodeformat.c', 'stringformat.c'], + depends = ['unicodeformat.c'], # Force rebuild of stringobject when this changes + ) + +setup (name = 'pep3101', + version = '1.0', + description = 'Extension module to implement features of PEP 3101', + ext_modules = [module1]) Added: sandbox/trunk/pep3101/stringformat.c ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/stringformat.c Thu Mar 1 09:22:25 2007 @@ -0,0 +1,4 @@ +#include "Python.h" +#define COMPILED_FROM_INSIDE_STRINGFORMAT +#define C_UNICODE 0 +#include "unicodeformat.c" Added: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/test_simpleformat.py Thu Mar 1 09:22:25 2007 @@ -0,0 +1,115 @@ + +import unittest +from test import test_support + +import pep3101 + + +# The test implementation does not allow an argument +# index or keyword name to be used more than once. The +# PEP doesn't make any specification on this, but it +# seems too useful to leave as is. + + +class FormatTest(unittest.TestCase): + # All tests run through these functions. They can be + # overridden to change the class of string being tested + # and the function being used. + def formatEquals(self, result, text, *args, **kwargs): + text = str(text) + result = str(result) + val = pep3101.format(text, *args, **kwargs) + self.assertEquals(val, result) + + def formatRaises(self, exc, text, *args, **kwargs): + exc = exc or Exception #StringFormat.FormatError + text = str(text) + #prevState = StringFormat.strict_format_errors + #StringFormat.strict_format_errors = True + try: + self.assertRaises(exc, + lambda: pep3101.format( + text, *args, **kwargs)) + finally: + pass + #StringFormat.strict_format_errors = prevState + + + def test_basic(self): + # directly from the pep intro + self.formatEquals( + "My name is Fred", + "My name is {0}", "Fred") + self.formatEquals( + "My name is Fred :-{}", + "My name is {0} :-{{}}", "Fred") + self.formatEquals("abc", "{0:}", "abc") # is this allowed? + + def test_missingargs(self): + #self.formatRaises(None, "Doesn't use all {0} args", 42, 24) + self.formatRaises(IndexError, "There is no {4} arg", 42, 24) + self.formatRaises(KeyError, "There question is {when}", who=True) + + def test_attributes(self): + class Container(object): + one, _two, four4 = 1, 2, 4 + def __getattr__(self, name): + if name == "five": return 5 + raise TypeError("Never do this") + self.formatEquals( + "Count with me; 1 2 4", + "Count with me; {0.one} {item._two} {1.four4}", + Container, Container, item=Container) + self.formatEquals( + "Five is 5", "Five is {c.five}", c=Container()) + self.formatRaises(AttributeError, + "Missing {0.rabbit} lookup", Container) + self.formatRaises(TypeError, + "Forbidden {0.secret} lookup", Container()) + + def test_items(self): + d = dict(val="value", sum=1) + t = tuple(("apple", "ball", "cat")) + self.formatEquals( + "The value of apple", + "The {0[val]} of {t[0]}", d, t=t) + # Decided against negative indices for now + #self.formatEquals( + # "The shiny red ball", + # "The shiny red {0[-2]}", t) + + def test_formatlookup(self): + self.formatEquals("32_0>4d", "{0:{1}}", 32, "0>4d") + self.formatEquals("32_*>4d", "{0:{1}{2}4{3}}", 32, "*", ">", "d") + + def test_specifiers(self): + self.formatEquals("97_c", "{0:c}", ord("a")) + self.formatEquals("8_08b", "{0:08b}", 8) + self.formatEquals("8_ >3d", "{0: >3d}", 8) + self.formatEquals("0.1515_.0%", "{0:.0%}", .1515) + + def test_custom_format(self): + class Custom(object): + def __format__(self, specifiers): + return specifiers + custom = Custom() + self.formatEquals("magic", "{0:magic}", custom) + self.formatEquals("custom", "{0:{1}}", custom, "custom") + + def test_syntaxerror(self): + self.assertRaises(Exception, "}{", True) + self.assertRaises(Exception, "{0", True) + self.assertRaises(Exception, "{0.[]}", True) + self.assertRaises(Exception, "{0[0}", True) + self.assertRaises(Exception, "{0[0:foo}", True) + self.assertRaises(Exception, "{c]}", True) + self.assertRaises(Exception, "{{1}}", True, 0) + self.assertRaises(Exception, "{{ {{{0}}", True) + self.assertRaises(Exception, "{0}}", True) + + +def test_main(): + test_support.run_unittest(FormatTest) + +if __name__ == "__main__": + test_main() Added: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/unicodeformat.c Thu Mar 1 09:22:25 2007 @@ -0,0 +1,1091 @@ +#define DUMMY_FORMATTING 1 + +/* + unicodeformat.c -- implementation of PEP 3101 + + PEP 3101 and example Python implementation written by Talin + + This module designed and written by Patrick Maupin and Eric V Smith + + This module is designed to be compiled standalone, or from inside stringformat.c, + to support both unicode and traditional strings. +*/ + +/* + XXX -- todo: insert a fragment of the source string into error messages +*/ + +#ifndef COMPILED_FROM_INSIDE_STRINGFORMAT +#include "Python.h" +#define C_UNICODE 1 +#endif + +#if C_UNICODE +#define CH_TYPE Py_UNICODE +#define CH_TYPE_ISDECIMAL Py_UNICODE_ISDECIMAL +#define CH_TYPE_TODECIMAL Py_UNICODE_TODECIMAL +#define STROBJ_AS_PTR PyUnicode_AS_UNICODE +#define STROBJ_GET_SIZE PyUnicode_GET_SIZE +#define STROBJ_NEW PyUnicode_FromUnicode +#define STROBJ_RESIZE PyUnicode_Resize +#define STROBJ_CHECK PyUnicode_Check +#define STROBJ_FORMAT PyUnicode_FormatMethod +#define STROBJ_STR PyObject_Unicode +#else +#define CH_TYPE char +#define CH_TYPE_ISDECIMAL(x) ((x >= '0') && (x <= '9')) +#define CH_TYPE_TODECIMAL(x) (CH_TYPE_ISDECIMAL(x) ? (x - '0') : -1) +#define STROBJ_AS_PTR PyString_AS_STRING +#define STROBJ_GET_SIZE PyString_GET_SIZE +#define STROBJ_NEW PyString_FromStringAndSize +#define STROBJ_RESIZE _PyString_Resize +#define STROBJ_CHECK PyString_Check +#define STROBJ_FORMAT PyString_FormatMethod +#define STROBJ_STR PyObject_Str +#endif + +/* Try to support older versions of Python*/ +#if PYTHON_API_VERSION < 1013 +typedef int Py_ssize_t; +#define Py_LOCAL_INLINE(x) static x +#endif + +/* Defines for more efficiently reallocating the string buffer */ +#define INITIAL_SIZE_INCREMENT 100 +#define SIZE_MULTIPLIER 2 +#define MAX_SIZE_INCREMENT 3200 + +#ifdef __cplusplus +extern "C" { +#endif + +/* XXX -- remove this include if integrated into Python.h ??? */ +#include "pep3101.h" + +/* + A SubString is a string between two unicode pointers. +*/ +typedef struct { + CH_TYPE *ptr; + CH_TYPE *end; +} SubString; + +/* + A SubStringObj is like a SubString, but also has an associated + object (which may be null). +*/ +typedef struct { + CH_TYPE *ptr; + CH_TYPE *end; + PyObject * obj; +} SubStringObj; + +/* + If this were written in C++, FmtState would be the class, + and most of the functions inside this file would be members + of this class. +*/ +typedef struct { + /* args passed to PyString_FormatMethod or PyUnicode_FormatMethod */ + PyObject *args; + /* keywords passed to PyString_FormatMethod or PyUnicode_FormatMethod */ + PyObject *keywords; + /* current position and end of the 'self' string passed to FormatMethod */ + SubString fmtstr; + /* Output string we are constructing, including current and end pointers*/ + SubStringObj outstr; + /* Field Specifier, after the colon in {1:{2}} + This may or may not have a valid object (the field specifier might + just be a substring of the fmtstr. If it does not have its own + object, the .obj struct member will be NULL */ + SubStringObj fieldspec; + /* size_increment is used for optimizing string growth */ + int size_increment; + /* max_recursion is used to limit the ability of a malicious string + to damage the stack. Default value is 4 */ + int max_recursion; + /* By default, leading underscores are not allowed for security reasons */ + int allow_leading_under; + /* positional_arg_set contains one bit for every positional argument + that we still expect to be used. This implementation only checks + that the first 32 positional arguments are actually used. If they + want more than that, they probably really need the check, but on + the other hand they are probably beyond help, so the check would + be necessary but not sufficient :) */ + int positional_arg_set; + /* Keyword arguments can be checked as well */ + PyObject *keyword_arg_set; + /* For some interface functions, we could have a list or tuple of + dictionaries to search, e.g. locals()/globals(). */ + int keywords_is_tuple; +} FmtState; + +/* + Our internal conversion functions have this signature. + + returns the number of characters written, or -1 if error +*/ +/* XXX obviously wrong, but just a placeholder currently */ +typedef Py_ssize_t (*ConversionFunction)(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +/* + Forward declarations for our conversion functions +*/ +static Py_ssize_t convert_binary(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_char(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_decimal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_exponent(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_exponentUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_fixed(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_fixedUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_general(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_generalUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_number(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_octal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_repr(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_string(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_hex(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_hexUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t convert_percentage(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + + +/* Some forward declarations for recursion */ +static PyObject * +get_field_object(FmtState *fs); + +static PyObject * +recurse_format(FmtState *fs); + +/* + Most of our errors are value errors, because to Python, the + format string is a "value". Also, it's convenient to return + a NULL when we are erroring out. +*/ +static void * +SetError(const char *s) +{ + PyErr_SetString(PyExc_ValueError, s); + return NULL; +} + +/* + check_fmtstr returns True if we still have characters + left in the format string. +*/ +Py_LOCAL_INLINE(int) +check_fmtstr(FmtState *fs) +{ + return (fs->fmtstr.ptr < fs->fmtstr.end) || + SetError("Invalid format string"); +} + +/* + end_identifier returns true if a character marks + the end of an identifier string. + + Although the PEP specifies that identifiers are + numbers or valid Python identifiers, we just let + getattr/getitem handle that, so the implementation + is more flexible than the PEP would indicate. +*/ +Py_LOCAL_INLINE(int) +end_identifier(CH_TYPE c) +{ + switch (c) { + case '.': case '[': case ']': case '}': case ':': + return 1; + default: + return 0; + } +} + + +/* returns true if this character is a specifier alignment token */ +Py_LOCAL_INLINE(int) +alignment_token(CH_TYPE c) +{ + switch (c) { + case '<': case '>': case '=': case '^': + return 1; + default: + return 0; + } +} + +/* returns true if this character is a sign element */ +Py_LOCAL_INLINE(int) +sign_element(CH_TYPE c) +{ + switch (c) { + case ' ': case '+': case '-': case '(': + return 1; + default: + return 0; + } +} + + + +/* returns a pointer to our conversion function, or NULL if invalid */ +Py_LOCAL_INLINE(ConversionFunction) +conversion_function(CH_TYPE c) +{ + switch (c) { + case 'b': return convert_binary; /* base-2 */ + case 'c': return convert_char; /* as character */ + case 'd': return convert_decimal; /* decimal integer */ + case 'e': return convert_exponent; /* exponential notation */ + case 'E': return convert_exponentUC; /* exponential notation with uppercase 'E' */ + case 'f': return convert_fixed; /* fixed-point */ + case 'F': return convert_fixedUC; /* fixed-point with uppercase */ + case 'g': return convert_general; /* general number notation */ + case 'G': return convert_generalUC; /* general number notation with uppercase 'E' */ + case 'n': return convert_number; /* number in locale-specific format */ + case 'o': return convert_octal; /* octal */ + case 'r': return convert_repr; /* in repr() format */ + case 's': return convert_string; /* convert using str() */ + case 'x': return convert_hex; /* base 16 */ + case 'X': return convert_hexUC; /* base 16 uppercase */ + case '%': return convert_percentage; /* as percentage */ + default: + return NULL; + } +} + +/* Fill in a SubStringObj from a Python string */ +Py_LOCAL_INLINE(SubStringObj) +make_substrobj(PyObject *obj) +{ + SubStringObj s; + s.obj = obj; + s.ptr = STROBJ_AS_PTR(obj); + s.end = STROBJ_GET_SIZE(obj) + s.ptr; + return s; +} + +#if PYTHON_API_VERSION < 1013 +static void +PySet_Discard(PyObject *myset, PyObject *mykey) +{ + /* XXX --- Need to add the right code here */ +} +#endif + +/* XXX -- similar function elsewhere ???? */ +/* + output_data dumps characters into our output string + buffer. + + In some cases, it has to reallocate the string. + + It returns a status: 0 for a failed reallocation, + 1 for success. +*/ +static int +output_data(FmtState *fs, const CH_TYPE *s, Py_ssize_t count) +{ + Py_ssize_t room = fs->outstr.end - fs->outstr.ptr; + if (count > room) { + CH_TYPE *startptr; + Py_ssize_t curlen, maxlen; + startptr = STROBJ_AS_PTR(fs->outstr.obj); + curlen = fs->outstr.ptr - startptr; + maxlen = curlen + count + fs->size_increment; + if (STROBJ_RESIZE(&fs->outstr.obj, maxlen) < 0) + return 0; + startptr = STROBJ_AS_PTR(fs->outstr.obj); + fs->outstr.ptr = startptr + curlen; + fs->outstr.end = startptr + maxlen; + if (fs->size_increment < MAX_SIZE_INCREMENT) + fs->size_increment *= SIZE_MULTIPLIER; + } + memcpy(fs->outstr.ptr, s, count * sizeof(CH_TYPE)); + fs->outstr.ptr += count; + return 1; +} + +/* + get_python_identifier is a bit of a misnomer. It returns + a value for use with getattr or getindex. This value + will usually be a string value, but we allow {} inside the + text, so it could really be any arbitrary python object, + as retrieved from the method arguments. +*/ +static PyObject * +get_python_identifier(FmtState *fs, int isargument) +{ + CH_TYPE *startptr; + PyObject *result; + if (!check_fmtstr(fs)) + return NULL; + if (*fs->fmtstr.ptr == '{') { + /* This little bit of mutual recursion allows nested dictionary + lookups and computed attribute names + */ + if (--fs->max_recursion < 0) + return SetError("Max string recursion exceeded"); + result = get_field_object(fs); + fs->max_recursion++; + if (result && (*fs->fmtstr.ptr++ != '}')) + result = SetError("Expected closing }"); + return result; + } + if (end_identifier(*fs->fmtstr.ptr)) + return SetError("Expected attribute or index"); + if ((*fs->fmtstr.ptr == '_') && !fs->allow_leading_under) + return SetError("Index/attribute leading underscores disallowed"); + + for (startptr = fs->fmtstr.ptr; + !end_identifier(*fs->fmtstr.ptr); + fs->fmtstr.ptr++) { + if (!check_fmtstr(fs)) + return NULL; + } + result = STROBJ_NEW(startptr, fs->fmtstr.ptr - startptr); + if (result == NULL) + return NULL; + if (isargument && (fs->keyword_arg_set != NULL)) + PySet_Discard(fs->keyword_arg_set, result); + /* + We might want to add code here to check for invalid Python + identifiers. All identifiers are eventually passed to getattr + or getitem, so there is a check when used. However, we might + want to remove (or not) the ability to have strings like + "a/b" or " ab" or "-1" (which is not parsed as a number). + For now, this is left as an exercise for the first disgruntled + user... + + if (XXX -- need check function) { + Py_DECREF(result); + PyErr_SetString(PyExc_ValueError, "Invalid embedded Python identifier"); + return NULL; + } + */ + return result; +} + +/* + If keywords are supplied as a sequence of dictionaries + (e.g. locals/globals) then name_mapper will do multiple + lookups until it finds the right information. This + should not be called (keywords_is_tuple should not be + set) unless fs->keywords is a tuple. +*/ +static PyObject * +name_mapper(PyObject *keywords, PyObject *key) +{ + PyObject *result; + int index; + int lastindex = PyTuple_GET_SIZE(keywords)-1; + + for (index=0;; index++) { + result = PyObject_GetItem(PyTuple_GET_ITEM(keywords, index), key); + if (result != NULL) { + Py_INCREF(result); + return result; + } + if (index >= lastindex) + return NULL; + PyErr_Clear(); + } +} + +/* + get_integer_index consumes 0 or more decimal digit characters + from a format string, updates *result with the corresponding + positive integer, and returns the number of digits consumed. + + if the isargument parameter is true, it will remove the + integer from the arguments bitset. +*/ +static int +get_integer_index(FmtState *fs, Py_ssize_t *result) +{ + Py_ssize_t accumulator, digitval, oldaccumulator; + int numdigits; + accumulator = numdigits = 0; + for (;;fs->fmtstr.ptr++, numdigits++) { + if (fs->fmtstr.ptr >= fs->fmtstr.end) + break; + digitval = CH_TYPE_TODECIMAL(*fs->fmtstr.ptr); + if (digitval < 0) + break; + /* + This trick was copied from old Unicode format code. It's cute, + but would really suck on an old machine with a slow divide + implementation. Fortunately, in the normal case we do not + expect too many digits. + */ + oldaccumulator = accumulator; + accumulator *= 10; + if ((accumulator+10)/10 != oldaccumulator+1) + return (int)SetError("field width or index value too large"); + accumulator += digitval; + } + *result = accumulator; + return numdigits; +} + +/* + get_specifier retrieves the part of the format string + between the colon and trailing }. +*/ +static int +get_specifier(FmtState *fs) +{ + CH_TYPE c; + + int curlycount, gotcurly; + + curlycount = 1; + gotcurly = 0; + + fs->fieldspec.ptr = fs->fmtstr.ptr; + for (;;) { + if (!check_fmtstr(fs)) + return 0; + c = *fs->fmtstr.ptr++; + if (c == '{') { + gotcurly = 1; + curlycount++; + } + else if (c == '}') { + curlycount--; + if (curlycount <= 0) + break; + } + } + fs->fieldspec.end = fs->fmtstr.ptr - 1; + if (gotcurly) { + PyObject *myobject; + SubString savefmt = fs->fmtstr; + fs->fmtstr.ptr = fs->fieldspec.ptr; + fs->fmtstr.end = fs->fieldspec.end; + myobject = recurse_format(fs); + if (myobject == NULL) + return 0; + fs->fieldspec = make_substrobj(myobject); + fs->fmtstr = savefmt; + } + return 1; +} + +/* + get_field_object returns the object inside {} + It handles getindex and getattr lookups and consumes + the format string up to but not including the trailing + } or the optional : format specifier separator. +*/ +static PyObject * +get_field_object(FmtState *fs) +{ + PyObject *myobj, *subobj, *newobj; + CH_TYPE c; + Py_ssize_t index; + int isindex, expectclose, isnumeric, isargument; + + if (!check_fmtstr(fs)) + return NULL; + isnumeric = (CH_TYPE_ISDECIMAL(*fs->fmtstr.ptr)); + myobj = isnumeric ? fs->args : fs->keywords; + Py_INCREF(myobj); + + for (isindex=1, expectclose=0, isargument=1;;) { + if (!check_fmtstr(fs)) + break; + if (!isindex) { + if ((subobj = get_python_identifier(fs, isargument)) == NULL) + break; + newobj = (isargument && fs->keywords_is_tuple) + ? name_mapper(myobj, subobj) + : PyObject_GetAttr(myobj, subobj); + Py_DECREF(subobj); + } + else { + isnumeric = (CH_TYPE_ISDECIMAL(*fs->fmtstr.ptr)); + if (isnumeric) { + get_integer_index(fs, &index); + if (isargument) + fs->positional_arg_set &= ~(1 << index); + } + if (isnumeric && PySequence_Check(myobj)) + newobj = PySequence_GetItem(myobj, index); + else { + /* XXX -- do we need PyLong_FromLongLong? Using ssizet, not int... */ + subobj = isnumeric ? + PyInt_FromLong(index) : + get_python_identifier(fs, isargument); + if (subobj == NULL) + break; + newobj = PyObject_GetItem(myobj, subobj); + Py_DECREF(subobj); + } + } + Py_DECREF(myobj); + myobj = newobj; + if (expectclose) + if ((!check_fmtstr(fs)) || (*fs->fmtstr.ptr++ != ']')) { + SetError("Expected ]"); + break; + } + if (!check_fmtstr(fs)) + break; + c = *fs->fmtstr.ptr; + if ((c == '}') || (c == ':')) + return myobj; + fs->fmtstr.ptr++; + isargument = 0; + isindex = expectclose = (c == '['); + if (!isindex && (c != '.')) { + SetError("Expected ., [, :, or }"); + break; + } + } + Py_DECREF(myobj); + return NULL; +} +/* + get_field_and_spec calls subfunctions to retrieve the + field object and optional specification string. +*/ +static PyObject * +get_field_and_spec(FmtState *fs) +{ + PyObject *myobj; + CH_TYPE c; + + fs->fieldspec.ptr = fs->fieldspec.end = fs->fmtstr.ptr; + fs->fieldspec.obj = NULL; + + myobj = get_field_object(fs); + if (myobj != NULL) { + if (check_fmtstr(fs)) { + c = *fs->fmtstr.ptr++; + if ((c == '}') || ((c == ':') && (get_specifier(fs)))) + return myobj; + } + Py_DECREF(myobj); + } + return NULL; +} + +/* + user_format is invoked to format an object with a defined __format__ + attribute. +*/ +static int +user_format(FmtState *fs, PyObject *__format__) +{ + PyObject *myobj; + int ok; + + myobj = fs->fieldspec.obj; + if (myobj == NULL) { + myobj = STROBJ_NEW(fs->fieldspec.ptr, + fs->fieldspec.end - fs->fieldspec.ptr); + if (myobj == NULL) + return 0; + fs->fieldspec.obj = myobj; /* Owned by our caller now */ + } + /* XXX -- possible optimization to CallFunctionWithArgs */ + myobj = PyObject_CallFunction(__format__, "(O)", myobj); + if (myobj == NULL) + return 0; + ok = STROBJ_CHECK(myobj); + if (!ok) + SetError("__format__ method did not return correct string type"); + else + ok = output_data(fs, STROBJ_AS_PTR(myobj), + STROBJ_GET_SIZE(myobj)); + Py_DECREF(myobj); + return ok; +} + +typedef struct { + CH_TYPE fill_char; + CH_TYPE align; + CH_TYPE sign; + Py_ssize_t width; + Py_ssize_t precision; + CH_TYPE type; +} DefaultFormat; + +/* + parse the default specification +*/ + +static int +parse_default_format(FmtState *fs, DefaultFormat *format) +{ + Py_ssize_t index = 0; + Py_ssize_t specified_width; + Py_ssize_t remaining; + SubString *spec = &fs->fmtstr; + + format->fill_char = '\0'; + format->align = '\0'; + format->sign = '\0'; + format->width = -1; + format->precision = -1; + format->type = '\0'; + + /* cache the length, since that's convenient */ + Py_ssize_t spec_len = spec->end - spec->ptr; + + /* If the second char is an alignment token, + then parse the fill char */ + if (spec_len >= 2 && alignment_token(spec->ptr[1])) { + format->align = spec->ptr[1]; + format->fill_char = spec->ptr[0]; + index = 2; + } else if (spec_len >= 1 && alignment_token(spec->ptr[0])) { + format->align = spec->ptr[0]; + index = 1; + } + + /* Parse the various sign options */ + if (index < spec_len && sign_element(spec->ptr[index])) { + format->sign = spec->ptr[index]; + index++; + if (index < spec_len && spec->ptr[index] == ')') { + index++; + } + } + + /* The special case for 0-padding (backwards compat) */ + if (format->fill_char == '\0' && index < spec_len && spec->ptr[index] == '0') { + format->fill_char = '0'; + if (format->align == '\0') { + format->align = '='; + } + index++; + } + + specified_width = get_integer_index(fs, &format->width); + + /* recalculate the length, since the pointers may have just changed */ + spec_len = spec->end - spec->ptr; + + /* if specified_width is 0, we didn't consume any characters for the width. + in that case, reset the width to -1, because get_integer_index() will + have set it to zero */ + if (specified_width <= 0) { + format->width = -1; + } + + /* Parse field precision */ + if (index < spec_len && spec->ptr[index] == '.') { + index++; + + specified_width = get_integer_index(fs, &format->precision); + + /* recalculate the length, since the pointers may have just changed */ + spec_len = spec->end - spec->ptr; + + /* again, check if any characters specified */ + if (specified_width <= 0) { + format->precision = -1; + } + } + + /* Finally, parse the type field */ + + remaining = spec_len - index; + if (remaining > 1) { + /* invalid conversion spec */ + SetError("Invalid conversion specification"); + return 0; + } + + if (remaining == 1) { + format->type = spec->ptr[index]; + } + + return 1; +} + + +/* conversion functions */ +static Py_ssize_t +convert_binary(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_char(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_decimal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_exponent(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_exponentUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_fixed(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_fixedUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_general(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_generalUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_number(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_octal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_repr(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + int ok; + PyObject *s; + PyObject *r; + Py_ssize_t len; + + r = PyObject_Repr(fieldobj); + if (r == NULL) + return 0; + + s = STROBJ_STR(r); + Py_DECREF(r); + + len = STROBJ_GET_SIZE(s); + ok = output_data(fs, STROBJ_AS_PTR(s), len); + Py_DECREF(s); + + return ok ? len : -1; +} + +static Py_ssize_t +convert_string(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + PyObject *myobj; + Py_ssize_t ok; + Py_ssize_t len; + + myobj = STROBJ_STR(fieldobj); + if (myobj == NULL) + return -1; + + len = STROBJ_GET_SIZE(myobj); + + ok = output_data(fs, STROBJ_AS_PTR(myobj), len); + Py_DECREF(myobj); + + return ok ? len : -1; +} + +static Py_ssize_t +convert_hex(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_hexUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +static Py_ssize_t +convert_percentage(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +{ + return -1; +} + +/* + default_format -- "Then a miracle occurs" +*/ +static int default_format(FmtState *fs, PyObject *fieldobj) +{ +#if DUMMY_FORMATTING == 1 + PyObject *myobj; + int ok; + + /* Test implementation, only at top level */ + CH_TYPE under = '_'; + + myobj = STROBJ_STR(fieldobj); + if (myobj == NULL) + return 0; + ok = output_data(fs, STROBJ_AS_PTR(myobj), + STROBJ_GET_SIZE(myobj)); + Py_DECREF(myobj); + if (!ok) + return 0; + if (fs->fieldspec.ptr != fs->fieldspec.end) { + if (!output_data(fs, &under, 1)) + return 0; + if (!output_data(fs, fs->fieldspec.ptr, + fs->fieldspec.end - fs->fieldspec.ptr)) + return 0; + } +#else + + Py_ssize_t len; + Py_ssize_t padding; + DefaultFormat format; + ConversionFunction conversion; + CH_TYPE sign = '\0'; + CH_TYPE prefix; + CH_TYPE suffix; + + if (!parse_default_format(fs, &format)) { + return 0; + } + + /* if no type character was specified, look up the default type character, based on the type of our object */ + if (format.type == '\0') { + if (PyInt_Check(fieldobj) || PyLong_Check(fieldobj)) { + format.type = 'd'; + } else if (PyFloat_Check(fieldobj)) { + format.type = 'g'; + } else { + format.type = 's'; + } + } + + /* handle conversion functions that logically map to other conversion functions? */ + + conversion = conversion_function(format.type); + if (conversion == NULL) { + SetError("Invalid conversion character"); + return 0; + } + + /* convert to a string first */ + /* get the length written so that we can fixup inside the buffer, as needed */ + len = conversion(fieldobj, fs, &sign); + if (len < 0) + return 0; + + /* we wrote "len" bytes. see what fixups need to be done */ + + /* Handle the sign logic */ + prefix = '\0'; + suffix = '\0'; + if (sign == '-') { + if (format.sign == '(') { + prefix = '('; + suffix = ')'; + } else { + prefix = '-'; + } + } else if (sign == '+') { + if (format.sign == '+') { + prefix = '+'; + } else if (format.sign == ' ') { + prefix = ' '; + } + } + + /* Handle the padding logic */ + if (format.width != -1) { + padding = format.width - len - (prefix == '\0' ? 0 : 1) - (suffix == '\0' ? 0 : 1); + if (padding > 0) { +#if 0 + if align == '>' or align == '^': + return fill_char * padding + prefix + result + suffix + elif align == '=' + return prefix + fill_char * padding + result + suffix + else: + return prefix + result + suffix + fill_char * padding + +#endif + } + } + +#endif + return 1; +} + +/* + renderfield determines if the field object has a defined __format__ + method, and dispatches to the appropriate subfunction. +*/ +static int +renderfield(FmtState *fs, PyObject *fieldobj) +{ + int result; + SubString savefmt; + + PyObject *__format__ = PyObject_GetAttrString(fieldobj, "__format__"); + if (__format__ != NULL) { + result = user_format(fs, __format__); + Py_DECREF(__format__); + } + else { + /* XXX -- saw other things just do this, but Guido mentioned + that maybe we should check whether the error was + an AttributeError or not. Figure out if this is + necessary -- if so, and not AttributeError, propagate + the error up the stack. + */ + PyErr_Clear(); /* For GetAttr __format__ */ + + savefmt = fs->fmtstr; + fs->fmtstr.ptr = fs->fieldspec.ptr; + fs->fmtstr.end = fs->fieldspec.end; + result = default_format(fs, fieldobj); + fs->fmtstr = savefmt; + } + return result; +} + +/* + do_format is the main program loop. It rummages through + the format string, looking for escapes to markup, and + calls other functions to move non-markup text to the output, + and to perform the markup to the output. +*/ +static PyObject * +do_format(FmtState *fs) +{ + PyObject *myobj; + CH_TYPE c, *start; + Py_ssize_t count, total; + SubString fmtstr; + int doubled, ok; + + fmtstr = fs->fmtstr; + count = fmtstr.end - fmtstr.ptr; + myobj = STROBJ_NEW(NULL, count + INITIAL_SIZE_INCREMENT); + if (myobj == NULL) + return NULL; + fs->outstr = make_substrobj(myobj); + fs->size_increment = INITIAL_SIZE_INCREMENT; + + ok = 1; + c = '\0'; /* Avoid compiler warning */ + while (fmtstr.ptr < fmtstr.end) { + start = fmtstr.ptr; + count = total = fmtstr.end - start; + while (count && ((c = *fmtstr.ptr) != '{') && (c != '}')) { + fmtstr.ptr++; + count--; + } + count = total - count; + total -= count; + doubled = (total > 1) && (fmtstr.ptr[1] == c); + if (doubled) { + output_data(fs, start, count+1); + fmtstr.ptr += 2; + continue; + } else if (count) + output_data(fs, start, count); + if (total < 2) { + ok = !total || + (int)SetError("Invalid format string -- { or } at end"); + break; + } + if (c == '}') { + SetError("Invalid format string -- single } encountered"); + ok = 0; + break; + } + fs->fmtstr.ptr = fmtstr.ptr + 1; + myobj = get_field_and_spec(fs); + ok = (myobj != NULL) && renderfield(fs, myobj); + Py_XDECREF(fs->fieldspec.obj); + Py_XDECREF(myobj); + if (!ok) + break; + fmtstr.ptr = fs->fmtstr.ptr; + } + myobj = fs->outstr.obj; + if (ok) { + count = fs->outstr.ptr - STROBJ_AS_PTR(myobj); + if (STROBJ_RESIZE(&myobj, count) >= 0) + return myobj; + } + Py_XDECREF(myobj); + return NULL; +} + +/* + recurse_format is called for nested format specifiers, + e.g. {1:{2}}. It saves off the current information, + and recursively calls do_format. +*/ +static PyObject * +recurse_format(FmtState *fs) +{ + PyObject *result; + SubStringObj saveoutstr = fs->outstr; + int saveincrement = fs->size_increment; + if (--(fs->max_recursion) < 0) + return SetError("Max string recursion exceeded"); + result = do_format(fs); + fs->max_recursion++; + fs->outstr = saveoutstr; + fs->size_increment = saveincrement; + return result; +} + +/* + STROBJ_FORMAT (actually PyUnicode_FormatMethod or PyString_FormatMethod) + is the public interface to the module. + + XXX -- do we need to check input types here, or are we guaranteed + they are right???? +*/ +PyObject * +STROBJ_FORMAT(PyObject *self, PyObject *args, PyObject *keywords) +{ + FmtState fs; + + fs.max_recursion = 4; + fs.allow_leading_under = 1; + fs.positional_arg_set = 0; + fs.keyword_arg_set = NULL; + fs.keywords_is_tuple = 0; + + fs.fmtstr.ptr = STROBJ_AS_PTR(self); + fs.fmtstr.end = fs.fmtstr.ptr + STROBJ_GET_SIZE(self); + fs.args = args; + fs.keywords = keywords; + + return do_format(&fs); +} + +#ifdef __cplusplus +} +#endif From python-checkins at python.org Thu Mar 1 09:43:11 2007 From: python-checkins at python.org (patrick.maupin) Date: Thu, 1 Mar 2007 09:43:11 +0100 (CET) Subject: [Python-checkins] r54057 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070301084311.E49911E4002@bag.python.org> Author: patrick.maupin Date: Thu Mar 1 09:43:11 2007 New Revision: 54057 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Reduced size of all lines below 80 characters Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Thu Mar 1 09:43:11 2007 @@ -7,8 +7,8 @@ This module designed and written by Patrick Maupin and Eric V Smith - This module is designed to be compiled standalone, or from inside stringformat.c, - to support both unicode and traditional strings. + This module is designed to be compiled standalone, or from inside + stringformat.c, to support both unicode and traditional strings. */ /* @@ -126,27 +126,59 @@ returns the number of characters written, or -1 if error */ /* XXX obviously wrong, but just a placeholder currently */ -typedef Py_ssize_t (*ConversionFunction)(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +typedef Py_ssize_t +(*ConversionFunction)(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); /* Forward declarations for our conversion functions */ -static Py_ssize_t convert_binary(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_char(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_decimal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_exponent(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_exponentUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_fixed(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_fixedUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_general(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_generalUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_number(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_octal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_repr(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_string(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_hex(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_hexUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); -static Py_ssize_t convert_percentage(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +static Py_ssize_t +convert_binary(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_char(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_decimal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_exponent(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_exponentUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_fixed(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_fixedUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_general(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_generalUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_number(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_octal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_repr(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_string(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_hex(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_hexUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + +static Py_ssize_t +convert_percentage(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); /* Some forward declarations for recursion */ @@ -235,12 +267,15 @@ case 'c': return convert_char; /* as character */ case 'd': return convert_decimal; /* decimal integer */ case 'e': return convert_exponent; /* exponential notation */ - case 'E': return convert_exponentUC; /* exponential notation with uppercase 'E' */ + case 'E': return convert_exponentUC; /* exponential notation + with uppercase 'E' */ case 'f': return convert_fixed; /* fixed-point */ case 'F': return convert_fixedUC; /* fixed-point with uppercase */ case 'g': return convert_general; /* general number notation */ - case 'G': return convert_generalUC; /* general number notation with uppercase 'E' */ - case 'n': return convert_number; /* number in locale-specific format */ + case 'G': return convert_generalUC; /* general number notation + with uppercase 'E' */ + case 'n': return convert_number; /* number in locale-specific + format */ case 'o': return convert_octal; /* octal */ case 'r': return convert_repr; /* in repr() format */ case 's': return convert_string; /* convert using str() */ @@ -357,7 +392,8 @@ if (XXX -- need check function) { Py_DECREF(result); - PyErr_SetString(PyExc_ValueError, "Invalid embedded Python identifier"); + PyErr_SetString(PyExc_ValueError, + "Invalid embedded Python identifier"); return NULL; } */ @@ -511,7 +547,8 @@ if (isnumeric && PySequence_Check(myobj)) newobj = PySequence_GetItem(myobj, index); else { - /* XXX -- do we need PyLong_FromLongLong? Using ssizet, not int... */ + /* XXX -- do we need PyLong_FromLongLong? + Using ssizet, not int... */ subobj = isnumeric ? PyInt_FromLong(index) : get_python_identifier(fs, isargument); @@ -653,7 +690,8 @@ } /* The special case for 0-padding (backwards compat) */ - if (format->fill_char == '\0' && index < spec_len && spec->ptr[index] == '0') { + if (format->fill_char == '\0' && + index < spec_len && spec->ptr[index] == '0') { format->fill_char = '0'; if (format->align == '\0') { format->align = '='; @@ -666,9 +704,9 @@ /* recalculate the length, since the pointers may have just changed */ spec_len = spec->end - spec->ptr; - /* if specified_width is 0, we didn't consume any characters for the width. - in that case, reset the width to -1, because get_integer_index() will - have set it to zero */ + /* if specified_width is 0, we didn't consume any characters for + the width. in that case, reset the width to -1, because + get_integer_index() will have set it to zero */ if (specified_width <= 0) { format->width = -1; } @@ -872,7 +910,8 @@ return 0; } - /* if no type character was specified, look up the default type character, based on the type of our object */ + /* if no type character was specified, look up the default + type character, based on the type of our object */ if (format.type == '\0') { if (PyInt_Check(fieldobj) || PyLong_Check(fieldobj)) { format.type = 'd'; @@ -883,7 +922,8 @@ } } - /* handle conversion functions that logically map to other conversion functions? */ + /* handle conversion functions that logically map to + other conversion functions? */ conversion = conversion_function(format.type); if (conversion == NULL) { @@ -892,7 +932,8 @@ } /* convert to a string first */ - /* get the length written so that we can fixup inside the buffer, as needed */ + /* get the length written so that we can fixup + inside the buffer, as needed */ len = conversion(fieldobj, fs, &sign); if (len < 0) return 0; @@ -919,7 +960,8 @@ /* Handle the padding logic */ if (format.width != -1) { - padding = format.width - len - (prefix == '\0' ? 0 : 1) - (suffix == '\0' ? 0 : 1); + padding = format.width - len - (prefix == '\0' ? 0 : 1) - + (suffix == '\0' ? 0 : 1); if (padding > 0) { #if 0 if align == '>' or align == '^': From python-checkins at python.org Thu Mar 1 14:24:10 2007 From: python-checkins at python.org (eric.smith) Date: Thu, 1 Mar 2007 14:24:10 +0100 (CET) Subject: [Python-checkins] r54058 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070301132410.E3F2A1E4002@bag.python.org> Author: eric.smith Date: Thu Mar 1 14:24:08 2007 New Revision: 54058 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Moved conversion functions so that forward declarations are no longer needed. It's one less thing to maintain. Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Thu Mar 1 14:24:08 2007 @@ -120,67 +120,6 @@ int keywords_is_tuple; } FmtState; -/* - Our internal conversion functions have this signature. - - returns the number of characters written, or -1 if error -*/ -/* XXX obviously wrong, but just a placeholder currently */ -typedef Py_ssize_t -(*ConversionFunction)(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -/* - Forward declarations for our conversion functions -*/ -static Py_ssize_t -convert_binary(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_char(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_decimal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_exponent(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_exponentUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_fixed(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_fixedUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_general(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_generalUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_number(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_octal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_repr(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_string(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_hex(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_hexUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - -static Py_ssize_t -convert_percentage(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); - - /* Some forward declarations for recursion */ static PyObject * get_field_object(FmtState *fs); @@ -258,35 +197,6 @@ -/* returns a pointer to our conversion function, or NULL if invalid */ -Py_LOCAL_INLINE(ConversionFunction) -conversion_function(CH_TYPE c) -{ - switch (c) { - case 'b': return convert_binary; /* base-2 */ - case 'c': return convert_char; /* as character */ - case 'd': return convert_decimal; /* decimal integer */ - case 'e': return convert_exponent; /* exponential notation */ - case 'E': return convert_exponentUC; /* exponential notation - with uppercase 'E' */ - case 'f': return convert_fixed; /* fixed-point */ - case 'F': return convert_fixedUC; /* fixed-point with uppercase */ - case 'g': return convert_general; /* general number notation */ - case 'G': return convert_generalUC; /* general number notation - with uppercase 'E' */ - case 'n': return convert_number; /* number in locale-specific - format */ - case 'o': return convert_octal; /* octal */ - case 'r': return convert_repr; /* in repr() format */ - case 's': return convert_string; /* convert using str() */ - case 'x': return convert_hex; /* base 16 */ - case 'X': return convert_hexUC; /* base 16 uppercase */ - case '%': return convert_percentage; /* as percentage */ - default: - return NULL; - } -} - /* Fill in a SubStringObj from a Python string */ Py_LOCAL_INLINE(SubStringObj) make_substrobj(PyObject *obj) @@ -743,6 +653,15 @@ } +/* + Our internal conversion functions have this signature. + + returns the number of characters written, or -1 if error +*/ +/* XXX obviously wrong, but just a placeholder currently */ +typedef Py_ssize_t +(*ConversionFunction)(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); + /* conversion functions */ static Py_ssize_t convert_binary(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) @@ -869,6 +788,35 @@ return -1; } +/* returns a pointer to our conversion function, or NULL if invalid */ +Py_LOCAL_INLINE(ConversionFunction) +conversion_function(CH_TYPE c) +{ + switch (c) { + case 'b': return convert_binary; /* base-2 */ + case 'c': return convert_char; /* as character */ + case 'd': return convert_decimal; /* decimal integer */ + case 'e': return convert_exponent; /* exponential notation */ + case 'E': return convert_exponentUC; /* exponential notation + with uppercase 'E' */ + case 'f': return convert_fixed; /* fixed-point */ + case 'F': return convert_fixedUC; /* fixed-point with uppercase */ + case 'g': return convert_general; /* general number notation */ + case 'G': return convert_generalUC; /* general number notation + with uppercase 'E' */ + case 'n': return convert_number; /* number in locale-specific + format */ + case 'o': return convert_octal; /* octal */ + case 'r': return convert_repr; /* in repr() format */ + case 's': return convert_string; /* convert using str() */ + case 'x': return convert_hex; /* base 16 */ + case 'X': return convert_hexUC; /* base 16 uppercase */ + case '%': return convert_percentage; /* as percentage */ + default: + return NULL; + } +} + /* default_format -- "Then a miracle occurs" */ From python-checkins at python.org Thu Mar 1 14:33:35 2007 From: python-checkins at python.org (eric.smith) Date: Thu, 1 Mar 2007 14:33:35 +0100 (CET) Subject: [Python-checkins] r54059 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070301133335.5A7DA1E4008@bag.python.org> Author: eric.smith Date: Thu Mar 1 14:33:32 2007 New Revision: 54059 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Removed alignment character '^'. It was in Talin's sample python implementation, but not in the PEP. Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Thu Mar 1 14:33:32 2007 @@ -176,7 +176,7 @@ alignment_token(CH_TYPE c) { switch (c) { - case '<': case '>': case '=': case '^': + case '<': case '>': case '=': return 1; default: return 0; @@ -912,7 +912,7 @@ (suffix == '\0' ? 0 : 1); if (padding > 0) { #if 0 - if align == '>' or align == '^': + if align == '>': return fill_char * padding + prefix + result + suffix elif align == '=' return prefix + fill_char * padding + result + suffix From python-checkins at python.org Thu Mar 1 15:07:21 2007 From: python-checkins at python.org (andrew.kuchling) Date: Thu, 1 Mar 2007 15:07:21 +0100 (CET) Subject: [Python-checkins] r54060 - python/branches/release25-maint/Doc/lib/libcollections.tex Message-ID: <20070301140721.58BB11E4002@bag.python.org> Author: andrew.kuchling Date: Thu Mar 1 15:07:19 2007 New Revision: 54060 Modified: python/branches/release25-maint/Doc/lib/libcollections.tex Log: Fix typo (noticed in Raymond's r54053 commit adding NamedTuple Modified: python/branches/release25-maint/Doc/lib/libcollections.tex ============================================================================== --- python/branches/release25-maint/Doc/lib/libcollections.tex (original) +++ python/branches/release25-maint/Doc/lib/libcollections.tex Thu Mar 1 15:07:19 2007 @@ -16,7 +16,7 @@ \subsection{\class{deque} objects \label{deque-objects}} \begin{funcdesc}{deque}{\optional{iterable}} - Returns a new deque objected initialized left-to-right (using + Returns a new deque object initialized left-to-right (using \method{append()}) with data from \var{iterable}. If \var{iterable} is not specified, the new deque is empty. From python-checkins at python.org Thu Mar 1 15:36:13 2007 From: python-checkins at python.org (andrew.kuchling) Date: Thu, 1 Mar 2007 15:36:13 +0100 (CET) Subject: [Python-checkins] r54061 - python/trunk/Doc/whatsnew/whatsnew26.tex Message-ID: <20070301143613.839E41E4002@bag.python.org> Author: andrew.kuchling Date: Thu Mar 1 15:36:12 2007 New Revision: 54061 Modified: python/trunk/Doc/whatsnew/whatsnew26.tex Log: Add NamedTuple Modified: python/trunk/Doc/whatsnew/whatsnew26.tex ============================================================================== --- python/trunk/Doc/whatsnew/whatsnew26.tex (original) +++ python/trunk/Doc/whatsnew/whatsnew26.tex Thu Mar 1 15:36:12 2007 @@ -76,6 +76,22 @@ \begin{itemize} +\item New data type in the \module{collections} module: +\class{NamedTuple(\var{typename}, \var{fieldnames})} is a factory function that +creates subclasses of the standard tuple whose fields are accessible +by name as well as index. For example: + +\begin{verbatim} +var_type = collections.NamedTuple('variable', + 'id name type size') +var = var_type(1, 'frequency', 'int', 4) + +print var[0], var.id # Equivalent +print var[2], var.type # Equivalent +\end{verbatim} + +(Contributed by Raymond Hettinger.) + \item New function in the \module{heapq} module: \function{merge(iter1, iter2, ...)} takes any number of iterables that return data From python-checkins at python.org Thu Mar 1 17:31:59 2007 From: python-checkins at python.org (brett.cannon) Date: Thu, 1 Mar 2007 17:31:59 +0100 (CET) Subject: [Python-checkins] r54062 - python/branches/p3yk_no_args_on_exc/Objects/exceptions.c Message-ID: <20070301163159.6A2771E4002@bag.python.org> Author: brett.cannon Date: Thu Mar 1 17:31:57 2007 New Revision: 54062 Modified: python/branches/p3yk_no_args_on_exc/Objects/exceptions.c Log: Add BaseException's name to its PyArg_ParseTuple() call. Modified: python/branches/p3yk_no_args_on_exc/Objects/exceptions.c ============================================================================== --- python/branches/p3yk_no_args_on_exc/Objects/exceptions.c (original) +++ python/branches/p3yk_no_args_on_exc/Objects/exceptions.c Thu Mar 1 17:31:57 2007 @@ -42,7 +42,7 @@ if (!_PyArg_NoKeywords(self->ob_type->tp_name, kwds)) return -1; - if (!PyArg_ParseTuple(args, "|O", &message)) + if (!PyArg_ParseTuple(args, "|O:BaseException", &message)) return -1; if (message) { From python-checkins at python.org Thu Mar 1 18:53:29 2007 From: python-checkins at python.org (patrick.maupin) Date: Thu, 1 Mar 2007 18:53:29 +0100 (CET) Subject: [Python-checkins] r54063 - sandbox/trunk/pep3101/loadpep.py sandbox/trunk/pep3101/makefile sandbox/trunk/pep3101/pep3101.c sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070301175329.E6B201E400B@bag.python.org> Author: patrick.maupin Date: Thu Mar 1 18:53:24 2007 New Revision: 54063 Added: sandbox/trunk/pep3101/loadpep.py sandbox/trunk/pep3101/makefile Modified: sandbox/trunk/pep3101/pep3101.c sandbox/trunk/pep3101/unicodeformat.c Log: Generalized the dispatch mechanism, added test/build infrastructure Added: sandbox/trunk/pep3101/loadpep.py ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/loadpep.py Thu Mar 1 18:53:24 2007 @@ -0,0 +1,16 @@ + +import sys + +platdict = dict( + linux2='build/lib.linux-i686-%s.%s', +) + +platstr = platdict.get(sys.platform) + +if platstr is None: + raise ValueError("Unknown platform") + +sys.path.append(platstr % sys.version_info[:2]) + +import test_simpleformat +test_simpleformat.test_main() Added: sandbox/trunk/pep3101/makefile ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/makefile Thu Mar 1 18:53:24 2007 @@ -0,0 +1,29 @@ + +SRCS = pep3101.c stringformat.c unicodeformat.c pep3101.h setup.py + +PY30 = ../bin/python +PY24 = python2.4 + +test: test24 test30 + +all: 24 30 + +24: build/lib.linux-i686-2.4/pep3101.so + +30: build/lib.linux-i686-3.0/pep3101.so + +build/lib.linux-i686-3.0/pep3101.so: $(SRCS) + $(PY30) setup.py build + +build/lib.linux-i686-2.4/pep3101.so: $(SRCS) + $(PY24) setup.py build + +test24: 24 + $(PY24) loadpep.py + +test30: 30 + $(PY24) loadpep.py + +clean: + rm -Rf build *.pyc + Modified: sandbox/trunk/pep3101/pep3101.c ============================================================================== --- sandbox/trunk/pep3101/pep3101.c (original) +++ sandbox/trunk/pep3101/pep3101.c Thu Mar 1 18:53:24 2007 @@ -11,26 +11,35 @@ ; static PyObject * -pep3101_format(PyObject *self, PyObject *args, PyObject *keywords) +StringDispatch(ternaryfunc *table, PyObject *self, PyObject *args, PyObject *keywords) { - PyObject *newargs, *newself, *result; - newself = PyTuple_GetItem(args, 0); /* borrowed reference */ - if (newself == NULL) - return NULL; - newargs = PyTuple_GetSlice(args, 1, PyTuple_Size(args) + 1); - if (newargs == NULL) - return NULL; - if (PyUnicode_Check(newself)) - result = PyUnicode_FormatMethod(newself, newargs, keywords); - else if (PyString_Check(newself)) - result = PyString_FormatMethod(newself, newargs, keywords); + PyObject *myobj = self; + + if (self == NULL) { + if (!PyTuple_GET_SIZE(args)) { + PyErr_SetString(PyExc_TypeError, + "Function expects at least one argument"); + return NULL; + } + myobj = PyTuple_GET_ITEM(args, 0); + } + if (PyUnicode_Check(myobj)) + return table[0](self, args, keywords); + else if (PyString_Check(self)) + return table[1](self, args, keywords); else { - result = NULL; PyErr_SetString(PyExc_TypeError, - "First parameter to format must be string or unicode object"); + "First parameter must be string or unicode object"); + return NULL; } - Py_DECREF(newargs); - return result; +} + +static PyObject * +pep3101_format(PyObject *self, PyObject *args, PyObject *keywords) +{ + static ternaryfunc table[2] = + {PyUnicode_FormatMethod, PyString_FormatMethod}; + return StringDispatch(table, self, args, keywords); } /* List of methods defined in the module */ Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Thu Mar 1 18:53:24 2007 @@ -81,15 +81,30 @@ } SubStringObj; /* + A MarkupEscapeHandler allows us to handle different escape + mechanisms between regular text and markup. This is useful + both for providing alternate markup syntax, and for + providing an eval() type function where there is no regular + text. +*/ +typedef struct FmtState *FSPTR; +typedef int +(*MarkupEscapeHandler)(FSPTR fs); + +/* If this were written in C++, FmtState would be the class, and most of the functions inside this file would be members of this class. */ -typedef struct { +typedef struct FmtState { /* args passed to PyString_FormatMethod or PyUnicode_FormatMethod */ PyObject *args; /* keywords passed to PyString_FormatMethod or PyUnicode_FormatMethod */ PyObject *keywords; + /* arg_param_offset is 1 if not called as a method */ + int arg_param_offset; + /* Function to call to perform markup */ + MarkupEscapeHandler do_markup; /* current position and end of the 'self' string passed to FormatMethod */ SubString fmtstr; /* Output string we are constructing, including current and end pointers*/ @@ -212,7 +227,7 @@ static void PySet_Discard(PyObject *myset, PyObject *mykey) { - /* XXX --- Need to add the right code here */ + Py_XDECREF(PyObject_CallMethod(myset, "discard", "(O)", mykey)); } #endif @@ -430,6 +445,7 @@ Py_ssize_t index; int isindex, expectclose, isnumeric, isargument; + index = 0; /* Just to shut up the compiler warning */ if (!check_fmtstr(fs)) return NULL; isnumeric = (CH_TYPE_ISDECIMAL(*fs->fmtstr.ptr)); @@ -454,6 +470,7 @@ if (isargument) fs->positional_arg_set &= ~(1 << index); } + if (isnumeric && PySequence_Check(myobj)) newobj = PySequence_GetItem(myobj, index); else { @@ -961,13 +978,13 @@ } /* - do_format is the main program loop. It rummages through + do_markup is the main program loop. It rummages through the format string, looking for escapes to markup, and calls other functions to move non-markup text to the output, and to perform the markup to the output. */ -static PyObject * -do_format(FmtState *fs) +static int +do_markup(FmtState *fs) { PyObject *myobj; CH_TYPE c, *start; @@ -976,13 +993,6 @@ int doubled, ok; fmtstr = fs->fmtstr; - count = fmtstr.end - fmtstr.ptr; - myobj = STROBJ_NEW(NULL, count + INITIAL_SIZE_INCREMENT); - if (myobj == NULL) - return NULL; - fs->outstr = make_substrobj(myobj); - fs->size_increment = INITIAL_SIZE_INCREMENT; - ok = 1; c = '\0'; /* Avoid compiler warning */ while (fmtstr.ptr < fmtstr.end) { @@ -1020,9 +1030,31 @@ break; fmtstr.ptr = fs->fmtstr.ptr; } - myobj = fs->outstr.obj; + return ok; +} + +/* + do_format allocates the output string and then + calls a markup handler to do the dirty work. +*/ +static PyObject * +do_format(FmtState *fs) +{ + PyObject *myobj; + int ok; + + myobj = STROBJ_NEW(NULL, + fs->fmtstr.end - fs->fmtstr.ptr + INITIAL_SIZE_INCREMENT); + if (myobj == NULL) + return NULL; + fs->outstr = make_substrobj(myobj); + fs->size_increment = INITIAL_SIZE_INCREMENT; + + ok = fs->do_markup(fs); + + myobj = fs->outstr.obj; /* Might have been reallocated */ if (ok) { - count = fs->outstr.ptr - STROBJ_AS_PTR(myobj); + int count = fs->outstr.ptr - STROBJ_AS_PTR(myobj); if (STROBJ_RESIZE(&myobj, count) >= 0) return myobj; } @@ -1050,6 +1082,7 @@ return result; } + /* STROBJ_FORMAT (actually PyUnicode_FormatMethod or PyString_FormatMethod) is the public interface to the module. @@ -1062,12 +1095,25 @@ { FmtState fs; + /* This function can be called as a python function or as a method */ + if (self == NULL) { + if (!PyTuple_GET_SIZE(args)) { + PyErr_SetString(PyExc_TypeError, + "function expects at least one argument"); + return NULL; + } + self = PyTuple_GET_ITEM(args, 0); + fs.arg_param_offset = 1; + } + else + fs.arg_param_offset = 0; + fs.max_recursion = 4; fs.allow_leading_under = 1; fs.positional_arg_set = 0; fs.keyword_arg_set = NULL; fs.keywords_is_tuple = 0; - + fs.do_markup = do_markup; fs.fmtstr.ptr = STROBJ_AS_PTR(self); fs.fmtstr.end = fs.fmtstr.ptr + STROBJ_GET_SIZE(self); fs.args = args; From python-checkins at python.org Thu Mar 1 19:10:15 2007 From: python-checkins at python.org (patrick.maupin) Date: Thu, 1 Mar 2007 19:10:15 +0100 (CET) Subject: [Python-checkins] r54064 - sandbox/trunk/pep3101/pep3101.c sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070301181015.7525E1E4002@bag.python.org> Author: patrick.maupin Date: Thu Mar 1 19:10:12 2007 New Revision: 54064 Modified: sandbox/trunk/pep3101/pep3101.c sandbox/trunk/pep3101/unicodeformat.c Log: Fixed bugs introduced when my import was picking up old .so file Modified: sandbox/trunk/pep3101/pep3101.c ============================================================================== --- sandbox/trunk/pep3101/pep3101.c (original) +++ sandbox/trunk/pep3101/pep3101.c Thu Mar 1 19:10:12 2007 @@ -25,7 +25,7 @@ } if (PyUnicode_Check(myobj)) return table[0](self, args, keywords); - else if (PyString_Check(self)) + else if (PyString_Check(myobj)) return table[1](self, args, keywords); else { PyErr_SetString(PyExc_TypeError, Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Thu Mar 1 19:10:12 2007 @@ -467,8 +467,10 @@ isnumeric = (CH_TYPE_ISDECIMAL(*fs->fmtstr.ptr)); if (isnumeric) { get_integer_index(fs, &index); - if (isargument) + if (isargument) { fs->positional_arg_set &= ~(1 << index); + index += fs->arg_param_offset; + } } if (isnumeric && PySequence_Check(myobj)) From python-checkins at python.org Thu Mar 1 19:54:07 2007 From: python-checkins at python.org (brett.cannon) Date: Thu, 1 Mar 2007 19:54:07 +0100 (CET) Subject: [Python-checkins] r54065 - python/branches/p3yk_no_args_on_exc/Objects/exceptions.c Message-ID: <20070301185407.CA1901E4002@bag.python.org> Author: brett.cannon Date: Thu Mar 1 19:54:06 2007 New Revision: 54065 Modified: python/branches/p3yk_no_args_on_exc/Objects/exceptions.c Log: Swith to PyArg_UnpackTuple() for BaseException_init. Modified: python/branches/p3yk_no_args_on_exc/Objects/exceptions.c ============================================================================== --- python/branches/p3yk_no_args_on_exc/Objects/exceptions.c (original) +++ python/branches/p3yk_no_args_on_exc/Objects/exceptions.c Thu Mar 1 19:54:06 2007 @@ -42,7 +42,7 @@ if (!_PyArg_NoKeywords(self->ob_type->tp_name, kwds)) return -1; - if (!PyArg_ParseTuple(args, "|O:BaseException", &message)) + if (!PyArg_UnpackTuple(args, "BaseException", 0, 1, &message)) return -1; if (message) { From python-checkins at python.org Thu Mar 1 21:54:13 2007 From: python-checkins at python.org (patrick.maupin) Date: Thu, 1 Mar 2007 21:54:13 +0100 (CET) Subject: [Python-checkins] r54067 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070301205413.94D2F1E4002@bag.python.org> Author: patrick.maupin Date: Thu Mar 1 21:54:10 2007 New Revision: 54067 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Added method option parsing code to format func Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Thu Mar 1 21:54:10 2007 @@ -102,6 +102,7 @@ /* keywords passed to PyString_FormatMethod or PyUnicode_FormatMethod */ PyObject *keywords; /* arg_param_offset is 1 if not called as a method */ + int num_args; int arg_param_offset; /* Function to call to perform markup */ MarkupEscapeHandler do_markup; @@ -224,11 +225,9 @@ } #if PYTHON_API_VERSION < 1013 -static void -PySet_Discard(PyObject *myset, PyObject *mykey) -{ - Py_XDECREF(PyObject_CallMethod(myset, "discard", "(O)", mykey)); -} +#define PySet_Discard PyDict_DelItem +#define PySet_New PyDict_Copy +#define PySet_GET_SIZE PyDict_Size #endif /* XXX -- similar function elsewhere ???? */ @@ -1084,6 +1083,94 @@ return result; } +static int +get_options(PyObject *keywords, FmtState *fs) +{ + static char* keys[3] = { + "useall", "allow_leading_under", NULL + }; + int values[2]; + int index; + + PyObject *flags, *myobj; + + fs->max_recursion = 4; + fs->allow_leading_under = 1; /* XXX- SHould set to 0, but breaks */ + fs->positional_arg_set = 0; + fs->keyword_arg_set = NULL; + fs->keywords_is_tuple = 0; + fs->do_markup = do_markup; + fs->keywords = keywords; + + flags = PyDict_GetItemString(keywords, "_dict"); + if (flags == NULL) + return 1; + + for (index=0; keys[index] != NULL; index++) { + myobj = PyDict_GetItemString(flags, keys[index]); + if (myobj == NULL) + values[index] = 0; + else if (PyInt_Check(myobj)) + values[index] = PyInt_AS_LONG(myobj); + else { + PyErr_SetString(PyExc_TypeError, + "All flags values must be integers"); + return 0; + } + } + if (values[0]) { + fs->positional_arg_set = (1 << fs->num_args) - 1; + fs->keyword_arg_set = PySet_New(keywords); + if (!fs->keyword_arg_set) + return 0; + } + fs->allow_leading_under = values[1]; + return 1; +} + +static int +get_self_args(PyObject *self, PyObject *args, FmtState *fs) +{ + fs->num_args = PyTuple_GET_SIZE(args); + if (self == NULL) { + if (!fs->num_args) { + PyErr_SetString(PyExc_TypeError, + "Function expects at least one argument"); + return 0; + } + self = PyTuple_GET_ITEM(args, 0); + if (!STROBJ_CHECK(self)) { + PyErr_SetString(PyExc_TypeError, + "Not valid format string"); + return 0; + } + fs->arg_param_offset = 1; + fs->num_args -= 1; + } + else + fs->arg_param_offset = 0; + fs->args = args; + fs->fmtstr.ptr = STROBJ_AS_PTR(self); + fs->fmtstr.end = fs->fmtstr.ptr + STROBJ_GET_SIZE(self); + return 1; +} + +static PyObject * +fs_cleanup(PyObject *result, FmtState *fs) +{ + PyObject *used; + int ok = result != NULL; + used = fs->keyword_arg_set; + if (ok && used) { + ok = (PySet_GET_SIZE(used) <= 1) && !fs->positional_arg_set; + if (!ok) { + Py_DECREF(result); + result = SetError("Not all arguments consumed"); + } + } + Py_XDECREF(used); + return result; +} /* STROBJ_FORMAT (actually PyUnicode_FormatMethod or PyString_FormatMethod) @@ -1098,30 +1185,11 @@ FmtState fs; /* This function can be called as a python function or as a method */ - if (self == NULL) { - if (!PyTuple_GET_SIZE(args)) { - PyErr_SetString(PyExc_TypeError, - "function expects at least one argument"); - return NULL; - } - self = PyTuple_GET_ITEM(args, 0); - fs.arg_param_offset = 1; - } - else - fs.arg_param_offset = 0; - - fs.max_recursion = 4; - fs.allow_leading_under = 1; - fs.positional_arg_set = 0; - fs.keyword_arg_set = NULL; - fs.keywords_is_tuple = 0; - fs.do_markup = do_markup; - fs.fmtstr.ptr = STROBJ_AS_PTR(self); - fs.fmtstr.end = fs.fmtstr.ptr + STROBJ_GET_SIZE(self); - fs.args = args; - fs.keywords = keywords; + if (!get_self_args(self, args, &fs) || + !get_options(keywords, &fs)) + return NULL; - return do_format(&fs); + return fs_cleanup(do_format(&fs), &fs); } #ifdef __cplusplus From python-checkins at python.org Thu Mar 1 23:39:01 2007 From: python-checkins at python.org (jack.diederich) Date: Thu, 1 Mar 2007 23:39:01 +0100 (CET) Subject: [Python-checkins] r54070 - peps/trunk/pep-0306.txt Message-ID: <20070301223901.556281E4003@bag.python.org> Author: jack.diederich Date: Thu Mar 1 23:39:00 2007 New Revision: 54070 Modified: peps/trunk/pep-0306.txt Log: * update the Checklist to reflect the current ast/compiler Modified: peps/trunk/pep-0306.txt ============================================================================== --- peps/trunk/pep-0306.txt (original) +++ peps/trunk/pep-0306.txt Thu Mar 1 23:39:00 2007 @@ -2,7 +2,7 @@ Title: How to Change Python's Grammar Version: $Revision$ Last-Modified: $Date$ -Author: Michael Hudson +Author: Michael Hudson , Jack Diederich , Nick Coghlan Status: Active Type: Informational Content-Type: text/plain @@ -33,13 +33,26 @@ Checklist - __ Grammar/Grammar: OK, you'd probably worked this one out :) + __ Grammar/Grammar: OK, you'd probably worked this one out :) - __ Python/compile.c: you'll most likely need to edit both the - actual compiler and the symtable builder (which is to say both - the com_foo and the sym_foo functions). + __ Parser/Python.asdl may need changes to match the Grammar. + Use Parser/asdl_c.py to regenerate Include/Python-ast.h - __ You may need to regenerate Lib/symbol.py and/or Lib/token.py. + __ Python/Python-ast.c may need changes to create the AST + objects involved with the Grammar change. Lib/compiler/ast.py + will need matching changes to the pure-python AST objects. + + __ Parser/pgen needs to be rerun to regenerate Include/graminit.h + and Python/graminit.c + + __ Python/symbtable.c: This handles the symbol collection pass + that happens immediately before the compilation pass + + __ Python/compile.c: You will need to create or modify the + compiler_* functions for your productions. + + __ You may need to regenerate Lib/symbol.py and/or Lib/token.py + and/or Lib/keyword.py __ The parser module. Add some of your new syntax to test_parser, bang on parsermodule.c until it passes. @@ -47,22 +60,17 @@ __ The compiler package. A good test is to compile the standard library and test suite with the compiler package and then check it runs. You did add some of your new syntax to the test - suite, didn't you? There's a script in Tools/compiler that - does this. + suite, didn't you? __ If you've gone so far as to change the token structure of - Python, then the tokenizer library module will need to be - changed. + Python, then the Lib/tokenizer.py library module will need to + be changed. __ Certain changes may require tweaks to the library module pyclbr. - __ Jython too will need work, but I don't know what. Explanations - gratefully received. - __ Documentation must be written! - References [1] SF Bug #676521, parser module validation failure From python-checkins at python.org Fri Mar 2 02:22:28 2007 From: python-checkins at python.org (phillip.eby) Date: Fri, 2 Mar 2007 02:22:28 +0100 (CET) Subject: [Python-checkins] r54071 - sandbox/trunk/setuptools/setuptools/command/test.py Message-ID: <20070302012228.997511E4004@bag.python.org> Author: phillip.eby Date: Fri Mar 2 02:22:27 2007 New Revision: 54071 Modified: sandbox/trunk/setuptools/setuptools/command/test.py Log: Fix problem activating dependencies for tests Modified: sandbox/trunk/setuptools/setuptools/command/test.py ============================================================================== --- sandbox/trunk/setuptools/setuptools/command/test.py (original) +++ sandbox/trunk/setuptools/setuptools/command/test.py Fri Mar 2 02:22:27 2007 @@ -96,6 +96,7 @@ try: sys.path.insert(0, normalize_path(ei_cmd.egg_base)) working_set.__init__() + add_activation_listener(lambda dist: dist.activate()) require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version)) func() finally: @@ -120,7 +121,6 @@ - def run_tests(self): import unittest loader_ep = EntryPoint.parse("x="+self.test_loader) From python-checkins at python.org Fri Mar 2 02:23:32 2007 From: python-checkins at python.org (phillip.eby) Date: Fri, 2 Mar 2007 02:23:32 +0100 (CET) Subject: [Python-checkins] r54072 - sandbox/branches/setuptools-0.6/setuptools/command/test.py Message-ID: <20070302012332.B26B51E400A@bag.python.org> Author: phillip.eby Date: Fri Mar 2 02:23:32 2007 New Revision: 54072 Modified: sandbox/branches/setuptools-0.6/setuptools/command/test.py Log: Fix problem activating dependencies for tests (backport from trunk) Modified: sandbox/branches/setuptools-0.6/setuptools/command/test.py ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools/command/test.py (original) +++ sandbox/branches/setuptools-0.6/setuptools/command/test.py Fri Mar 2 02:23:32 2007 @@ -96,6 +96,7 @@ try: sys.path.insert(0, normalize_path(ei_cmd.egg_base)) working_set.__init__() + add_activation_listener(lambda dist: dist.activate()) require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version)) func() finally: @@ -120,7 +121,6 @@ - def run_tests(self): import unittest loader_ep = EntryPoint.parse("x="+self.test_loader) From python-checkins at python.org Fri Mar 2 02:38:44 2007 From: python-checkins at python.org (patrick.maupin) Date: Fri, 2 Mar 2007 02:38:44 +0100 (CET) Subject: [Python-checkins] r54073 - sandbox/trunk/pep3101/loadpep.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070302013844.1D99F1E4004@bag.python.org> Author: patrick.maupin Date: Fri Mar 2 02:38:38 2007 New Revision: 54073 Modified: sandbox/trunk/pep3101/loadpep.py sandbox/trunk/pep3101/unicodeformat.c Log: Cope with null keyword arguments (need testcase for this) Modified: sandbox/trunk/pep3101/loadpep.py ============================================================================== --- sandbox/trunk/pep3101/loadpep.py (original) +++ sandbox/trunk/pep3101/loadpep.py Fri Mar 2 02:38:38 2007 @@ -12,5 +12,8 @@ sys.path.append(platstr % sys.version_info[:2]) -import test_simpleformat -test_simpleformat.test_main() +if __name__ == '__main__': + import test_simpleformat + test_simpleformat.test_main() + from pep3101 import format as f + f('Hi there') Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Fri Mar 2 02:38:38 2007 @@ -449,6 +449,8 @@ return NULL; isnumeric = (CH_TYPE_ISDECIMAL(*fs->fmtstr.ptr)); myobj = isnumeric ? fs->args : fs->keywords; + if (myobj == NULL) + return SetError("No keyword arguments passed"); Py_INCREF(myobj); for (isindex=1, expectclose=0, isargument=1;;) { @@ -1102,6 +1104,9 @@ fs->do_markup = do_markup; fs->keywords = keywords; + if (keywords == NULL) + return 1; + flags = PyDict_GetItemString(keywords, "_dict"); if (flags == NULL) return 1; From python-checkins at python.org Fri Mar 2 03:03:19 2007 From: python-checkins at python.org (patrick.maupin) Date: Fri, 2 Mar 2007 03:03:19 +0100 (CET) Subject: [Python-checkins] r54074 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070302020319.0F84F1E4004@bag.python.org> Author: patrick.maupin Date: Fri Mar 2 03:03:11 2007 New Revision: 54074 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Disallow leading underscores by default, fix _flags and tests Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Fri Mar 2 03:03:11 2007 @@ -57,10 +57,17 @@ if name == "five": return 5 raise TypeError("Never do this") self.formatEquals( - "Count with me; 1 2 4", + "Count with me; 1 4", + "Count with me; {0.one} {1.four4}", + Container, Container, item=Container) + self.formatRaises(ValueError, "Count with me; {0.one} {item._two} {1.four4}", Container, Container, item=Container) self.formatEquals( + "Count with me; 1 2 4", + "Count with me; {0.one} {item._two} {1.four4}", + Container, Container, item=Container, _flags=dict(allow_leading_under=1)) + self.formatEquals( "Five is 5", "Five is {c.five}", c=Container()) self.formatRaises(AttributeError, "Missing {0.rabbit} lookup", Container) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Fri Mar 2 03:03:11 2007 @@ -1097,7 +1097,7 @@ PyObject *flags, *myobj; fs->max_recursion = 4; - fs->allow_leading_under = 1; /* XXX- SHould set to 0, but breaks */ + fs->allow_leading_under = 0; fs->positional_arg_set = 0; fs->keyword_arg_set = NULL; fs->keywords_is_tuple = 0; @@ -1107,7 +1107,7 @@ if (keywords == NULL) return 1; - flags = PyDict_GetItemString(keywords, "_dict"); + flags = PyDict_GetItemString(keywords, "_flags"); if (flags == NULL) return 1; From python-checkins at python.org Fri Mar 2 04:19:11 2007 From: python-checkins at python.org (eric.smith) Date: Fri, 2 Mar 2007 04:19:11 +0100 (CET) Subject: [Python-checkins] r54075 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070302031911.16D581E4004@bag.python.org> Author: eric.smith Date: Fri Mar 2 04:19:03 2007 New Revision: 54075 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Added output_allocate() so I can allocate memory separately from copying into it. Modified signature of built-in conversion functions. Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Fri Mar 2 04:19:03 2007 @@ -230,18 +230,19 @@ #define PySet_GET_SIZE PyDict_Size #endif -/* XXX -- similar function elsewhere ???? */ /* - output_data dumps characters into our output string - buffer. + output_allocate reserves space in our output string buffer In some cases, it has to reallocate the string. It returns a status: 0 for a failed reallocation, 1 for success. + + On success, it sets *ptr to point to the allocated memory. */ + static int -output_data(FmtState *fs, const CH_TYPE *s, Py_ssize_t count) +output_allocate(FmtState *fs, Py_ssize_t count, CH_TYPE **ptr) { Py_ssize_t room = fs->outstr.end - fs->outstr.ptr; if (count > room) { @@ -258,11 +259,31 @@ if (fs->size_increment < MAX_SIZE_INCREMENT) fs->size_increment *= SIZE_MULTIPLIER; } - memcpy(fs->outstr.ptr, s, count * sizeof(CH_TYPE)); + *ptr = fs->outstr.ptr; fs->outstr.ptr += count; return 1; } +/* XXX -- similar function elsewhere ???? */ +/* + output_data dumps characters into our output string + buffer. + + In some cases, it has to reallocate the string. + + It returns a status: 0 for a failed reallocation, + 1 for success. +*/ +static int +output_data(FmtState *fs, const CH_TYPE *s, Py_ssize_t count) +{ + CH_TYPE *dst; + if (output_allocate(fs, count, &dst) == 0) + return 0; + memcpy(dst, s, count * sizeof(CH_TYPE)); + return 1; +} + /* get_python_identifier is a bit of a misnomer. It returns a value for use with getattr or getindex. This value @@ -477,7 +498,7 @@ if (isnumeric && PySequence_Check(myobj)) newobj = PySequence_GetItem(myobj, index); else { - /* XXX -- do we need PyLong_FromLongLong? + /* XXX -- do we need PyLong_FromLongLong? Using ssizet, not int... */ subobj = isnumeric ? PyInt_FromLong(index) : @@ -680,77 +701,77 @@ */ /* XXX obviously wrong, but just a placeholder currently */ typedef Py_ssize_t -(*ConversionFunction)(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign); +(*ConversionFunction)(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format); /* conversion functions */ static Py_ssize_t -convert_binary(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_binary(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_char(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_char(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_decimal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_decimal(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_exponent(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_exponent(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_exponentUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_exponentUC(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_fixed(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_fixed(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_fixedUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_fixedUC(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_general(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_general(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_generalUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_generalUC(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_number(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_number(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_octal(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_octal(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_repr(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_repr(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { int ok; PyObject *s; @@ -772,11 +793,12 @@ } static Py_ssize_t -convert_string(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_string(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { PyObject *myobj; Py_ssize_t ok; Py_ssize_t len; + CH_TYPE *dst; myobj = STROBJ_STR(fieldobj); if (myobj == NULL) @@ -784,26 +806,30 @@ len = STROBJ_GET_SIZE(myobj); - ok = output_data(fs, STROBJ_AS_PTR(myobj), len); + /* reserve all the space we'll need */ + ok = output_allocate(fs, len, &dst); + if (ok) { + memcpy(dst, STROBJ_AS_PTR(myobj), len * sizeof(CH_TYPE)); + } Py_DECREF(myobj); return ok ? len : -1; } static Py_ssize_t -convert_hex(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_hex(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_hexUC(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_hexUC(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } static Py_ssize_t -convert_percentage(PyObject *fieldobj, FmtState *fs, CH_TYPE *sign) +convert_percentage(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) { return -1; } @@ -902,7 +928,7 @@ /* convert to a string first */ /* get the length written so that we can fixup inside the buffer, as needed */ - len = conversion(fieldobj, fs, &sign); + len = conversion(fieldobj, fs, &format); if (len < 0) return 0; From python-checkins at python.org Fri Mar 2 06:13:40 2007 From: python-checkins at python.org (patrick.maupin) Date: Fri, 2 Mar 2007 06:13:40 +0100 (CET) Subject: [Python-checkins] r54076 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070302051340.9FB1E1E4004@bag.python.org> Author: patrick.maupin Date: Fri Mar 2 06:13:36 2007 New Revision: 54076 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Reordered code to group into logical sections. Added format string location to exception messages. Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Fri Mar 2 06:13:36 2007 @@ -11,9 +11,11 @@ stringformat.c, to support both unicode and traditional strings. */ -/* - XXX -- todo: insert a fragment of the source string into error messages -*/ +/************************************************************************/ +/*********** Macros to encapsulate build differences ****************/ +/************************************************************************/ + +/* We can build for several Python versions, and for Unicode or strings */ #ifndef COMPILED_FROM_INSIDE_STRINGFORMAT #include "Python.h" @@ -55,6 +57,16 @@ #define SIZE_MULTIPLIER 2 #define MAX_SIZE_INCREMENT 3200 +#if PYTHON_API_VERSION < 1013 +#define PySet_Discard PyDict_DelItem +#define PySet_New PyDict_Copy +#define PySet_GET_SIZE PyDict_Size +#endif + +/************************************************************************/ +/*********** Global data structures and forward declarations *********/ +/************************************************************************/ + #ifdef __cplusplus extern "C" { #endif @@ -108,6 +120,8 @@ MarkupEscapeHandler do_markup; /* current position and end of the 'self' string passed to FormatMethod */ SubString fmtstr; + /* Used for error reporting */ + CH_TYPE *fmtstart; /* Output string we are constructing, including current and end pointers*/ SubStringObj outstr; /* Field Specifier, after the colon in {1:{2}} @@ -143,15 +157,27 @@ static PyObject * recurse_format(FmtState *fs); +/************************************************************************/ +/*********** Error handling and exception generation **************/ +/************************************************************************/ + /* Most of our errors are value errors, because to Python, the format string is a "value". Also, it's convenient to return a NULL when we are erroring out. */ static void * -SetError(const char *s) +SetError(FmtState *fs, const char *s) { - PyErr_SetString(PyExc_ValueError, s); + if (fs->fmtstr.ptr == fs->fmtstr.end) + PyErr_Format(PyExc_ValueError, "%s at end of format_string", s); + else if ((fs->fmtstr.ptr >= fs->fmtstart) && + (fs->fmtstr.ptr < fs->fmtstr.end)) + PyErr_Format(PyExc_ValueError, "%s at format_string[%d]", + s, fs->fmtstr.ptr - fs->fmtstart); + else + PyErr_Format(PyExc_ValueError, + "%s (apparently in computed format specifier)", s); return NULL; } @@ -163,55 +189,12 @@ check_fmtstr(FmtState *fs) { return (fs->fmtstr.ptr < fs->fmtstr.end) || - SetError("Invalid format string"); -} - -/* - end_identifier returns true if a character marks - the end of an identifier string. - - Although the PEP specifies that identifiers are - numbers or valid Python identifiers, we just let - getattr/getitem handle that, so the implementation - is more flexible than the PEP would indicate. -*/ -Py_LOCAL_INLINE(int) -end_identifier(CH_TYPE c) -{ - switch (c) { - case '.': case '[': case ']': case '}': case ':': - return 1; - default: - return 0; - } + SetError(fs, "Unexpected end of format_string"); } - -/* returns true if this character is a specifier alignment token */ -Py_LOCAL_INLINE(int) -alignment_token(CH_TYPE c) -{ - switch (c) { - case '<': case '>': case '=': - return 1; - default: - return 0; - } -} - -/* returns true if this character is a sign element */ -Py_LOCAL_INLINE(int) -sign_element(CH_TYPE c) -{ - switch (c) { - case ' ': case '+': case '-': case '(': - return 1; - default: - return 0; - } -} - - +/************************************************************************/ +/*********** Output string management functions ****************/ +/************************************************************************/ /* Fill in a SubStringObj from a Python string */ Py_LOCAL_INLINE(SubStringObj) @@ -224,12 +207,6 @@ return s; } -#if PYTHON_API_VERSION < 1013 -#define PySet_Discard PyDict_DelItem -#define PySet_New PyDict_Copy -#define PySet_GET_SIZE PyDict_Size -#endif - /* output_allocate reserves space in our output string buffer @@ -264,7 +241,6 @@ return 1; } -/* XXX -- similar function elsewhere ???? */ /* output_data dumps characters into our output string buffer. @@ -284,6 +260,66 @@ return 1; } +/************************************************************************/ +/*********** Format string parsing -- integers and identifiers *********/ +/************************************************************************/ + +/* + end_identifier returns true if a character marks + the end of an identifier string. + + Although the PEP specifies that identifiers are + numbers or valid Python identifiers, we just let + getattr/getitem handle that, so the implementation + is more flexible than the PEP would indicate. +*/ +Py_LOCAL_INLINE(int) +end_identifier(CH_TYPE c) +{ + switch (c) { + case '.': case '[': case ']': case '}': case ':': + return 1; + default: + return 0; + } +} + +/* + get_integer_index consumes 0 or more decimal digit characters + from a format string, updates *result with the corresponding + positive integer, and returns the number of digits consumed. + + if the isargument parameter is true, it will remove the + integer from the arguments bitset. +*/ +static int +get_integer_index(FmtState *fs, Py_ssize_t *result) +{ + Py_ssize_t accumulator, digitval, oldaccumulator; + int numdigits; + accumulator = numdigits = 0; + for (;;fs->fmtstr.ptr++, numdigits++) { + if (fs->fmtstr.ptr >= fs->fmtstr.end) + break; + digitval = CH_TYPE_TODECIMAL(*fs->fmtstr.ptr); + if (digitval < 0) + break; + /* + This trick was copied from old Unicode format code. It's cute, + but would really suck on an old machine with a slow divide + implementation. Fortunately, in the normal case we do not + expect too many digits. + */ + oldaccumulator = accumulator; + accumulator *= 10; + if ((accumulator+10)/10 != oldaccumulator+1) + return (int)SetError(fs, "Too many digits"); + accumulator += digitval; + } + *result = accumulator; + return numdigits; +} + /* get_python_identifier is a bit of a misnomer. It returns a value for use with getattr or getindex. This value @@ -303,17 +339,18 @@ lookups and computed attribute names */ if (--fs->max_recursion < 0) - return SetError("Max string recursion exceeded"); + return SetError(fs, "Maximum string recursion limit exceeded"); result = get_field_object(fs); fs->max_recursion++; if (result && (*fs->fmtstr.ptr++ != '}')) - result = SetError("Expected closing }"); + result = SetError(fs, "Expected closing }"); return result; } if (end_identifier(*fs->fmtstr.ptr)) - return SetError("Expected attribute or index"); + return SetError(fs, "Expected attribute or index"); if ((*fs->fmtstr.ptr == '_') && !fs->allow_leading_under) - return SetError("Index/attribute leading underscores disallowed"); + return SetError(fs, + "Leading underscores not allowed in attribute/index strings"); for (startptr = fs->fmtstr.ptr; !end_identifier(*fs->fmtstr.ptr); @@ -345,6 +382,15 @@ return result; } +/************************************************************************/ +/******** Functions to get field objects and specification strings ******/ +/************************************************************************/ + +/* get_field_and_spec is the main function in this section. It parses + the format string well enough to return a field object to render along + with a field specification string. +*/ + /* If keywords are supplied as a sequence of dictionaries (e.g. locals/globals) then name_mapper will do multiple @@ -372,42 +418,6 @@ } /* - get_integer_index consumes 0 or more decimal digit characters - from a format string, updates *result with the corresponding - positive integer, and returns the number of digits consumed. - - if the isargument parameter is true, it will remove the - integer from the arguments bitset. -*/ -static int -get_integer_index(FmtState *fs, Py_ssize_t *result) -{ - Py_ssize_t accumulator, digitval, oldaccumulator; - int numdigits; - accumulator = numdigits = 0; - for (;;fs->fmtstr.ptr++, numdigits++) { - if (fs->fmtstr.ptr >= fs->fmtstr.end) - break; - digitval = CH_TYPE_TODECIMAL(*fs->fmtstr.ptr); - if (digitval < 0) - break; - /* - This trick was copied from old Unicode format code. It's cute, - but would really suck on an old machine with a slow divide - implementation. Fortunately, in the normal case we do not - expect too many digits. - */ - oldaccumulator = accumulator; - accumulator *= 10; - if ((accumulator+10)/10 != oldaccumulator+1) - return (int)SetError("field width or index value too large"); - accumulator += digitval; - } - *result = accumulator; - return numdigits; -} - -/* get_specifier retrieves the part of the format string between the colon and trailing }. */ @@ -471,7 +481,7 @@ isnumeric = (CH_TYPE_ISDECIMAL(*fs->fmtstr.ptr)); myobj = isnumeric ? fs->args : fs->keywords; if (myobj == NULL) - return SetError("No keyword arguments passed"); + return SetError(fs, "Keyword not specified"); Py_INCREF(myobj); for (isindex=1, expectclose=0, isargument=1;;) { @@ -513,7 +523,7 @@ myobj = newobj; if (expectclose) if ((!check_fmtstr(fs)) || (*fs->fmtstr.ptr++ != ']')) { - SetError("Expected ]"); + SetError(fs, "Expected ]"); break; } if (!check_fmtstr(fs)) @@ -525,13 +535,14 @@ isargument = 0; isindex = expectclose = (c == '['); if (!isindex && (c != '.')) { - SetError("Expected ., [, :, or }"); + SetError(fs, "Expected ., [, :, or }"); break; } } Py_DECREF(myobj); return NULL; } + /* get_field_and_spec calls subfunctions to retrieve the field object and optional specification string. @@ -557,37 +568,21 @@ return NULL; } +/************************************************************************/ +/***************** Field rendering functions **************************/ +/************************************************************************/ + /* - user_format is invoked to format an object with a defined __format__ - attribute. + render_field is the main function in this section. It takes the field + object and field specification string generated by get_field_and_spec, + and renders the field into the output string. + + The two main subfunctions of render_field are caller_render (which + calls the object-supplied __format__ hook), and internal_render, which + renders objects which don't have format hoohs. */ -static int -user_format(FmtState *fs, PyObject *__format__) -{ - PyObject *myobj; - int ok; - myobj = fs->fieldspec.obj; - if (myobj == NULL) { - myobj = STROBJ_NEW(fs->fieldspec.ptr, - fs->fieldspec.end - fs->fieldspec.ptr); - if (myobj == NULL) - return 0; - fs->fieldspec.obj = myobj; /* Owned by our caller now */ - } - /* XXX -- possible optimization to CallFunctionWithArgs */ - myobj = PyObject_CallFunction(__format__, "(O)", myobj); - if (myobj == NULL) - return 0; - ok = STROBJ_CHECK(myobj); - if (!ok) - SetError("__format__ method did not return correct string type"); - else - ok = output_data(fs, STROBJ_AS_PTR(myobj), - STROBJ_GET_SIZE(myobj)); - Py_DECREF(myobj); - return ok; -} +#if !DUMMY_FORMATTING typedef struct { CH_TYPE fill_char; @@ -598,12 +593,36 @@ CH_TYPE type; } DefaultFormat; +/* returns true if this character is a specifier alignment token */ +Py_LOCAL_INLINE(int) +alignment_token(CH_TYPE c) +{ + switch (c) { + case '<': case '>': case '=': + return 1; + default: + return 0; + } +} + +/* returns true if this character is a sign element */ +Py_LOCAL_INLINE(int) +sign_element(CH_TYPE c) +{ + switch (c) { + case ' ': case '+': case '-': case '(': + return 1; + default: + return 0; + } +} + /* parse the default specification */ static int -parse_default_format(FmtState *fs, DefaultFormat *format) +parse_internal_render(FmtState *fs, DefaultFormat *format) { Py_ssize_t index = 0; Py_ssize_t specified_width; @@ -682,7 +701,7 @@ remaining = spec_len - index; if (remaining > 1) { /* invalid conversion spec */ - SetError("Invalid conversion specification"); + SetError(fs, "Invalid conversion specification"); return 0; } @@ -862,11 +881,12 @@ return NULL; } } +#endif /* - default_format -- "Then a miracle occurs" + internal_render -- "Then a miracle occurs" */ -static int default_format(FmtState *fs, PyObject *fieldobj) +static int internal_render(FmtState *fs, PyObject *fieldobj) { #if DUMMY_FORMATTING == 1 PyObject *myobj; @@ -900,7 +920,7 @@ CH_TYPE prefix; CH_TYPE suffix; - if (!parse_default_format(fs, &format)) { + if (!parse_internal_render(fs, &format)) { return 0; } @@ -921,7 +941,7 @@ conversion = conversion_function(format.type); if (conversion == NULL) { - SetError("Invalid conversion character"); + SetError(fs, "Invalid conversion character"); return 0; } @@ -974,18 +994,50 @@ } /* - renderfield determines if the field object has a defined __format__ + caller_render is invoked to format an object with a defined __format__ + attribute. +*/ +static int +caller_render(FmtState *fs, PyObject *__format__) +{ + PyObject *myobj; + int ok; + + myobj = fs->fieldspec.obj; + if (myobj == NULL) { + myobj = STROBJ_NEW(fs->fieldspec.ptr, + fs->fieldspec.end - fs->fieldspec.ptr); + if (myobj == NULL) + return 0; + fs->fieldspec.obj = myobj; /* Owned by our caller now */ + } + /* XXX -- possible optimization to CallFunctionWithArgs */ + myobj = PyObject_CallFunction(__format__, "(O)", myobj); + if (myobj == NULL) + return 0; + ok = STROBJ_CHECK(myobj); + if (!ok) + SetError(fs, "__format__ method did not return correct string type"); + else + ok = output_data(fs, STROBJ_AS_PTR(myobj), + STROBJ_GET_SIZE(myobj)); + Py_DECREF(myobj); + return ok; +} + +/* + render_field determines if the field object has a defined __format__ method, and dispatches to the appropriate subfunction. */ static int -renderfield(FmtState *fs, PyObject *fieldobj) +render_field(FmtState *fs, PyObject *fieldobj) { int result; SubString savefmt; PyObject *__format__ = PyObject_GetAttrString(fieldobj, "__format__"); if (__format__ != NULL) { - result = user_format(fs, __format__); + result = caller_render(fs, __format__); Py_DECREF(__format__); } else { @@ -1000,12 +1052,16 @@ savefmt = fs->fmtstr; fs->fmtstr.ptr = fs->fieldspec.ptr; fs->fmtstr.end = fs->fieldspec.end; - result = default_format(fs, fieldobj); + result = internal_render(fs, fieldobj); fs->fmtstr = savefmt; } return result; } +/************************************************************************/ +/******* Output string allocation and escape-to-markup processing ******/ +/************************************************************************/ + /* do_markup is the main program loop. It rummages through the format string, looking for escapes to markup, and @@ -1031,28 +1087,29 @@ fmtstr.ptr++; count--; } + fmtstr.ptr++; count = total - count; total -= count; - doubled = (total > 1) && (fmtstr.ptr[1] == c); + doubled = (total > 1) && (*fmtstr.ptr == c); if (doubled) { output_data(fs, start, count+1); - fmtstr.ptr += 2; + fmtstr.ptr++; continue; } else if (count) output_data(fs, start, count); - if (total < 2) { - ok = !total || - (int)SetError("Invalid format string -- { or } at end"); - break; - } + fs->fmtstr.ptr = fmtstr.ptr; if (c == '}') { - SetError("Invalid format string -- single } encountered"); + SetError(fs, "Single } encountered"); ok = 0; break; } - fs->fmtstr.ptr = fmtstr.ptr + 1; + if (total < 2) { + ok = !total || + (int)SetError(fs, "Single { encountered"); + break; + } myobj = get_field_and_spec(fs); - ok = (myobj != NULL) && renderfield(fs, myobj); + ok = (myobj != NULL) && render_field(fs, myobj); Py_XDECREF(fs->fieldspec.obj); Py_XDECREF(myobj); if (!ok) @@ -1103,7 +1160,7 @@ SubStringObj saveoutstr = fs->outstr; int saveincrement = fs->size_increment; if (--(fs->max_recursion) < 0) - return SetError("Max string recursion exceeded"); + return SetError(fs, "Max string recursion exceeded"); result = do_format(fs); fs->max_recursion++; fs->outstr = saveoutstr; @@ -1111,6 +1168,10 @@ return result; } +/************************************************************************/ +/*********** Main function, option processing, setup and teardown ******/ +/************************************************************************/ + static int get_options(PyObject *keywords, FmtState *fs) { @@ -1181,7 +1242,7 @@ else fs->arg_param_offset = 0; fs->args = args; - fs->fmtstr.ptr = STROBJ_AS_PTR(self); + fs->fmtstr.ptr = fs->fmtstart = STROBJ_AS_PTR(self); fs->fmtstr.end = fs->fmtstr.ptr + STROBJ_GET_SIZE(self); return 1; } @@ -1196,7 +1257,7 @@ ok = (PySet_GET_SIZE(used) <= 1) && !fs->positional_arg_set; if (!ok) { Py_DECREF(result); - result = SetError("Not all arguments consumed"); + result = SetError(fs, "Not all arguments consumed"); } } Py_XDECREF(used); From python-checkins at python.org Fri Mar 2 07:28:11 2007 From: python-checkins at python.org (patrick.maupin) Date: Fri, 2 Mar 2007 07:28:11 +0100 (CET) Subject: [Python-checkins] r54077 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070302062811.B57E31E4004@bag.python.org> Author: patrick.maupin Date: Fri Mar 2 07:28:09 2007 New Revision: 54077 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Better error detection and exception reporting for bad/missing arguments and object index/attribute errors. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Fri Mar 2 07:28:09 2007 @@ -47,8 +47,8 @@ def test_missingargs(self): #self.formatRaises(None, "Doesn't use all {0} args", 42, 24) - self.formatRaises(IndexError, "There is no {4} arg", 42, 24) - self.formatRaises(KeyError, "There question is {when}", who=True) + self.formatRaises(ValueError, "There is no {4} arg", 42, 24) + self.formatRaises(ValueError, "There question is {when}", who=True) def test_attributes(self): class Container(object): Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Fri Mar 2 07:28:09 2007 @@ -121,7 +121,7 @@ /* current position and end of the 'self' string passed to FormatMethod */ SubString fmtstr; /* Used for error reporting */ - CH_TYPE *fmtstart; + CH_TYPE *fmtstart, *fieldstart; /* Output string we are constructing, including current and end pointers*/ SubStringObj outstr; /* Field Specifier, after the colon in {1:{2}} @@ -185,11 +185,18 @@ check_fmtstr returns True if we still have characters left in the format string. */ +static void * +check_fmtstr_helper(FmtState *fs) +{ + fs->fmtstr.ptr = fs->fieldstart; + return SetError(fs, "Unterminated replacement field"); +} + Py_LOCAL_INLINE(int) check_fmtstr(FmtState *fs) { return (fs->fmtstr.ptr < fs->fmtstr.end) || - SetError(fs, "Unexpected end of format_string"); + check_fmtstr_helper(fs); } /************************************************************************/ @@ -478,13 +485,14 @@ index = 0; /* Just to shut up the compiler warning */ if (!check_fmtstr(fs)) return NULL; + isargument=1; isnumeric = (CH_TYPE_ISDECIMAL(*fs->fmtstr.ptr)); myobj = isnumeric ? fs->args : fs->keywords; if (myobj == NULL) - return SetError(fs, "Keyword not specified"); + goto ERROR; Py_INCREF(myobj); - for (isindex=1, expectclose=0, isargument=1;;) { + for (isindex=1, expectclose=0;;) { if (!check_fmtstr(fs)) break; if (!isindex) { @@ -521,6 +529,8 @@ } Py_DECREF(myobj); myobj = newobj; + if (myobj == NULL) + break; if (expectclose) if ((!check_fmtstr(fs)) || (*fs->fmtstr.ptr++ != ']')) { SetError(fs, "Expected ]"); @@ -539,7 +549,16 @@ break; } } - Py_DECREF(myobj); +ERROR: + if ((myobj == NULL) && isargument) + { + PyErr_Clear(); + fs->fmtstr.ptr = fs->fieldstart; + return SetError(fs, isnumeric + ? "Not enough positional arguments" + : "Keyword argument not found"); + } + Py_XDECREF(myobj); return NULL; } @@ -1087,7 +1106,7 @@ fmtstr.ptr++; count--; } - fmtstr.ptr++; + fs->fieldstart = fmtstr.ptr++; count = total - count; total -= count; doubled = (total > 1) && (*fmtstr.ptr == c); From python-checkins at python.org Fri Mar 2 12:42:10 2007 From: python-checkins at python.org (eric.smith) Date: Fri, 2 Mar 2007 12:42:10 +0100 (CET) Subject: [Python-checkins] r54078 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/StringFormat.py Message-ID: <20070302114210.095291E4004@bag.python.org> Author: eric.smith Date: Fri Mar 2 12:42:08 2007 New Revision: 54078 Added: sandbox/trunk/pep3101/StringFormat.py (contents, props changed) Modified: sandbox/trunk/pep3101/README.txt Log: Added StringFormat.py, which is Talin's original pure Python implementation. Only for historical interest. Modified: sandbox/trunk/pep3101/README.txt ============================================================================== --- sandbox/trunk/pep3101/README.txt (original) +++ sandbox/trunk/pep3101/README.txt Fri Mar 2 12:42:08 2007 @@ -42,6 +42,9 @@ Python versions. - setup.py -- Use "build" option to make the extension module - test_simpleformat.py -- initial unittests + - StringFormat.py -- Talin's original implementation in Python. + This is only for historical interest: it doesn't exactly match + the PEP or C implementation. Todo: Added: sandbox/trunk/pep3101/StringFormat.py ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/StringFormat.py Fri Mar 2 12:42:08 2007 @@ -0,0 +1,442 @@ +# Python string formatting + +from math import log +try: + import locale +except: + locale = None +try: + import fpformat +except: + fpformat = None + +# Except for errors in the format string. +class FormatError(StandardError): + pass + +strict_format_errors = False + +class ConversionTypes: + Binary = 'b' # Base-2 + Character = 'c' # Print as character + Decimal = 'd' # Decimal integer + Exponent = 'e' # Exponential notation + ExponentUC = 'E' # Exponential notation with upper case 'E' + Fixed = 'f' # Fixed-point + FixedUC = 'F' # Fixed-point with upper case + General = 'g' # General number notation + GeneralUC = 'G' # General number notation with upper case 'E' + Number = 'n' # Number in locale-specific format + Octal = 'o' # Octal + Repr = 'r' # In repr() format + String = 's' # Convert using str() + Hex = 'x' # Base 16 + HexUC = 'X' # Base 16 upper case + Percentage = '%' # As percentage + +ConversionTypes.All = set(ConversionTypes.__dict__.values()) + +# Parse the standard conversion spec. Note that I don't use +# regex here because I'm trying to eliminate external dependencies +# as much as possible. +def parse_std_conversion(spec): + length = None + precision = None + ctype = None + align = None + fill_char = None + sign = None + + index = 0 + spec_len = len(spec) + + # If the second char is an alignment token, + # then parse the fill char + if spec_len >=2 and spec[ 1 ] in '<>=^': + fill_char = spec[ 0 ] + align = spec[ 1 ] + index = 2 + # Otherwise, parse the alignment token + elif spec_len >= 1 and spec[ 0 ] in '<>=^': + align = spec[ 0 ] + index = 1 + + # Parse the various sign options + if index < spec_len and spec[ index ] in ' +-(': + sign = spec_len[ index ] + index += 1 + if index < spec_len and spec[ index ] == ')': + index += 1 + + # The special case for 0-padding (backwards compat) + if fill_char == None and index < spec_len and spec[ index ] == '0': + fill_char = '0' + if align == None: + align = '=' + index += 1 + + # Parse field width + saveindex = index + while index < spec_len and spec[index].isdigit(): + index += 1 + + if index > saveindex: + length = int(spec[saveindex : index]) + + # Parse field precision + if index < spec_len and spec[index] == '.': + index += 1 + saveindex = index + while index < spec_len and spec[index].isdigit(): + index += 1 + if index > saveindex: + precision = int(spec[saveindex:index]) + + # Finally, parse the type field + remaining = spec_len - index + if remaining > 1: + return None # Invalid conversion spec + + if remaining == 1: + ctype = spec[index] + if ctype not in ConversionTypes.All: + return None + + return (fill_char, align, sign, length, precision, ctype) + +# Convert to int, and split into sign part and magnitude part +def to_int(val): + val = int(val) + if val < 0: return '-', -val + return '+', val + +# Convert to float, and split into sign part and magnitude part +def to_float(val): + val = float(val) + if val < 0: return '-', -val + return '+', val + +# Pure python implementation of the C printf 'e' format specificer +def sci(val,precision,letter='e'): + # Split into sign and magnitude (not really needed for formatting + # since we already did this part. Mainly here in case 'sci' + # ever gets split out as an independent function.) + sign = '' + if val < 0: + sign = '-' + val = -val + + # Calculate the exponent + exp = int(floor(log(val,10))) + + # Normalize the value + val *= 10**-exp + + # If the value is exactly an integer, then we don't want to + # print *any* decimal digits, regardless of precision + if val == floor(val): + val = int(val) + else: + # Otherwise, round it based on precision + val = round(val,precision) + # The rounding operation might have increased the + # number to where it is no longer normalized, if so + # then adjust the exponent. + if val >= 10.0: + exp += 1 + val = val * 0.1 + + # Convert the exponent to a string using only str(). + # The existing C printf always prints at least 2 digits. + esign = '+' + if exp < 0: + exp = -exp + esign = '-' + if exp < 10: exp = '0' + str(exp) + else: exp = str(exp) + + # The final result + return sign + str(val) + letter + esign + exp + +# The standard formatter +def format_builtin_type(value, spec): + + # Parse the conversion spec + conversion = parse_std_conversion(spec) + if conversion is None: + raise FormatError("Invalid conversion spec: " + spec) + + # Unpack the conversion spec + fill_char, align, sign_char, length, precision, ctype = conversion + + # Choose a default conversion type + if ctype == None: + if isinstance(value, int) or isinstance(value, long): + ctype = ConversionTypes.Decimal + elif isinstance(value, float): + ctype = ConversionTypes.General + else: + ctype = ConversionTypes.String + + sign = None + + # Conversion types that resolve to other types + if ctype == ConversionTypes.Percentage: + ctype = ConversionTypes.Fixed + value = float(value) * 100.0 + + if ctype == ConversionTypes.Binary: + result = '' + sign, value = to_int(value) + while value: + if value & 1: result = '1' + result + else: result = '0' + result + value >>= 1 + if len(result) == 0: + result = '0' + elif ctype == ConversionTypes.Octal: + sign, value = to_int(value) + result = oct(value) + elif ctype == ConversionTypes.Hex: + sign, value = to_int(value) + result = hex(value) + elif ctype == ConversionTypes.HexUC: + sign, value = to_int(value) + result = hex(value).upper() + elif ctype == ConversionTypes.Character: + result = chr(int( value) ) + elif ctype == ConversionTypes.Decimal: + sign, value = to_int(value) + result = str(value) + elif ctype == ConversionTypes.Fixed or ctype == ConversionTypes.FixedUC: + sign, value = to_float(value) + if fpformat and precision is not None: + result = fpformat.fix(value, precision) + else: + result = str(value) + elif ctype == ConversionTypes.General or ctype == ConversionTypes.GeneralUC: + #Same as "e" if exponent is less than -4 or greater than precision, "f" otherwise. + sign, value = to_float(value) + if fpformat and precision is not None: + if value < 0.0001 or value > 10**precision: + result = fpformat.sci(value, precision) + else: + result = fpformat.fix(value, precision) + if ctype == ConversionTypes.GeneralUC: + result = result.upper() + else: + result = str(value) + elif ctype == ConversionTypes.Exponent or ctype == ConversionTypes.ExponentUC: + sign, value = to_float(value) + if precision is None: precision = 5 # Duh, I dunno + result = sci(value, precision, ctype) + elif ctype == ConversionTypes.Number: + sign, value = to_float(value) + if locale: + # For some reason, this is not working the way I would + # expect + result = locale.format("%f", float( value) ) + else: + result = str(value) + elif ctype == ConversionTypes.String: + result = str(value) + elif ctype == ConversionTypes.Repr: + result = repr(value) + + # Handle the sign logic + prefix = '' + suffix = '' + if sign == '-': + if sign_char == '(': prefix, suffix = '(', ')' + else: prefix = '-' + elif sign == '+': + if sign_char == '+': prefix = '+' + elif sign_char == ' ': prefix = ' ' + + # Handle the padding logic + if length is not None: + padding = length - len(result) - len(prefix) - len(suffix) + if padding > 0: + if align == '>' or align == '^': + return fill_char * padding + prefix + result + suffix + elif align == '=' + return prefix + fill_char * padding + result + suffix + else: + return prefix + result + suffix + fill_char * padding + + return prefix + result + suffix + +def cformat(template, format_hook, args, kwargs): + # Using array types since we're going to be growing + # a lot. + from array import array + array_type = 'c' + + # Use unicode array if the original string is unicode. + if isinstance(template, unicode): array_type = 'u' + buffer = array(array_type) + + # Track which arguments actuallly got used + unused_args = set(kwargs.keys()) + unused_args.update(range(0, len(args))) + + # Inner function to format a field from a value and + # conversion spec. Most details missing. + def format_field(value, cspec): + + # See if there's a hook + if format_hook: + v = format_hook(value, cspec) + if v is not None: + return str(v) + + # See if there's a __format__ method + elif hasattr(value, '__format__'): + return value.__format__(cspec) + + # Default formatting + return format_builtin_type(value, cspec) + + # Parse a field specification. Returns True if it was a valid + # field, False if it was merely an escaped brace. (We do it + # this way to avoid lookahead.) + def parse_field(buffer): + + # A separate array for the field spec. + fieldspec = array(array_type) + + # Consume from the template iterator. + for index, ch in template_iter: + # A sub-field. We just interpret it like a normal field, + # and append to the fieldspec. + if ch == '{': + # If the very first character is an open brace, then + # assume its an escaped (doubled) brace. + if len(fieldspec) == 0: + return False + + # Here's where we catch that doubled brace + if not parse_field(fieldspec): + buffer.extend('{') + return True + + # End of field. Now interpret it. + elif ch == '}': + # Convert the array to string or uni + if array_type == 'u': + fieldspec = fieldspec.tosunicode() + else: + fieldspec = fieldspec.tostring() + + # Check for conversion spec + name = fieldspec + conversion = '' + parts = fieldspec.split(':', 1) + if len(parts) > 1: + name, conversion = parts + + try: + first_time = True + # Split the field name into subfields + for namepart in name.split('.'): + # Split that part by open bracket chars + keyparts = namepart.split('[') + # The first part is just a bare name + key = keyparts[0] + + # Empty strings are not allowed as field names + if key == '': + raise FormatError("empty field name at char " + str(index)) + + # The first name in the sequence is used to index + # the args/kwargs arrays. Subsequent names are used + # on the result of the previous operation. + if first_time: + first_time = False + + # Attempt to coerce key to integer + try: + key = int(key) + value = args[key] + except ValueError: + # Keyword args are strings, not uni (so far) + value = kwargs[key] + + # If we got no exception, then remove from + # unused args + unused_args.remove(key) + else: + # This is not the first time, so get + # an attribute + value = getattr(value, key) + + # Now process any bracket expressions which followed + # the first part. + for key in keyparts[1:]: + endbracket = key.find(']') + if endbracket < 0 or endbracket != len(key) - 1: + raise FormatError("Invalid field syntax at position " + str(index)) + + # Strip off the closing bracket and try to coerce to int + key = key[:-1] + try: + key = int(key) + except ValueError: + pass + + # Get the attribute + value = value[key] + + except (AttributeError,KeyError,IndexError), e: + if strict_format_errors: raise + buffer.extend('?' + e.__class__.__name__ + '?') + return True + + buffer.extend(format_field(value, conversion)) + return True + else: + fieldspec.append(ch) + + raise FormatError("unmatched open brace at position " + str(index)) + + # Construct an iterator from the template + template_iter = enumerate(template) + prev = None + for index, ch in template_iter: + if prev == '}': + if ch != '}': + raise FormatError("unmatched close brace") + else: + buffer.append('}') + prev = None + continue + + if ch == '{': + # It's a field + if not parse_field(buffer): + buffer.extend('{') + elif ch != '}': + buffer.append(ch) + prev = ch + + if prev == '}': + raise FormatError("unmatched close brace") + + # Complain about unused args + if unused_args and strict_format_errors: + raise FormatError( + "Unused arguments: " + + ",".join(str(x) for x in unused_args)) + + # Convert the array to its proper type + if isinstance(template, unicode): + return buffer.tounicode() + else: + return buffer.tostring() + +def format(template, *args, **kwargs): + return cformat(template, None, args, kwargs) + +if __name__ == '__main__': + print format("This is a test of }} {0:x} {x} {y[3]} {2[2]} {1:5n}{{", + 1000, 200000, 'grag', x='hex', y=[1,2,3]); From python-checkins at python.org Fri Mar 2 13:07:41 2007 From: python-checkins at python.org (eric.smith) Date: Fri, 2 Mar 2007 13:07:41 +0100 (CET) Subject: [Python-checkins] r54079 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070302120741.5E1EA1E4004@bag.python.org> Author: eric.smith Date: Fri Mar 2 13:07:39 2007 New Revision: 54079 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Completed implementation for string and repr formatting. Removed 'DUMMY_FORMATTING' define, so that we can incrementally add and test formatting for various types. Fixed parsing of internal format specifiers, it now no longer caches the length. Added unit tests for strings and repr. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Fri Mar 2 13:07:39 2007 @@ -1,4 +1,3 @@ - import unittest from test import test_support @@ -12,111 +11,134 @@ class FormatTest(unittest.TestCase): - # All tests run through these functions. They can be - # overridden to change the class of string being tested - # and the function being used. - def formatEquals(self, result, text, *args, **kwargs): - text = str(text) - result = str(result) - val = pep3101.format(text, *args, **kwargs) - self.assertEquals(val, result) - - def formatRaises(self, exc, text, *args, **kwargs): - exc = exc or Exception #StringFormat.FormatError - text = str(text) - #prevState = StringFormat.strict_format_errors - #StringFormat.strict_format_errors = True - try: - self.assertRaises(exc, - lambda: pep3101.format( - text, *args, **kwargs)) - finally: - pass - #StringFormat.strict_format_errors = prevState - - - def test_basic(self): - # directly from the pep intro - self.formatEquals( + # All tests run through these functions. They can be + # overridden to change the class of string being tested + # and the function being used. + def formatEquals(self, result, text, *args, **kwargs): + text = str(text) + result = str(result) + val = pep3101.format(text, *args, **kwargs) + self.assertEquals(val, result) + + def formatRaises(self, exc, text, *args, **kwargs): + exc = exc or Exception #StringFormat.FormatError + text = str(text) + #prevState = StringFormat.strict_format_errors + #StringFormat.strict_format_errors = True + try: + self.assertRaises(exc, + lambda: pep3101.format( + text, *args, **kwargs)) + finally: + pass + #StringFormat.strict_format_errors = prevState + + + def test_basic(self): + # directly from the pep intro + self.formatEquals( "My name is Fred", "My name is {0}", "Fred") - self.formatEquals( + self.formatEquals( "My name is Fred :-{}", "My name is {0} :-{{}}", "Fred") - self.formatEquals("abc", "{0:}", "abc") # is this allowed? + self.formatEquals("abc", "{0:}", "abc") # is this allowed? - def test_missingargs(self): - #self.formatRaises(None, "Doesn't use all {0} args", 42, 24) - self.formatRaises(ValueError, "There is no {4} arg", 42, 24) - self.formatRaises(ValueError, "There question is {when}", who=True) - - def test_attributes(self): - class Container(object): - one, _two, four4 = 1, 2, 4 - def __getattr__(self, name): - if name == "five": return 5 - raise TypeError("Never do this") - self.formatEquals( + def test_missingargs(self): + #self.formatRaises(None, "Doesn't use all {0} args", 42, 24) + self.formatRaises(ValueError, "There is no {4} arg", 42, 24) + self.formatRaises(ValueError, "There question is {when}", who=True) + + def test_attributes(self): + class Container(object): + one, _two, four4 = 1, 2, 4 + def __getattr__(self, name): + if name == "five": return 5 + raise TypeError("Never do this") + self.formatEquals( "Count with me; 1 4", "Count with me; {0.one} {1.four4}", Container, Container, item=Container) - self.formatRaises(ValueError, + self.formatRaises(ValueError, "Count with me; {0.one} {item._two} {1.four4}", Container, Container, item=Container) - self.formatEquals( + self.formatEquals( "Count with me; 1 2 4", "Count with me; {0.one} {item._two} {1.four4}", Container, Container, item=Container, _flags=dict(allow_leading_under=1)) - self.formatEquals( + self.formatEquals( "Five is 5", "Five is {c.five}", c=Container()) - self.formatRaises(AttributeError, + self.formatRaises(AttributeError, "Missing {0.rabbit} lookup", Container) - self.formatRaises(TypeError, + self.formatRaises(TypeError, "Forbidden {0.secret} lookup", Container()) - def test_items(self): - d = dict(val="value", sum=1) - t = tuple(("apple", "ball", "cat")) - self.formatEquals( + def test_items(self): + d = dict(val="value", sum=1) + t = tuple(("apple", "ball", "cat")) + self.formatEquals( "The value of apple", "The {0[val]} of {t[0]}", d, t=t) - # Decided against negative indices for now - #self.formatEquals( - # "The shiny red ball", - # "The shiny red {0[-2]}", t) - - def test_formatlookup(self): - self.formatEquals("32_0>4d", "{0:{1}}", 32, "0>4d") - self.formatEquals("32_*>4d", "{0:{1}{2}4{3}}", 32, "*", ">", "d") - - def test_specifiers(self): - self.formatEquals("97_c", "{0:c}", ord("a")) - self.formatEquals("8_08b", "{0:08b}", 8) - self.formatEquals("8_ >3d", "{0: >3d}", 8) - self.formatEquals("0.1515_.0%", "{0:.0%}", .1515) - - def test_custom_format(self): - class Custom(object): - def __format__(self, specifiers): - return specifiers - custom = Custom() - self.formatEquals("magic", "{0:magic}", custom) - self.formatEquals("custom", "{0:{1}}", custom, "custom") - - def test_syntaxerror(self): - self.assertRaises(Exception, "}{", True) - self.assertRaises(Exception, "{0", True) - self.assertRaises(Exception, "{0.[]}", True) - self.assertRaises(Exception, "{0[0}", True) - self.assertRaises(Exception, "{0[0:foo}", True) - self.assertRaises(Exception, "{c]}", True) - self.assertRaises(Exception, "{{1}}", True, 0) - self.assertRaises(Exception, "{{ {{{0}}", True) - self.assertRaises(Exception, "{0}}", True) + # Decided against negative indices for now + #self.formatEquals( + # "The shiny red ball", + # "The shiny red {0[-2]}", t) + + def test_formatlookup(self): + self.formatEquals("32_0>4d", "{0:{1}}", 32, "0>4d") + self.formatEquals("32_*>4d", "{0:{1}{2}4{3}}", 32, "*", ">", "d") + + def test_specifiers(self): + self.formatEquals("97_c", "{0:c}", ord("a")) + self.formatEquals("8_08b", "{0:08b}", 8) + self.formatEquals("8_ >3d", "{0: >3d}", 8) + self.formatEquals("0.1515_.0%", "{0:.0%}", .1515) + + def test_string_specifiers(self): + self.formatEquals("abc", "{0:.3s}", "abc") + + self.formatEquals("ab", "{0:.3s}", "ab") + + self.formatEquals("abc", "{0:.3s}", "abcdef") + self.formatEquals("resultx", "{0:x<7s}", "result") + self.formatEquals("result ", "{0: <7s}", "result") + self.formatEquals("result ", "{0:<7s}", "result") + self.formatEquals(" result", "{0:>7s}", "result") + + def test_repr_specifiers(self): + self.formatEquals("3", "{0:r}", 3) + self.formatEquals("3.141", "{0:5r}", 3.141592654) + + # I'm not sure this is a good test, since the quoting might change + self.formatEquals("'abcdefg'", "{0:r}", "abcdefg") + self.formatEquals("'abcdefg", "{0:8r}", "abcdefg") + + def test_missing_type_specifier(self): + # make sure floats use 'g', ints and longs 'd', and everything else 's' + pass + + def test_custom_format(self): + class Custom(object): + def __format__(self, specifiers): + return specifiers + custom = Custom() + self.formatEquals("magic", "{0:magic}", custom) + self.formatEquals("custom", "{0:{1}}", custom, "custom") + + def test_syntaxerror(self): + self.assertRaises(Exception, "}{", True) + self.assertRaises(Exception, "{0", True) + self.assertRaises(Exception, "{0.[]}", True) + self.assertRaises(Exception, "{0[0}", True) + self.assertRaises(Exception, "{0[0:foo}", True) + self.assertRaises(Exception, "{c]}", True) + self.assertRaises(Exception, "{{1}}", True, 0) + self.assertRaises(Exception, "{{ {{{0}}", True) + self.assertRaises(Exception, "{0}}", True) def test_main(): - test_support.run_unittest(FormatTest) + test_support.run_unittest(FormatTest) if __name__ == "__main__": - test_main() + test_main() Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Fri Mar 2 13:07:39 2007 @@ -158,6 +158,22 @@ recurse_format(FmtState *fs); /************************************************************************/ +/************************** Utility functions ************************/ +/************************************************************************/ + +/* XXX probably a better way to do this. can't use memset, though, + because of Unicode and char* support */ +Py_LOCAL_INLINE(void) +charset(CH_TYPE* dst, CH_TYPE ch, Py_ssize_t len) +{ + CH_TYPE* end = dst + len; + for(; dst < end; dst++) { + *dst = ch; + } +} + + +/************************************************************************/ /*********** Error handling and exception generation **************/ /************************************************************************/ @@ -295,9 +311,6 @@ get_integer_index consumes 0 or more decimal digit characters from a format string, updates *result with the corresponding positive integer, and returns the number of digits consumed. - - if the isargument parameter is true, it will remove the - integer from the arguments bitset. */ static int get_integer_index(FmtState *fs, Py_ssize_t *result) @@ -598,11 +611,9 @@ The two main subfunctions of render_field are caller_render (which calls the object-supplied __format__ hook), and internal_render, which - renders objects which don't have format hoohs. + renders objects which don't have format hooks. */ -#if !DUMMY_FORMATTING - typedef struct { CH_TYPE fill_char; CH_TYPE align; @@ -610,7 +621,7 @@ Py_ssize_t width; Py_ssize_t precision; CH_TYPE type; -} DefaultFormat; +} InternalFormatSpec; /* returns true if this character is a specifier alignment token */ Py_LOCAL_INLINE(int) @@ -636,16 +647,22 @@ } } + +/* a convenience function to return the length of a substring */ +Py_LOCAL_INLINE(int) +spec_len(SubString* spec) +{ + return spec->end - spec->ptr; +} + /* parse the default specification */ static int -parse_internal_render(FmtState *fs, DefaultFormat *format) +parse_internal_render_format_spec(FmtState *fs, InternalFormatSpec *format) { - Py_ssize_t index = 0; Py_ssize_t specified_width; - Py_ssize_t remaining; SubString *spec = &fs->fmtstr; format->fill_char = '\0'; @@ -655,44 +672,38 @@ format->precision = -1; format->type = '\0'; - /* cache the length, since that's convenient */ - Py_ssize_t spec_len = spec->end - spec->ptr; - /* If the second char is an alignment token, then parse the fill char */ - if (spec_len >= 2 && alignment_token(spec->ptr[1])) { + if (spec_len(spec) >= 2 && alignment_token(spec->ptr[1])) { format->align = spec->ptr[1]; format->fill_char = spec->ptr[0]; - index = 2; - } else if (spec_len >= 1 && alignment_token(spec->ptr[0])) { + spec->ptr += 2; + } else if (spec_len(spec) >= 1 && alignment_token(spec->ptr[0])) { format->align = spec->ptr[0]; - index = 1; + spec->ptr++; } /* Parse the various sign options */ - if (index < spec_len && sign_element(spec->ptr[index])) { - format->sign = spec->ptr[index]; - index++; - if (index < spec_len && spec->ptr[index] == ')') { - index++; + if (spec_len(spec) >= 1 && sign_element(spec->ptr[0])) { + format->sign = spec->ptr[0]; + spec->ptr++; + if (spec_len(spec) >= 1 && spec->ptr[0] == ')') { + spec->ptr++; } } /* The special case for 0-padding (backwards compat) */ if (format->fill_char == '\0' && - index < spec_len && spec->ptr[index] == '0') { + spec_len(spec) >= 1 && spec->ptr[0] == '0') { format->fill_char = '0'; if (format->align == '\0') { format->align = '='; } - index++; + spec->ptr++; } specified_width = get_integer_index(fs, &format->width); - /* recalculate the length, since the pointers may have just changed */ - spec_len = spec->end - spec->ptr; - /* if specified_width is 0, we didn't consume any characters for the width. in that case, reset the width to -1, because get_integer_index() will have set it to zero */ @@ -701,33 +712,86 @@ } /* Parse field precision */ - if (index < spec_len && spec->ptr[index] == '.') { - index++; + if (spec_len(spec) && spec->ptr[0] == '.') { + spec->ptr++; specified_width = get_integer_index(fs, &format->precision); - /* recalculate the length, since the pointers may have just changed */ - spec_len = spec->end - spec->ptr; - - /* again, check if any characters specified */ + /* not having a precision after a dot is an error */ if (specified_width <= 0) { - format->precision = -1; + SetError(fs, "Missing precision"); + return 0; } + } /* Finally, parse the type field */ - remaining = spec_len - index; - if (remaining > 1) { + if (spec_len(spec) > 1) { /* invalid conversion spec */ SetError(fs, "Invalid conversion specification"); return 0; } - if (remaining == 1) { - format->type = spec->ptr[index]; + if (spec_len(spec) == 1) { + format->type = spec->ptr[0]; + spec->ptr++; } + /* XXX do some consistency checking, like "=" can only be on + signed numbers. or leave that to the individual converers? */ + + return 1; +} + + +/* used to output simple strings, only supports a maximum width and + total field alignment */ +static int +output_string_chars(FmtState *fs, CH_TYPE *src, Py_ssize_t len, const InternalFormatSpec *format) +{ + Py_ssize_t ok; + Py_ssize_t width; /* total field width */ + CH_TYPE *dst; + + /* if precision is specified, output no more that format.precision + characters */ + if (format->precision >= 0 && len >= format->precision) { + len = format->precision; + } + + if (format->width >= 0) { + width = format->width; + } else { + /* not specified, use all of the chars and no more */ + width = len; + } + + /* reserve all the space we'll need */ + if (output_allocate(fs, width, &dst) == 0) + return 0; + + /* now write into that space */ + + /* if right aligning, increment the destination allow space on the left */ + memcpy(dst + (format->align == '>' ? (width - len) : 0), src, len * sizeof(CH_TYPE)); + + /* do any padding */ + if (len != width) { + CH_TYPE fill_char = format->fill_char; + if (fill_char == '\0') { + /* use the default, if not specified */ + fill_char = ' '; + } + + if (format->align == '>') { + /* right align, pad on left */ + charset(dst, fill_char, width - len); + } else { + /* left align, pad on right */ + charset(dst + len, fill_char, width - len); + } + } return 1; } @@ -735,141 +799,190 @@ /* Our internal conversion functions have this signature. - returns the number of characters written, or -1 if error + returns 0 on failure, else 1 */ -/* XXX obviously wrong, but just a placeholder currently */ -typedef Py_ssize_t -(*ConversionFunction)(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format); +typedef int +(*ConversionFunction)(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format); + +/* XXX delete this when all internal conversions are implemented */ +static int +convert_DUMMY(PyObject *fieldobj, FmtState *fs) +{ + PyObject *myobj; + int ok; + + /* Test implementation, only at top level */ + CH_TYPE under = '_'; + + myobj = STROBJ_STR(fieldobj); + if (myobj == NULL) + return 0; + ok = output_data(fs, STROBJ_AS_PTR(myobj), + STROBJ_GET_SIZE(myobj)); + Py_DECREF(myobj); + if (!ok) + return 0; + if (fs->fieldspec.ptr != fs->fieldspec.end) { + if (!output_data(fs, &under, 1)) + return 0; + if (!output_data(fs, fs->fieldspec.ptr, + fs->fieldspec.end - fs->fieldspec.ptr)) + return 0; + } + return 1; +} /* conversion functions */ -static Py_ssize_t -convert_binary(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_binary(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_char(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_char(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_decimal(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_decimal(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); +#if 0 + PyObject *intobj; + PyObject *strobj; + CH_TYPE* src; + Py_ssize_t len; + int negative = 0; + int ok; + + + intobj = PyIntObject(fieldobj); + if (intobj == NULL) + return 0; + + strobj = STROBJ_STR(intobj); + Py_DECREF(intobj); + + /* see if we're negative. we know src must point to at least one + character, so skip that check */ + src = STROBJ_AS_PTR(strobj); + len = STROBJ_GET_SIZE(strobj); + if (src[0] == '-') { + /* remember that we're negative, and skip the char */ + negative = 1; + src++; + len--; + } + + ok = output_string_chars(fs, src, len, format); + Py_DECREF(strobj); + + return ok; +#endif } -static Py_ssize_t -convert_exponent(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_exponent(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_exponentUC(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_exponentUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_fixed(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_fixed(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_fixedUC(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_fixedUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_general(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_general(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_generalUC(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_generalUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_number(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_number(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_octal(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_octal(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_repr(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_repr(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { int ok; - PyObject *s; - PyObject *r; - Py_ssize_t len; + PyObject *strobj; + PyObject *reprobj; - r = PyObject_Repr(fieldobj); - if (r == NULL) + reprobj = PyObject_Repr(fieldobj); + if (reprobj == NULL) return 0; - s = STROBJ_STR(r); - Py_DECREF(r); + strobj = STROBJ_STR(reprobj); + Py_DECREF(reprobj); - len = STROBJ_GET_SIZE(s); - ok = output_data(fs, STROBJ_AS_PTR(s), len); - Py_DECREF(s); + ok = output_string_chars(fs, STROBJ_AS_PTR(strobj), STROBJ_GET_SIZE(strobj), format); + Py_DECREF(strobj); - return ok ? len : -1; + return ok; } -static Py_ssize_t -convert_string(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_string(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - PyObject *myobj; - Py_ssize_t ok; - Py_ssize_t len; - CH_TYPE *dst; + PyObject *strobj; + int ok; - myobj = STROBJ_STR(fieldobj); - if (myobj == NULL) - return -1; + strobj = STROBJ_STR(fieldobj); + if (strobj == NULL) + return 0; - len = STROBJ_GET_SIZE(myobj); + ok = output_string_chars(fs, STROBJ_AS_PTR(strobj), STROBJ_GET_SIZE(strobj), format); + Py_DECREF(strobj); - /* reserve all the space we'll need */ - ok = output_allocate(fs, len, &dst); - if (ok) { - memcpy(dst, STROBJ_AS_PTR(myobj), len * sizeof(CH_TYPE)); - } - Py_DECREF(myobj); - - return ok ? len : -1; + return ok; } -static Py_ssize_t -convert_hex(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_hex(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_hexUC(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_hexUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } -static Py_ssize_t -convert_percentage(PyObject *fieldobj, FmtState *fs, const DefaultFormat *format) +static int +convert_percentage(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return -1; + return convert_DUMMY(fieldobj, fs); } /* returns a pointer to our conversion function, or NULL if invalid */ @@ -900,46 +1013,16 @@ return NULL; } } -#endif /* internal_render -- "Then a miracle occurs" */ static int internal_render(FmtState *fs, PyObject *fieldobj) { -#if DUMMY_FORMATTING == 1 - PyObject *myobj; - int ok; - - /* Test implementation, only at top level */ - CH_TYPE under = '_'; - - myobj = STROBJ_STR(fieldobj); - if (myobj == NULL) - return 0; - ok = output_data(fs, STROBJ_AS_PTR(myobj), - STROBJ_GET_SIZE(myobj)); - Py_DECREF(myobj); - if (!ok) - return 0; - if (fs->fieldspec.ptr != fs->fieldspec.end) { - if (!output_data(fs, &under, 1)) - return 0; - if (!output_data(fs, fs->fieldspec.ptr, - fs->fieldspec.end - fs->fieldspec.ptr)) - return 0; - } -#else - - Py_ssize_t len; - Py_ssize_t padding; - DefaultFormat format; + InternalFormatSpec format; ConversionFunction conversion; - CH_TYPE sign = '\0'; - CH_TYPE prefix; - CH_TYPE suffix; - if (!parse_internal_render(fs, &format)) { + if (!parse_internal_render_format_spec(fs, &format)) { return 0; } @@ -955,8 +1038,9 @@ } } - /* handle conversion functions that logically map to - other conversion functions? */ + /* XXX handle conversion functions that logically map to + other conversion functions? percent is the only one, and I'm not wild + about having percent at all*/ conversion = conversion_function(format.type); if (conversion == NULL) { @@ -964,14 +1048,10 @@ return 0; } - /* convert to a string first */ - /* get the length written so that we can fixup - inside the buffer, as needed */ - len = conversion(fieldobj, fs, &format); - if (len < 0) - return 0; + /* do the conversion, writing into the output string */ + return conversion(fieldobj, fs, &format); - /* we wrote "len" bytes. see what fixups need to be done */ +#if 0 /* Handle the sign logic */ prefix = '\0'; @@ -1008,8 +1088,8 @@ } } -#endif return 1; +#endif } /* From python-checkins at python.org Fri Mar 2 15:37:15 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 2 Mar 2007 15:37:15 +0100 (CET) Subject: [Python-checkins] r54080 - python/trunk/Lib/pydoc.py Message-ID: <20070302143715.B6DC61E4005@bag.python.org> Author: georg.brandl Date: Fri Mar 2 15:37:12 2007 New Revision: 54080 Modified: python/trunk/Lib/pydoc.py Log: Bug #1628895: some better tries to find HTML documentation in pydoc. Modified: python/trunk/Lib/pydoc.py ============================================================================== --- python/trunk/Lib/pydoc.py (original) +++ python/trunk/Lib/pydoc.py Fri Mar 2 15:37:12 2007 @@ -1627,16 +1627,21 @@ self.docdir = None execdir = os.path.dirname(sys.executable) homedir = os.environ.get('PYTHONHOME') + join = os.path.join for dir in [os.environ.get('PYTHONDOCS'), homedir and os.path.join(homedir, 'doc'), - os.path.join(execdir, 'doc'), - '/usr/doc/python-docs-' + split(sys.version)[0], - '/usr/doc/python-' + split(sys.version)[0], - '/usr/doc/python-docs-' + sys.version[:3], - '/usr/doc/python-' + sys.version[:3], - os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]: - if dir and os.path.isdir(os.path.join(dir, 'lib')): + join(execdir, 'doc'), # for Windows + join(sys.prefix, 'doc/python-docs-' + split(sys.version)[0]), + join(sys.prefix, 'doc/python-' + split(sys.version)[0]), + join(sys.prefix, 'doc/python-docs-' + sys.version[:3]), + join(sys.prefix, 'doc/python-' + sys.version[:3]), + join(sys.prefix, 'Resources/English.lproj/Documentation')]: + if dir and os.path.isdir(join(dir, 'lib')): self.docdir = dir + break + if dir and os.path.isdir(join(dir, 'html', 'lib')): + self.docdir = join(dir, 'html') + break def __repr__(self): if inspect.stack()[1][3] == '?': From buildbot at python.org Fri Mar 2 15:44:57 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 02 Mar 2007 14:44:57 +0000 Subject: [Python-checkins] buildbot failure in x86 XP trunk Message-ID: <20070302144457.52B3D1E4005@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/231 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: andrew.kuchling,georg.brandl,neal.norwitz BUILD FAILED: failed failed slave lost sincerely, -The Buildbot From buildbot at python.org Fri Mar 2 16:01:53 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 02 Mar 2007 15:01:53 +0000 Subject: [Python-checkins] buildbot warnings in amd64 gentoo trunk Message-ID: <20070302150153.C767F1E4005@bag.python.org> The Buildbot has detected a new failure of amd64 gentoo trunk. Full details are available at: http://www.python.org/dev/buildbot/all/amd64%2520gentoo%2520trunk/builds/1878 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: andrew.kuchling,georg.brandl,neal.norwitz Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_ctypes ====================================================================== ERROR: test_gl (ctypes.test.test_find.Test_OpenGL_libs) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/buildslave/buildslave/python/trunk.norwitz-amd64/build/Lib/ctypes/test/test_find.py", line 38, in setUp self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) File "/home/buildslave/buildslave/python/trunk.norwitz-amd64/build/Lib/ctypes/__init__.py", line 340, in __init__ self._handle = _dlopen(self._name, mode) OSError: libGL.so.1: cannot open shared object file: No such file or directory ====================================================================== ERROR: test_glu (ctypes.test.test_find.Test_OpenGL_libs) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/buildslave/buildslave/python/trunk.norwitz-amd64/build/Lib/ctypes/test/test_find.py", line 38, in setUp self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) File "/home/buildslave/buildslave/python/trunk.norwitz-amd64/build/Lib/ctypes/__init__.py", line 340, in __init__ self._handle = _dlopen(self._name, mode) OSError: libGL.so.1: cannot open shared object file: No such file or directory ====================================================================== ERROR: test_glut (ctypes.test.test_find.Test_OpenGL_libs) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/buildslave/buildslave/python/trunk.norwitz-amd64/build/Lib/ctypes/test/test_find.py", line 38, in setUp self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) File "/home/buildslave/buildslave/python/trunk.norwitz-amd64/build/Lib/ctypes/__init__.py", line 340, in __init__ self._handle = _dlopen(self._name, mode) OSError: libGL.so.1: cannot open shared object file: No such file or directory make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Fri Mar 2 20:19:06 2007 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 2 Mar 2007 20:19:06 +0100 (CET) Subject: [Python-checkins] r54085 - in python/branches/release25-maint: Lib/test/test_peepholer.py Misc/NEWS Python/compile.c Message-ID: <20070302191906.BC7351E4005@bag.python.org> Author: raymond.hettinger Date: Fri Mar 2 20:19:05 2007 New Revision: 54085 Modified: python/branches/release25-maint/Lib/test/test_peepholer.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Python/compile.c Log: Fix constantification of None. Modified: python/branches/release25-maint/Lib/test/test_peepholer.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_peepholer.py (original) +++ python/branches/release25-maint/Lib/test/test_peepholer.py Fri Mar 2 20:19:05 2007 @@ -49,6 +49,11 @@ self.assert_(elem not in asm) for elem in ('LOAD_CONST', '(None)'): self.assert_(elem in asm) + def f(): + 'Adding a docstring made this test fail in Py2.5.0' + return None + self.assert_('LOAD_CONST' in disassemble(f)) + self.assert_('LOAD_GLOBAL' not in disassemble(f)) def test_while_one(self): # Skip over: LOAD_CONST trueconst JUMP_IF_FALSE xx POP_TOP Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Fri Mar 2 20:19:05 2007 @@ -15,6 +15,9 @@ - Bug #1669182: prevent crash when trying to print an unraisable error from a string exception. +- The peephole optimizer left None as a global in functions with a docstring + and an explicit return value. + - Bug #1653736: Properly discard third argument to slot_nb_inplace_power. - SF #151204: enumerate() now raises an Overflow error at sys.maxint items. Modified: python/branches/release25-maint/Python/compile.c ============================================================================== --- python/branches/release25-maint/Python/compile.c (original) +++ python/branches/release25-maint/Python/compile.c Fri Mar 2 20:19:05 2007 @@ -773,13 +773,17 @@ if (name == NULL || strcmp(name, "None") != 0) continue; for (j=0 ; j < PyList_GET_SIZE(consts) ; j++) { - if (PyList_GET_ITEM(consts, j) == Py_None) { - codestr[i] = LOAD_CONST; - SETARG(codestr, i, j); - cumlc = lastlc + 1; + if (PyList_GET_ITEM(consts, j) == Py_None) break; - } } + if (j == PyList_GET_SIZE(consts)) { + if (PyList_Append(consts, Py_None) == -1) + goto exitUnchanged; + } + assert(PyList_GET_ITEM(consts, j) == Py_None); + codestr[i] = LOAD_CONST; + SETARG(codestr, i, j); + cumlc = lastlc + 1; break; /* Skip over LOAD_CONST trueconst From python-checkins at python.org Fri Mar 2 20:20:47 2007 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 2 Mar 2007 20:20:47 +0100 (CET) Subject: [Python-checkins] r54086 - in python/trunk: Lib/test/test_peepholer.py Python/peephole.c Message-ID: <20070302192047.611C71E4005@bag.python.org> Author: raymond.hettinger Date: Fri Mar 2 20:20:46 2007 New Revision: 54086 Modified: python/trunk/Lib/test/test_peepholer.py python/trunk/Python/peephole.c Log: Fix embarrassing typo and fix constantification of None Modified: python/trunk/Lib/test/test_peepholer.py ============================================================================== --- python/trunk/Lib/test/test_peepholer.py (original) +++ python/trunk/Lib/test/test_peepholer.py Fri Mar 2 20:20:46 2007 @@ -49,6 +49,11 @@ self.assert_(elem not in asm) for elem in ('LOAD_CONST', '(None)'): self.assert_(elem in asm) + def f(): + 'Adding a docstring made this test fail in Py2.5.0' + return None + self.assert_('LOAD_CONST' in disassemble(f)) + self.assert_('LOAD_GLOBAL' not in disassemble(f)) def test_while_one(self): # Skip over: LOAD_CONST trueconst JUMP_IF_FALSE xx POP_TOP Modified: python/trunk/Python/peephole.c ============================================================================== --- python/trunk/Python/peephole.c (original) +++ python/trunk/Python/peephole.c Fri Mar 2 20:20:46 2007 @@ -1,4 +1,4 @@ -/* Peehole optimizations for bytecode compiler. */ +/* Peephole optimizations for bytecode compiler. */ #include "Python.h" @@ -386,13 +386,17 @@ if (name == NULL || strcmp(name, "None") != 0) continue; for (j=0 ; j < PyList_GET_SIZE(consts) ; j++) { - if (PyList_GET_ITEM(consts, j) == Py_None) { - codestr[i] = LOAD_CONST; - SETARG(codestr, i, j); - cumlc = lastlc + 1; + if (PyList_GET_ITEM(consts, j) == Py_None) break; - } } + if (j == PyList_GET_SIZE(consts)) { + if (PyList_Append(consts, Py_None) == -1) + goto exitUnchanged; + } + assert(PyList_GET_ITEM(consts, j) == Py_None); + codestr[i] = LOAD_CONST; + SETARG(codestr, i, j); + cumlc = lastlc + 1; break; /* Skip over LOAD_CONST trueconst From buildbot at python.org Fri Mar 2 20:43:17 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 02 Mar 2007 19:43:17 +0000 Subject: [Python-checkins] buildbot warnings in amd64 gentoo 2.5 Message-ID: <20070302194318.057DD1E4005@bag.python.org> The Buildbot has detected a new failure of amd64 gentoo 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/amd64%2520gentoo%25202.5/builds/249 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: andrew.kuchling,raymond.hettinger Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_ctypes ====================================================================== ERROR: test_gl (ctypes.test.test_find.Test_OpenGL_libs) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/buildslave/buildslave/python/2.5.norwitz-amd64/build/Lib/ctypes/test/test_find.py", line 38, in setUp self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) File "/home/buildslave/buildslave/python/2.5.norwitz-amd64/build/Lib/ctypes/__init__.py", line 340, in __init__ self._handle = _dlopen(self._name, mode) OSError: libGL.so.1: cannot open shared object file: No such file or directory ====================================================================== ERROR: test_glu (ctypes.test.test_find.Test_OpenGL_libs) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/buildslave/buildslave/python/2.5.norwitz-amd64/build/Lib/ctypes/test/test_find.py", line 38, in setUp self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) File "/home/buildslave/buildslave/python/2.5.norwitz-amd64/build/Lib/ctypes/__init__.py", line 340, in __init__ self._handle = _dlopen(self._name, mode) OSError: libGL.so.1: cannot open shared object file: No such file or directory ====================================================================== ERROR: test_glut (ctypes.test.test_find.Test_OpenGL_libs) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/buildslave/buildslave/python/2.5.norwitz-amd64/build/Lib/ctypes/test/test_find.py", line 38, in setUp self.gl = CDLL(lib_gl, mode=RTLD_GLOBAL) File "/home/buildslave/buildslave/python/2.5.norwitz-amd64/build/Lib/ctypes/__init__.py", line 340, in __init__ self._handle = _dlopen(self._name, mode) OSError: libGL.so.1: cannot open shared object file: No such file or directory make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Fri Mar 2 21:15:25 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 02 Mar 2007 20:15:25 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 2.5 Message-ID: <20070302201526.67C121E400D@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%25202.5/builds/181 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: andrew.kuchling,raymond.hettinger Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket ====================================================================== FAIL: testInterruptedTimeout (test.test_socket.TCPTimeoutTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/net/ringneck/scratch1/nnorwitz/python/2.5.norwitz-tru64/build/Lib/test/test_socket.py", line 872, in testInterruptedTimeout self.fail("got Alarm in wrong place") AssertionError: got Alarm in wrong place sincerely, -The Buildbot From python-checkins at python.org Fri Mar 2 21:29:30 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 2 Mar 2007 21:29:30 +0100 (CET) Subject: [Python-checkins] r54087 - sandbox/trunk/2to3/tests/test_grammar.py Message-ID: <20070302202930.E282B1E4005@bag.python.org> Author: collin.winter Date: Fri Mar 2 21:29:28 2007 New Revision: 54087 Added: sandbox/trunk/2to3/tests/test_grammar.py (contents, props changed) Log: Add a test suite for grammar changes. Added: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/tests/test_grammar.py Fri Mar 2 21:29:28 2007 @@ -0,0 +1,100 @@ +#!/usr/bin/env python2.5 +""" Test suite for Grammar.txt. This is the place to add tests for +changes to 2to3's grammar, such as those merging the grammars for +Python 2 and 3. """ +# Author: Collin Winter + +# Testing imports +import support +if __name__ == '__main__': + support.adjust_path() + +# Python imports +import os.path + +# Local imports +import pytree +from pgen2 import driver +from pgen2.parse import ParseError + + +grammar_path = os.path.join(os.path.dirname(__file__), "..", "Grammar.txt") +grammar = driver.load_grammar(grammar_path) +driver = driver.Driver(grammar, convert=pytree.convert) + +class GrammarTest(support.TestCase): + def validate(self, code): + driver.parse_string(support.reformat(code), debug=True) + + def invalid_syntax(self, code): + try: + self.validate(code) + except ParseError: + pass + + +# Adapated from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef +class TestFunctionAnnotations(GrammarTest): + def test_1(self): + self.validate("""def f(x) -> list: pass""") + + def test_2(self): + self.validate("""def f(x:int): pass""") + + def test_3(self): + self.validate("""def f(*x:str): pass""") + + def test_4(self): + self.validate("""def f(**x:float): pass""") + + def test_5(self): + self.validate("""def f(x, y:1+2): pass""") + + def test_6(self): + self.validate("""def f(a, (b:1, c:2, d)): pass""") + + def test_7(self): + self.validate("""def f(a, (b:1, c:2, d), e:3=4, f=5, *g:6): pass""") + + def test_8(self): + s = """def f(a, (b:1, c:2, d), e:3=4, f=5, + *g:6, h:7, i=8, j:9=10, **k:11) -> 12: pass""" + self.validate(s) + + +class TestExcept(GrammarTest): + def test_new(self): + s = """ + try: + x + except E as N: + y""" + self.validate(s) + + def test_old(self): + s = """ + try: + x + except E, N: + y""" + self.validate(s) + + +# Adapted from Python 3's Lib/test/test_grammar.py:GrammarTests.testAtoms +class TestSetLiteral(GrammarTest): + def test_1(self): + self.validate("""x = {'one'}""") + + def test_2(self): + self.validate("""x = {'one', 1,}""") + + def test_3(self): + self.validate("""x = {'one', 'two', 'three'}""") + + def test_4(self): + self.validate("""x = {2, 3, 4,}""") + + +if __name__ == "__main__": + import __main__ + support.run_all_tests(__main__) From python-checkins at python.org Fri Mar 2 21:30:15 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 2 Mar 2007 21:30:15 +0100 (CET) Subject: [Python-checkins] r54088 - python/trunk/Doc/api/memory.tex Message-ID: <20070302203015.843851E400C@bag.python.org> Author: georg.brandl Date: Fri Mar 2 21:30:14 2007 New Revision: 54088 Modified: python/trunk/Doc/api/memory.tex Log: Bugs #1668032, #1668036, #1669304: clarify behavior of PyMem_Realloc and _Resize. Modified: python/trunk/Doc/api/memory.tex ============================================================================== --- python/trunk/Doc/api/memory.tex (original) +++ python/trunk/Doc/api/memory.tex Fri Mar 2 21:30:14 2007 @@ -100,7 +100,9 @@ memory block is resized but is not freed, and the returned pointer is non-\NULL. Unless \var{p} is \NULL, it must have been returned by a previous call to \cfunction{PyMem_Malloc()} or - \cfunction{PyMem_Realloc()}. + \cfunction{PyMem_Realloc()}. If the request fails, + \cfunction{PyMem_Realloc()} returns \NULL{} and \var{p} remains a + valid pointer to the previous memory area. \end{cfuncdesc} \begin{cfuncdesc}{void}{PyMem_Free}{void *p} @@ -124,7 +126,8 @@ \begin{cfuncdesc}{\var{TYPE}*}{PyMem_Resize}{void *p, TYPE, size_t n} Same as \cfunction{PyMem_Realloc()}, but the memory block is resized to \code{(\var{n} * sizeof(\var{TYPE}))} bytes. Returns a pointer - cast to \ctype{\var{TYPE}*}. + cast to \ctype{\var{TYPE}*}. On return, \var{p} will be a pointer to + the new memory area, or \NULL{} in the event of failure. \end{cfuncdesc} \begin{cfuncdesc}{void}{PyMem_Del}{void *p} From python-checkins at python.org Fri Mar 2 21:30:19 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 2 Mar 2007 21:30:19 +0100 (CET) Subject: [Python-checkins] r54089 - python/branches/release25-maint/Doc/api/memory.tex Message-ID: <20070302203019.C497E1E4014@bag.python.org> Author: georg.brandl Date: Fri Mar 2 21:30:19 2007 New Revision: 54089 Modified: python/branches/release25-maint/Doc/api/memory.tex Log: Bugs #1668032, #1668036, #1669304: clarify behavior of PyMem_Realloc and _Resize. (backport from rev. 54088) Modified: python/branches/release25-maint/Doc/api/memory.tex ============================================================================== --- python/branches/release25-maint/Doc/api/memory.tex (original) +++ python/branches/release25-maint/Doc/api/memory.tex Fri Mar 2 21:30:19 2007 @@ -100,7 +100,9 @@ memory block is resized but is not freed, and the returned pointer is non-\NULL. Unless \var{p} is \NULL, it must have been returned by a previous call to \cfunction{PyMem_Malloc()} or - \cfunction{PyMem_Realloc()}. + \cfunction{PyMem_Realloc()}. If the request fails, + \cfunction{PyMem_Realloc()} returns \NULL{} and \var{p} remains a + valid pointer to the previous memory area. \end{cfuncdesc} \begin{cfuncdesc}{void}{PyMem_Free}{void *p} @@ -124,7 +126,8 @@ \begin{cfuncdesc}{\var{TYPE}*}{PyMem_Resize}{void *p, TYPE, size_t n} Same as \cfunction{PyMem_Realloc()}, but the memory block is resized to \code{(\var{n} * sizeof(\var{TYPE}))} bytes. Returns a pointer - cast to \ctype{\var{TYPE}*}. + cast to \ctype{\var{TYPE}*}. On return, \var{p} will be a pointer to + the new memory area, or \NULL{} in the event of failure. \end{cfuncdesc} \begin{cfuncdesc}{void}{PyMem_Del}{void *p} From python-checkins at python.org Fri Mar 2 21:33:02 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 2 Mar 2007 21:33:02 +0100 (CET) Subject: [Python-checkins] r54090 - in sandbox/trunk/2to3: Grammar.txt tests/test_grammar.py Message-ID: <20070302203302.E46D21E4011@bag.python.org> Author: collin.winter Date: Fri Mar 2 21:33:02 2007 New Revision: 54090 Modified: sandbox/trunk/2to3/Grammar.txt sandbox/trunk/2to3/tests/test_grammar.py Log: Add support for parsing Py3k's 'raise ... from ...' statement. Modified: sandbox/trunk/2to3/Grammar.txt ============================================================================== --- sandbox/trunk/2to3/Grammar.txt (original) +++ sandbox/trunk/2to3/Grammar.txt Fri Mar 2 21:33:02 2007 @@ -66,7 +66,7 @@ continue_stmt: 'continue' return_stmt: 'return' [testlist] yield_stmt: yield_expr -raise_stmt: 'raise' [test [',' test [',' test]]] +raise_stmt: 'raise' [test ['from' test | ',' test [',' test]]] import_stmt: import_name | import_from import_name: 'import' dotted_as_names import_from: ('from' ('.'* dotted_name | '.'+) Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Fri Mar 2 21:33:02 2007 @@ -33,6 +33,35 @@ pass +class TestRaiseChanges(GrammarTest): + def test_2x_style_1(self): + self.validate("raise") + + def test_2x_style_2(self): + self.validate("raise E, V") + + def test_2x_style_3(self): + self.validate("raise E, V, T") + + def test_2x_style_invalid_1(self): + self.invalid_syntax("raise E, V, T, Z") + + def test_3x_style(self): + self.validate("raise E1 from E2") + + def test_3x_style_invalid_1(self): + self.invalid_syntax("raise E, V from E1") + + def test_3x_style_invalid_2(self): + self.invalid_syntax("raise E from E1, E2") + + def test_3x_style_invalid_3(self): + self.invalid_syntax("raise from E1, E2") + + def test_3x_style_invalid_4(self): + self.invalid_syntax("raise E from") + + # Adapated from Python 3's Lib/test/test_grammar.py:GrammarTests.testFuncdef class TestFunctionAnnotations(GrammarTest): def test_1(self): From python-checkins at python.org Fri Mar 2 21:43:50 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 2 Mar 2007 21:43:50 +0100 (CET) Subject: [Python-checkins] r54091 - in sandbox/trunk/2to3/tests: data data/py2_test_grammar.py data/py3_test_grammar.py test_grammar.py Message-ID: <20070302204350.BB3DE1E4005@bag.python.org> Author: collin.winter Date: Fri Mar 2 21:43:48 2007 New Revision: 54091 Added: sandbox/trunk/2to3/tests/data/ sandbox/trunk/2to3/tests/data/py2_test_grammar.py (contents, props changed) sandbox/trunk/2to3/tests/data/py3_test_grammar.py (contents, props changed) Modified: sandbox/trunk/2to3/tests/test_grammar.py Log: Add two tests that try to parse the Lib/test/test_grammar.py files from Python 2.5 and Python 3.0. Added: sandbox/trunk/2to3/tests/data/py2_test_grammar.py ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/tests/data/py2_test_grammar.py Fri Mar 2 21:43:48 2007 @@ -0,0 +1,922 @@ +# Python 2's Lib/test/test_grammar.py (r54061) + +# Python test set -- part 1, grammar. +# This just tests whether the parser accepts them all. + +# NOTE: When you run this test as a script from the command line, you +# get warnings about certain hex/oct constants. Since those are +# issued by the parser, you can't suppress them by adding a +# filterwarnings() call to this module. Therefore, to shut up the +# regression test, the filterwarnings() call has been added to +# regrtest.py. + +from test.test_support import run_unittest, check_syntax_error +import unittest +import sys +# testing import * +from sys import * + +class TokenTests(unittest.TestCase): + + def testBackslash(self): + # Backslash means line continuation: + x = 1 \ + + 1 + self.assertEquals(x, 2, 'backslash for line continuation') + + # Backslash does not means continuation in comments :\ + x = 0 + self.assertEquals(x, 0, 'backslash ending comment') + + def testPlainIntegers(self): + self.assertEquals(0xff, 255) + self.assertEquals(0377, 255) + self.assertEquals(2147483647, 017777777777) + from sys import maxint + if maxint == 2147483647: + self.assertEquals(-2147483647-1, -020000000000) + # XXX -2147483648 + self.assert_(037777777777 > 0) + self.assert_(0xffffffff > 0) + for s in '2147483648', '040000000000', '0x100000000': + try: + x = eval(s) + except OverflowError: + self.fail("OverflowError on huge integer literal %r" % s) + elif maxint == 9223372036854775807: + self.assertEquals(-9223372036854775807-1, -01000000000000000000000) + self.assert_(01777777777777777777777 > 0) + self.assert_(0xffffffffffffffff > 0) + for s in '9223372036854775808', '02000000000000000000000', \ + '0x10000000000000000': + try: + x = eval(s) + except OverflowError: + self.fail("OverflowError on huge integer literal %r" % s) + else: + self.fail('Weird maxint value %r' % maxint) + + def testLongIntegers(self): + x = 0L + x = 0l + x = 0xffffffffffffffffL + x = 0xffffffffffffffffl + x = 077777777777777777L + x = 077777777777777777l + x = 123456789012345678901234567890L + x = 123456789012345678901234567890l + + def testFloats(self): + x = 3.14 + x = 314. + x = 0.314 + # XXX x = 000.314 + x = .314 + x = 3e14 + x = 3E14 + x = 3e-14 + x = 3e+14 + x = 3.e14 + x = .3e14 + x = 3.1e4 + + def testStringLiterals(self): + x = ''; y = ""; self.assert_(len(x) == 0 and x == y) + x = '\''; y = "'"; self.assert_(len(x) == 1 and x == y and ord(x) == 39) + x = '"'; y = "\""; self.assert_(len(x) == 1 and x == y and ord(x) == 34) + x = "doesn't \"shrink\" does it" + y = 'doesn\'t "shrink" does it' + self.assert_(len(x) == 24 and x == y) + x = "does \"shrink\" doesn't it" + y = 'does "shrink" doesn\'t it' + self.assert_(len(x) == 24 and x == y) + x = """ +The "quick" +brown fox +jumps over +the 'lazy' dog. +""" + y = '\nThe "quick"\nbrown fox\njumps over\nthe \'lazy\' dog.\n' + self.assertEquals(x, y) + y = ''' +The "quick" +brown fox +jumps over +the 'lazy' dog. +''' + self.assertEquals(x, y) + y = "\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the 'lazy' dog.\n\ +" + self.assertEquals(x, y) + y = '\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the \'lazy\' dog.\n\ +' + self.assertEquals(x, y) + + +class GrammarTests(unittest.TestCase): + + # single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE + # XXX can't test in a script -- this rule is only used when interactive + + # file_input: (NEWLINE | stmt)* ENDMARKER + # Being tested as this very moment this very module + + # expr_input: testlist NEWLINE + # XXX Hard to test -- used only in calls to input() + + def testEvalInput(self): + # testlist ENDMARKER + x = eval('1, 0 or 1') + + def testFuncdef(self): + ### 'def' NAME parameters ':' suite + ### parameters: '(' [varargslist] ')' + ### varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' ('**'|'*' '*') NAME] + ### | ('**'|'*' '*') NAME) + ### | fpdef ['=' test] (',' fpdef ['=' test])* [','] + ### fpdef: NAME | '(' fplist ')' + ### fplist: fpdef (',' fpdef)* [','] + ### arglist: (argument ',')* (argument | *' test [',' '**' test] | '**' test) + ### argument: [test '='] test # Really [keyword '='] test + def f1(): pass + f1() + f1(*()) + f1(*(), **{}) + def f2(one_argument): pass + def f3(two, arguments): pass + def f4(two, (compound, (argument, list))): pass + def f5((compound, first), two): pass + self.assertEquals(f2.func_code.co_varnames, ('one_argument',)) + self.assertEquals(f3.func_code.co_varnames, ('two', 'arguments')) + if sys.platform.startswith('java'): + self.assertEquals(f4.func_code.co_varnames, + ('two', '(compound, (argument, list))', 'compound', 'argument', + 'list',)) + self.assertEquals(f5.func_code.co_varnames, + ('(compound, first)', 'two', 'compound', 'first')) + else: + self.assertEquals(f4.func_code.co_varnames, + ('two', '.1', 'compound', 'argument', 'list')) + self.assertEquals(f5.func_code.co_varnames, + ('.0', 'two', 'compound', 'first')) + def a1(one_arg,): pass + def a2(two, args,): pass + def v0(*rest): pass + def v1(a, *rest): pass + def v2(a, b, *rest): pass + def v3(a, (b, c), *rest): return a, b, c, rest + + f1() + f2(1) + f2(1,) + f3(1, 2) + f3(1, 2,) + f4(1, (2, (3, 4))) + v0() + v0(1) + v0(1,) + v0(1,2) + v0(1,2,3,4,5,6,7,8,9,0) + v1(1) + v1(1,) + v1(1,2) + v1(1,2,3) + v1(1,2,3,4,5,6,7,8,9,0) + v2(1,2) + v2(1,2,3) + v2(1,2,3,4) + v2(1,2,3,4,5,6,7,8,9,0) + v3(1,(2,3)) + v3(1,(2,3),4) + v3(1,(2,3),4,5,6,7,8,9,0) + + # ceval unpacks the formal arguments into the first argcount names; + # thus, the names nested inside tuples must appear after these names. + if sys.platform.startswith('java'): + self.assertEquals(v3.func_code.co_varnames, ('a', '(b, c)', 'rest', 'b', 'c')) + else: + self.assertEquals(v3.func_code.co_varnames, ('a', '.1', 'rest', 'b', 'c')) + self.assertEquals(v3(1, (2, 3), 4), (1, 2, 3, (4,))) + def d01(a=1): pass + d01() + d01(1) + d01(*(1,)) + d01(**{'a':2}) + def d11(a, b=1): pass + d11(1) + d11(1, 2) + d11(1, **{'b':2}) + def d21(a, b, c=1): pass + d21(1, 2) + d21(1, 2, 3) + d21(*(1, 2, 3)) + d21(1, *(2, 3)) + d21(1, 2, *(3,)) + d21(1, 2, **{'c':3}) + def d02(a=1, b=2): pass + d02() + d02(1) + d02(1, 2) + d02(*(1, 2)) + d02(1, *(2,)) + d02(1, **{'b':2}) + d02(**{'a': 1, 'b': 2}) + def d12(a, b=1, c=2): pass + d12(1) + d12(1, 2) + d12(1, 2, 3) + def d22(a, b, c=1, d=2): pass + d22(1, 2) + d22(1, 2, 3) + d22(1, 2, 3, 4) + def d01v(a=1, *rest): pass + d01v() + d01v(1) + d01v(1, 2) + d01v(*(1, 2, 3, 4)) + d01v(*(1,)) + d01v(**{'a':2}) + def d11v(a, b=1, *rest): pass + d11v(1) + d11v(1, 2) + d11v(1, 2, 3) + def d21v(a, b, c=1, *rest): pass + d21v(1, 2) + d21v(1, 2, 3) + d21v(1, 2, 3, 4) + d21v(*(1, 2, 3, 4)) + d21v(1, 2, **{'c': 3}) + def d02v(a=1, b=2, *rest): pass + d02v() + d02v(1) + d02v(1, 2) + d02v(1, 2, 3) + d02v(1, *(2, 3, 4)) + d02v(**{'a': 1, 'b': 2}) + def d12v(a, b=1, c=2, *rest): pass + d12v(1) + d12v(1, 2) + d12v(1, 2, 3) + d12v(1, 2, 3, 4) + d12v(*(1, 2, 3, 4)) + d12v(1, 2, *(3, 4, 5)) + d12v(1, *(2,), **{'c': 3}) + def d22v(a, b, c=1, d=2, *rest): pass + d22v(1, 2) + d22v(1, 2, 3) + d22v(1, 2, 3, 4) + d22v(1, 2, 3, 4, 5) + d22v(*(1, 2, 3, 4)) + d22v(1, 2, *(3, 4, 5)) + d22v(1, *(2, 3), **{'d': 4}) + def d31v((x)): pass + d31v(1) + def d32v((x,)): pass + d32v((1,)) + + def testLambdef(self): + ### lambdef: 'lambda' [varargslist] ':' test + l1 = lambda : 0 + self.assertEquals(l1(), 0) + l2 = lambda : a[d] # XXX just testing the expression + l3 = lambda : [2 < x for x in [-1, 3, 0L]] + self.assertEquals(l3(), [0, 1, 0]) + l4 = lambda x = lambda y = lambda z=1 : z : y() : x() + self.assertEquals(l4(), 1) + l5 = lambda x, y, z=2: x + y + z + self.assertEquals(l5(1, 2), 5) + self.assertEquals(l5(1, 2, 3), 6) + check_syntax_error(self, "lambda x: x = 2") + + ### stmt: simple_stmt | compound_stmt + # Tested below + + def testSimpleStmt(self): + ### simple_stmt: small_stmt (';' small_stmt)* [';'] + x = 1; pass; del x + def foo(): + # verify statments that end with semi-colons + x = 1; pass; del x; + foo() + + ### small_stmt: expr_stmt | print_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt | global_stmt | access_stmt | exec_stmt + # Tested below + + def testExprStmt(self): + # (exprlist '=')* exprlist + 1 + 1, 2, 3 + x = 1 + x = 1, 2, 3 + x = y = z = 1, 2, 3 + x, y, z = 1, 2, 3 + abc = a, b, c = x, y, z = xyz = 1, 2, (3, 4) + + check_syntax_error(self, "x + 1 = 1") + check_syntax_error(self, "a + 1 = b + 2") + + def testPrintStmt(self): + # 'print' (test ',')* [test] + import StringIO + + # Can't test printing to real stdout without comparing output + # which is not available in unittest. + save_stdout = sys.stdout + sys.stdout = StringIO.StringIO() + + print 1, 2, 3 + print 1, 2, 3, + print + print 0 or 1, 0 or 1, + print 0 or 1 + + # 'print' '>>' test ',' + print >> sys.stdout, 1, 2, 3 + print >> sys.stdout, 1, 2, 3, + print >> sys.stdout + print >> sys.stdout, 0 or 1, 0 or 1, + print >> sys.stdout, 0 or 1 + + # test printing to an instance + class Gulp: + def write(self, msg): pass + + gulp = Gulp() + print >> gulp, 1, 2, 3 + print >> gulp, 1, 2, 3, + print >> gulp + print >> gulp, 0 or 1, 0 or 1, + print >> gulp, 0 or 1 + + # test print >> None + def driver(): + oldstdout = sys.stdout + sys.stdout = Gulp() + try: + tellme(Gulp()) + tellme() + finally: + sys.stdout = oldstdout + + # we should see this once + def tellme(file=sys.stdout): + print >> file, 'hello world' + + driver() + + # we should not see this at all + def tellme(file=None): + print >> file, 'goodbye universe' + + driver() + + self.assertEqual(sys.stdout.getvalue(), '''\ +1 2 3 +1 2 3 +1 1 1 +1 2 3 +1 2 3 +1 1 1 +hello world +''') + sys.stdout = save_stdout + + # syntax errors + check_syntax_error(self, 'print ,') + check_syntax_error(self, 'print >> x,') + + def testDelStmt(self): + # 'del' exprlist + abc = [1,2,3] + x, y, z = abc + xyz = x, y, z + + del abc + del x, y, (z, xyz) + + def testPassStmt(self): + # 'pass' + pass + + # flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt + # Tested below + + def testBreakStmt(self): + # 'break' + while 1: break + + def testContinueStmt(self): + # 'continue' + i = 1 + while i: i = 0; continue + + msg = "" + while not msg: + msg = "ok" + try: + continue + msg = "continue failed to continue inside try" + except: + msg = "continue inside try called except block" + if msg != "ok": + self.fail(msg) + + msg = "" + while not msg: + msg = "finally block not called" + try: + continue + finally: + msg = "ok" + if msg != "ok": + self.fail(msg) + + def test_break_continue_loop(self): + # This test warrants an explanation. It is a test specifically for SF bugs + # #463359 and #462937. The bug is that a 'break' statement executed or + # exception raised inside a try/except inside a loop, *after* a continue + # statement has been executed in that loop, will cause the wrong number of + # arguments to be popped off the stack and the instruction pointer reset to + # a very small number (usually 0.) Because of this, the following test + # *must* written as a function, and the tracking vars *must* be function + # arguments with default values. Otherwise, the test will loop and loop. + + def test_inner(extra_burning_oil = 1, count=0): + big_hippo = 2 + while big_hippo: + count += 1 + try: + if extra_burning_oil and big_hippo == 1: + extra_burning_oil -= 1 + break + big_hippo -= 1 + continue + except: + raise + if count > 2 or big_hippo <> 1: + self.fail("continue then break in try/except in loop broken!") + test_inner() + + def testReturn(self): + # 'return' [testlist] + def g1(): return + def g2(): return 1 + g1() + x = g2() + check_syntax_error(self, "class foo:return 1") + + def testYield(self): + check_syntax_error(self, "class foo:yield 1") + + def testRaise(self): + # 'raise' test [',' test] + try: raise RuntimeError, 'just testing' + except RuntimeError: pass + try: raise KeyboardInterrupt + except KeyboardInterrupt: pass + + def testImport(self): + # 'import' dotted_as_names + import sys + import time, sys + # 'from' dotted_name 'import' ('*' | '(' import_as_names ')' | import_as_names) + from time import time + from time import (time) + # not testable inside a function, but already done at top of the module + # from sys import * + from sys import path, argv + from sys import (path, argv) + from sys import (path, argv,) + + def testGlobal(self): + # 'global' NAME (',' NAME)* + global a + global a, b + global one, two, three, four, five, six, seven, eight, nine, ten + + def testExec(self): + # 'exec' expr ['in' expr [',' expr]] + z = None + del z + exec 'z=1+1\n' + if z != 2: self.fail('exec \'z=1+1\'\\n') + del z + exec 'z=1+1' + if z != 2: self.fail('exec \'z=1+1\'') + z = None + del z + import types + if hasattr(types, "UnicodeType"): + exec r"""if 1: + exec u'z=1+1\n' + if z != 2: self.fail('exec u\'z=1+1\'\\n') + del z + exec u'z=1+1' + if z != 2: self.fail('exec u\'z=1+1\'')""" + g = {} + exec 'z = 1' in g + if g.has_key('__builtins__'): del g['__builtins__'] + if g != {'z': 1}: self.fail('exec \'z = 1\' in g') + g = {} + l = {} + + import warnings + warnings.filterwarnings("ignore", "global statement", module="") + exec 'global a; a = 1; b = 2' in g, l + if g.has_key('__builtins__'): del g['__builtins__'] + if l.has_key('__builtins__'): del l['__builtins__'] + if (g, l) != ({'a':1}, {'b':2}): + self.fail('exec ... in g (%s), l (%s)' %(g,l)) + + def testAssert(self): + # assert_stmt: 'assert' test [',' test] + assert 1 + assert 1, 1 + assert lambda x:x + assert 1, lambda x:x+1 + try: + assert 0, "msg" + except AssertionError, e: + self.assertEquals(e.args[0], "msg") + else: + if __debug__: + self.fail("AssertionError not raised by assert 0") + + ### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef + # Tested below + + def testIf(self): + # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] + if 1: pass + if 1: pass + else: pass + if 0: pass + elif 0: pass + if 0: pass + elif 0: pass + elif 0: pass + elif 0: pass + else: pass + + def testWhile(self): + # 'while' test ':' suite ['else' ':' suite] + while 0: pass + while 0: pass + else: pass + + def testFor(self): + # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] + for i in 1, 2, 3: pass + for i, j, k in (): pass + else: pass + class Squares: + def __init__(self, max): + self.max = max + self.sofar = [] + def __len__(self): return len(self.sofar) + def __getitem__(self, i): + if not 0 <= i < self.max: raise IndexError + n = len(self.sofar) + while n <= i: + self.sofar.append(n*n) + n = n+1 + return self.sofar[i] + n = 0 + for x in Squares(10): n = n+x + if n != 285: + self.fail('for over growing sequence') + + result = [] + for x, in [(1,), (2,), (3,)]: + result.append(x) + self.assertEqual(result, [1, 2, 3]) + + def testTry(self): + ### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] + ### | 'try' ':' suite 'finally' ':' suite + ### except_clause: 'except' [expr [',' expr]] + try: + 1/0 + except ZeroDivisionError: + pass + else: + pass + try: 1/0 + except EOFError: pass + except TypeError, msg: pass + except RuntimeError, msg: pass + except: pass + else: pass + try: 1/0 + except (EOFError, TypeError, ZeroDivisionError): pass + try: 1/0 + except (EOFError, TypeError, ZeroDivisionError), msg: pass + try: pass + finally: pass + + def testSuite(self): + # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT + if 1: pass + if 1: + pass + if 1: + # + # + # + pass + pass + # + pass + # + + def testTest(self): + ### and_test ('or' and_test)* + ### and_test: not_test ('and' not_test)* + ### not_test: 'not' not_test | comparison + if not 1: pass + if 1 and 1: pass + if 1 or 1: pass + if not not not 1: pass + if not 1 and 1 and 1: pass + if 1 and 1 or 1 and 1 and 1 or not 1 and 1: pass + + def testComparison(self): + ### comparison: expr (comp_op expr)* + ### comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not' + if 1: pass + x = (1 == 1) + if 1 == 1: pass + if 1 != 1: pass + if 1 <> 1: pass + if 1 < 1: pass + if 1 > 1: pass + if 1 <= 1: pass + if 1 >= 1: pass + if 1 is 1: pass + if 1 is not 1: pass + if 1 in (): pass + if 1 not in (): pass + if 1 < 1 > 1 == 1 >= 1 <= 1 <> 1 != 1 in 1 not in 1 is 1 is not 1: pass + + def testBinaryMaskOps(self): + x = 1 & 1 + x = 1 ^ 1 + x = 1 | 1 + + def testShiftOps(self): + x = 1 << 1 + x = 1 >> 1 + x = 1 << 1 >> 1 + + def testAdditiveOps(self): + x = 1 + x = 1 + 1 + x = 1 - 1 - 1 + x = 1 - 1 + 1 - 1 + 1 + + def testMultiplicativeOps(self): + x = 1 * 1 + x = 1 / 1 + x = 1 % 1 + x = 1 / 1 * 1 % 1 + + def testUnaryOps(self): + x = +1 + x = -1 + x = ~1 + x = ~1 ^ 1 & 1 | 1 & 1 ^ -1 + x = -1*1/1 + 1*1 - ---1*1 + + def testSelectors(self): + ### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME + ### subscript: expr | [expr] ':' [expr] + + import sys, time + c = sys.path[0] + x = time.time() + x = sys.modules['time'].time() + a = '01234' + c = a[0] + c = a[-1] + s = a[0:5] + s = a[:5] + s = a[0:] + s = a[:] + s = a[-5:] + s = a[:-1] + s = a[-4:-3] + # A rough test of SF bug 1333982. http://python.org/sf/1333982 + # The testing here is fairly incomplete. + # Test cases should include: commas with 1 and 2 colons + d = {} + d[1] = 1 + d[1,] = 2 + d[1,2] = 3 + d[1,2,3] = 4 + L = list(d) + L.sort() + self.assertEquals(str(L), '[1, (1,), (1, 2), (1, 2, 3)]') + + def testAtoms(self): + ### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING + ### dictmaker: test ':' test (',' test ':' test)* [','] + + x = (1) + x = (1 or 2 or 3) + x = (1 or 2 or 3, 2, 3) + + x = [] + x = [1] + x = [1 or 2 or 3] + x = [1 or 2 or 3, 2, 3] + x = [] + + x = {} + x = {'one': 1} + x = {'one': 1,} + x = {'one' or 'two': 1 or 2} + x = {'one': 1, 'two': 2} + x = {'one': 1, 'two': 2,} + x = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6} + + x = `x` + x = `1 or 2 or 3` + self.assertEqual(`1,2`, '(1, 2)') + + x = x + x = 'x' + x = 123 + + ### exprlist: expr (',' expr)* [','] + ### testlist: test (',' test)* [','] + # These have been exercised enough above + + def testClassdef(self): + # 'class' NAME ['(' [testlist] ')'] ':' suite + class B: pass + class B2(): pass + class C1(B): pass + class C2(B): pass + class D(C1, C2, B): pass + class C: + def meth1(self): pass + def meth2(self, arg): pass + def meth3(self, a1, a2): pass + + def testListcomps(self): + # list comprehension tests + nums = [1, 2, 3, 4, 5] + strs = ["Apple", "Banana", "Coconut"] + spcs = [" Apple", " Banana ", "Coco nut "] + + self.assertEqual([s.strip() for s in spcs], ['Apple', 'Banana', 'Coco nut']) + self.assertEqual([3 * x for x in nums], [3, 6, 9, 12, 15]) + self.assertEqual([x for x in nums if x > 2], [3, 4, 5]) + self.assertEqual([(i, s) for i in nums for s in strs], + [(1, 'Apple'), (1, 'Banana'), (1, 'Coconut'), + (2, 'Apple'), (2, 'Banana'), (2, 'Coconut'), + (3, 'Apple'), (3, 'Banana'), (3, 'Coconut'), + (4, 'Apple'), (4, 'Banana'), (4, 'Coconut'), + (5, 'Apple'), (5, 'Banana'), (5, 'Coconut')]) + self.assertEqual([(i, s) for i in nums for s in [f for f in strs if "n" in f]], + [(1, 'Banana'), (1, 'Coconut'), (2, 'Banana'), (2, 'Coconut'), + (3, 'Banana'), (3, 'Coconut'), (4, 'Banana'), (4, 'Coconut'), + (5, 'Banana'), (5, 'Coconut')]) + self.assertEqual([(lambda a:[a**i for i in range(a+1)])(j) for j in range(5)], + [[1], [1, 1], [1, 2, 4], [1, 3, 9, 27], [1, 4, 16, 64, 256]]) + + def test_in_func(l): + return [None < x < 3 for x in l if x > 2] + + self.assertEqual(test_in_func(nums), [False, False, False]) + + def test_nested_front(): + self.assertEqual([[y for y in [x, x + 1]] for x in [1,3,5]], + [[1, 2], [3, 4], [5, 6]]) + + test_nested_front() + + check_syntax_error(self, "[i, s for i in nums for s in strs]") + check_syntax_error(self, "[x if y]") + + suppliers = [ + (1, "Boeing"), + (2, "Ford"), + (3, "Macdonalds") + ] + + parts = [ + (10, "Airliner"), + (20, "Engine"), + (30, "Cheeseburger") + ] + + suppart = [ + (1, 10), (1, 20), (2, 20), (3, 30) + ] + + x = [ + (sname, pname) + for (sno, sname) in suppliers + for (pno, pname) in parts + for (sp_sno, sp_pno) in suppart + if sno == sp_sno and pno == sp_pno + ] + + self.assertEqual(x, [('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), + ('Macdonalds', 'Cheeseburger')]) + + def testGenexps(self): + # generator expression tests + g = ([x for x in range(10)] for x in range(1)) + self.assertEqual(g.next(), [x for x in range(10)]) + try: + g.next() + self.fail('should produce StopIteration exception') + except StopIteration: + pass + + a = 1 + try: + g = (a for d in a) + g.next() + self.fail('should produce TypeError') + except TypeError: + pass + + self.assertEqual(list((x, y) for x in 'abcd' for y in 'abcd'), [(x, y) for x in 'abcd' for y in 'abcd']) + self.assertEqual(list((x, y) for x in 'ab' for y in 'xy'), [(x, y) for x in 'ab' for y in 'xy']) + + a = [x for x in range(10)] + b = (x for x in (y for y in a)) + self.assertEqual(sum(b), sum([x for x in range(10)])) + + self.assertEqual(sum(x**2 for x in range(10)), sum([x**2 for x in range(10)])) + self.assertEqual(sum(x*x for x in range(10) if x%2), sum([x*x for x in range(10) if x%2])) + self.assertEqual(sum(x for x in (y for y in range(10))), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in (y for y in (z for z in range(10)))), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in [y for y in (z for z in range(10))]), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True)) if True), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True) if False) if True), 0) + check_syntax_error(self, "foo(x for x in range(10), 100)") + check_syntax_error(self, "foo(100, x for x in range(10))") + + def testComprehensionSpecials(self): + # test for outmost iterable precomputation + x = 10; g = (i for i in range(x)); x = 5 + self.assertEqual(len(list(g)), 10) + + # This should hold, since we're only precomputing outmost iterable. + x = 10; t = False; g = ((i,j) for i in range(x) if t for j in range(x)) + x = 5; t = True; + self.assertEqual([(i,j) for i in range(10) for j in range(5)], list(g)) + + # Grammar allows multiple adjacent 'if's in listcomps and genexps, + # even though it's silly. Make sure it works (ifelse broke this.) + self.assertEqual([ x for x in range(10) if x % 2 if x % 3 ], [1, 5, 7]) + self.assertEqual(list(x for x in range(10) if x % 2 if x % 3), [1, 5, 7]) + + # verify unpacking single element tuples in listcomp/genexp. + self.assertEqual([x for x, in [(4,), (5,), (6,)]], [4, 5, 6]) + self.assertEqual(list(x for x, in [(7,), (8,), (9,)]), [7, 8, 9]) + + def testIfElseExpr(self): + # Test ifelse expressions in various cases + def _checkeval(msg, ret): + "helper to check that evaluation of expressions is done correctly" + print x + return ret + + self.assertEqual([ x() for x in lambda: True, lambda: False if x() ], [True]) + self.assertEqual([ x() for x in (lambda: True, lambda: False) if x() ], [True]) + self.assertEqual([ x(False) for x in (lambda x: False if x else True, lambda x: True if x else False) if x(False) ], [True]) + self.assertEqual((5 if 1 else _checkeval("check 1", 0)), 5) + self.assertEqual((_checkeval("check 2", 0) if 0 else 5), 5) + self.assertEqual((5 and 6 if 0 else 1), 1) + self.assertEqual(((5 and 6) if 0 else 1), 1) + self.assertEqual((5 and (6 if 1 else 1)), 6) + self.assertEqual((0 or _checkeval("check 3", 2) if 0 else 3), 3) + self.assertEqual((1 or _checkeval("check 4", 2) if 1 else _checkeval("check 5", 3)), 1) + self.assertEqual((0 or 5 if 1 else _checkeval("check 6", 3)), 5) + self.assertEqual((not 5 if 1 else 1), False) + self.assertEqual((not 5 if 0 else 1), 1) + self.assertEqual((6 + 1 if 1 else 2), 7) + self.assertEqual((6 - 1 if 1 else 2), 5) + self.assertEqual((6 * 2 if 1 else 4), 12) + self.assertEqual((6 / 2 if 1 else 3), 3) + self.assertEqual((6 < 4 if 0 else 2), 2) + + +def test_main(): + run_unittest(TokenTests, GrammarTests) + +if __name__ == '__main__': + test_main() Added: sandbox/trunk/2to3/tests/data/py3_test_grammar.py ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/tests/data/py3_test_grammar.py Fri Mar 2 21:43:48 2007 @@ -0,0 +1,864 @@ +# Python 3's Lib/test/test_grammar.py (r53781) + +# Python test set -- part 1, grammar. +# This just tests whether the parser accepts them all. + +# NOTE: When you run this test as a script from the command line, you +# get warnings about certain hex/oct constants. Since those are +# issued by the parser, you can't suppress them by adding a +# filterwarnings() call to this module. Therefore, to shut up the +# regression test, the filterwarnings() call has been added to +# regrtest.py. + +from test.test_support import run_unittest, check_syntax_error +import unittest +import sys +# testing import * +from sys import * + +class TokenTests(unittest.TestCase): + + def testBackslash(self): + # Backslash means line continuation: + x = 1 \ + + 1 + self.assertEquals(x, 2, 'backslash for line continuation') + + # Backslash does not means continuation in comments :\ + x = 0 + self.assertEquals(x, 0, 'backslash ending comment') + + def testPlainIntegers(self): + self.assertEquals(0xff, 255) + self.assertEquals(0377, 255) + self.assertEquals(2147483647, 017777777777) + from sys import maxint + if maxint == 2147483647: + self.assertEquals(-2147483647-1, -020000000000) + # XXX -2147483648 + self.assert_(037777777777 > 0) + self.assert_(0xffffffff > 0) + for s in '2147483648', '040000000000', '0x100000000': + try: + x = eval(s) + except OverflowError: + self.fail("OverflowError on huge integer literal %r" % s) + elif maxint == 9223372036854775807: + self.assertEquals(-9223372036854775807-1, -01000000000000000000000) + self.assert_(01777777777777777777777 > 0) + self.assert_(0xffffffffffffffff > 0) + for s in '9223372036854775808', '02000000000000000000000', \ + '0x10000000000000000': + try: + x = eval(s) + except OverflowError: + self.fail("OverflowError on huge integer literal %r" % s) + else: + self.fail('Weird maxint value %r' % maxint) + + def testLongIntegers(self): + x = 0 + x = 0 + x = 0xffffffffffffffff + x = 0xffffffffffffffff + x = 077777777777777777 + x = 077777777777777777 + x = 123456789012345678901234567890 + x = 123456789012345678901234567890 + + def testFloats(self): + x = 3.14 + x = 314. + x = 0.314 + # XXX x = 000.314 + x = .314 + x = 3e14 + x = 3E14 + x = 3e-14 + x = 3e+14 + x = 3.e14 + x = .3e14 + x = 3.1e4 + + def testStringLiterals(self): + x = ''; y = ""; self.assert_(len(x) == 0 and x == y) + x = '\''; y = "'"; self.assert_(len(x) == 1 and x == y and ord(x) == 39) + x = '"'; y = "\""; self.assert_(len(x) == 1 and x == y and ord(x) == 34) + x = "doesn't \"shrink\" does it" + y = 'doesn\'t "shrink" does it' + self.assert_(len(x) == 24 and x == y) + x = "does \"shrink\" doesn't it" + y = 'does "shrink" doesn\'t it' + self.assert_(len(x) == 24 and x == y) + x = """ +The "quick" +brown fox +jumps over +the 'lazy' dog. +""" + y = '\nThe "quick"\nbrown fox\njumps over\nthe \'lazy\' dog.\n' + self.assertEquals(x, y) + y = ''' +The "quick" +brown fox +jumps over +the 'lazy' dog. +''' + self.assertEquals(x, y) + y = "\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the 'lazy' dog.\n\ +" + self.assertEquals(x, y) + y = '\n\ +The \"quick\"\n\ +brown fox\n\ +jumps over\n\ +the \'lazy\' dog.\n\ +' + self.assertEquals(x, y) + + def testEllipsis(self): + x = ... + self.assert_(x is Ellipsis) + +class GrammarTests(unittest.TestCase): + + # single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE + # XXX can't test in a script -- this rule is only used when interactive + + # file_input: (NEWLINE | stmt)* ENDMARKER + # Being tested as this very moment this very module + + # expr_input: testlist NEWLINE + # XXX Hard to test -- used only in calls to input() + + def testEvalInput(self): + # testlist ENDMARKER + x = eval('1, 0 or 1') + + def testFuncdef(self): + ### [decorators] 'def' NAME parameters ['->' test] ':' suite + ### decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE + ### decorators: decorator+ + ### parameters: '(' [typedargslist] ')' + ### typedargslist: ((tfpdef ['=' test] ',')* + ### ('*' [tname] (',' tname ['=' test])* [',' '**' tname] | '**' tname) + ### | tfpdef ['=' test] (',' tfpdef ['=' test])* [',']) + ### tname: NAME [':' test] + ### tfpdef: tname | '(' tfplist ')' + ### tfplist: tfpdef (',' tfpdef)* [','] + ### varargslist: ((vfpdef ['=' test] ',')* + ### ('*' [vname] (',' vname ['=' test])* [',' '**' vname] | '**' vname) + ### | vfpdef ['=' test] (',' vfpdef ['=' test])* [',']) + ### vname: NAME + ### vfpdef: vname | '(' vfplist ')' + ### vfplist: vfpdef (',' vfpdef)* [','] + def f1(): pass + f1() + f1(*()) + f1(*(), **{}) + def f2(one_argument): pass + def f3(two, arguments): pass + def f4(two, (compound, (argument, list))): pass + def f5((compound, first), two): pass + self.assertEquals(f2.func_code.co_varnames, ('one_argument',)) + self.assertEquals(f3.func_code.co_varnames, ('two', 'arguments')) + if sys.platform.startswith('java'): + self.assertEquals(f4.func_code.co_varnames, + ('two', '(compound, (argument, list))', 'compound', 'argument', + 'list',)) + self.assertEquals(f5.func_code.co_varnames, + ('(compound, first)', 'two', 'compound', 'first')) + else: + self.assertEquals(f4.func_code.co_varnames, + ('two', '.1', 'compound', 'argument', 'list')) + self.assertEquals(f5.func_code.co_varnames, + ('.0', 'two', 'compound', 'first')) + def a1(one_arg,): pass + def a2(two, args,): pass + def v0(*rest): pass + def v1(a, *rest): pass + def v2(a, b, *rest): pass + def v3(a, (b, c), *rest): return a, b, c, rest + + f1() + f2(1) + f2(1,) + f3(1, 2) + f3(1, 2,) + f4(1, (2, (3, 4))) + v0() + v0(1) + v0(1,) + v0(1,2) + v0(1,2,3,4,5,6,7,8,9,0) + v1(1) + v1(1,) + v1(1,2) + v1(1,2,3) + v1(1,2,3,4,5,6,7,8,9,0) + v2(1,2) + v2(1,2,3) + v2(1,2,3,4) + v2(1,2,3,4,5,6,7,8,9,0) + v3(1,(2,3)) + v3(1,(2,3),4) + v3(1,(2,3),4,5,6,7,8,9,0) + + # ceval unpacks the formal arguments into the first argcount names; + # thus, the names nested inside tuples must appear after these names. + if sys.platform.startswith('java'): + self.assertEquals(v3.func_code.co_varnames, ('a', '(b, c)', 'rest', 'b', 'c')) + else: + self.assertEquals(v3.func_code.co_varnames, ('a', '.1', 'rest', 'b', 'c')) + self.assertEquals(v3(1, (2, 3), 4), (1, 2, 3, (4,))) + def d01(a=1): pass + d01() + d01(1) + d01(*(1,)) + d01(**{'a':2}) + def d11(a, b=1): pass + d11(1) + d11(1, 2) + d11(1, **{'b':2}) + def d21(a, b, c=1): pass + d21(1, 2) + d21(1, 2, 3) + d21(*(1, 2, 3)) + d21(1, *(2, 3)) + d21(1, 2, *(3,)) + d21(1, 2, **{'c':3}) + def d02(a=1, b=2): pass + d02() + d02(1) + d02(1, 2) + d02(*(1, 2)) + d02(1, *(2,)) + d02(1, **{'b':2}) + d02(**{'a': 1, 'b': 2}) + def d12(a, b=1, c=2): pass + d12(1) + d12(1, 2) + d12(1, 2, 3) + def d22(a, b, c=1, d=2): pass + d22(1, 2) + d22(1, 2, 3) + d22(1, 2, 3, 4) + def d01v(a=1, *rest): pass + d01v() + d01v(1) + d01v(1, 2) + d01v(*(1, 2, 3, 4)) + d01v(*(1,)) + d01v(**{'a':2}) + def d11v(a, b=1, *rest): pass + d11v(1) + d11v(1, 2) + d11v(1, 2, 3) + def d21v(a, b, c=1, *rest): pass + d21v(1, 2) + d21v(1, 2, 3) + d21v(1, 2, 3, 4) + d21v(*(1, 2, 3, 4)) + d21v(1, 2, **{'c': 3}) + def d02v(a=1, b=2, *rest): pass + d02v() + d02v(1) + d02v(1, 2) + d02v(1, 2, 3) + d02v(1, *(2, 3, 4)) + d02v(**{'a': 1, 'b': 2}) + def d12v(a, b=1, c=2, *rest): pass + d12v(1) + d12v(1, 2) + d12v(1, 2, 3) + d12v(1, 2, 3, 4) + d12v(*(1, 2, 3, 4)) + d12v(1, 2, *(3, 4, 5)) + d12v(1, *(2,), **{'c': 3}) + def d22v(a, b, c=1, d=2, *rest): pass + d22v(1, 2) + d22v(1, 2, 3) + d22v(1, 2, 3, 4) + d22v(1, 2, 3, 4, 5) + d22v(*(1, 2, 3, 4)) + d22v(1, 2, *(3, 4, 5)) + d22v(1, *(2, 3), **{'d': 4}) + def d31v((x)): pass + d31v(1) + def d32v((x,)): pass + d32v((1,)) + # keyword only argument tests + def pos0key1(*, key): return key + pos0key1(key=100) + def pos2key2(p1, p2, *, k1, k2=100): return p1,p2,k1,k2 + pos2key2(1, 2, k1=100) + pos2key2(1, 2, k1=100, k2=200) + pos2key2(1, 2, k2=100, k1=200) + def pos2key2dict(p1, p2, *, k1=100, k2, **kwarg): return p1,p2,k1,k2,kwarg + pos2key2dict(1,2,k2=100,tokwarg1=100,tokwarg2=200) + pos2key2dict(1,2,tokwarg1=100,tokwarg2=200, k2=100) + + # argument annotation tests + def f(x) -> list: pass + self.assertEquals(f.func_annotations, {'return': list}) + def f(x:int): pass + self.assertEquals(f.func_annotations, {'x': int}) + def f(*x:str): pass + self.assertEquals(f.func_annotations, {'x': str}) + def f(**x:float): pass + self.assertEquals(f.func_annotations, {'x': float}) + def f(x, y:1+2): pass + self.assertEquals(f.func_annotations, {'y': 3}) + def f(a, (b:1, c:2, d)): pass + self.assertEquals(f.func_annotations, {'b': 1, 'c': 2}) + def f(a, (b:1, c:2, d), e:3=4, f=5, *g:6): pass + self.assertEquals(f.func_annotations, + {'b': 1, 'c': 2, 'e': 3, 'g': 6}) + def f(a, (b:1, c:2, d), e:3=4, f=5, *g:6, h:7, i=8, j:9=10, + **k:11) -> 12: pass + self.assertEquals(f.func_annotations, + {'b': 1, 'c': 2, 'e': 3, 'g': 6, 'h': 7, 'j': 9, + 'k': 11, 'return': 12}) + + def testLambdef(self): + ### lambdef: 'lambda' [varargslist] ':' test + l1 = lambda : 0 + self.assertEquals(l1(), 0) + l2 = lambda : a[d] # XXX just testing the expression + l3 = lambda : [2 < x for x in [-1, 3, 0]] + self.assertEquals(l3(), [0, 1, 0]) + l4 = lambda x = lambda y = lambda z=1 : z : y() : x() + self.assertEquals(l4(), 1) + l5 = lambda x, y, z=2: x + y + z + self.assertEquals(l5(1, 2), 5) + self.assertEquals(l5(1, 2, 3), 6) + check_syntax_error(self, "lambda x: x = 2") + l6 = lambda x, y, *, k=20: x+y+k + self.assertEquals(l6(1,2), 1+2+20) + self.assertEquals(l6(1,2,k=10), 1+2+10) + + + ### stmt: simple_stmt | compound_stmt + # Tested below + + def testSimpleStmt(self): + ### simple_stmt: small_stmt (';' small_stmt)* [';'] + x = 1; pass; del x + def foo(): + # verify statments that end with semi-colons + x = 1; pass; del x; + foo() + + ### small_stmt: expr_stmt | pass_stmt | del_stmt | flow_stmt | import_stmt | global_stmt | access_stmt + # Tested below + + def testExprStmt(self): + # (exprlist '=')* exprlist + 1 + 1, 2, 3 + x = 1 + x = 1, 2, 3 + x = y = z = 1, 2, 3 + x, y, z = 1, 2, 3 + abc = a, b, c = x, y, z = xyz = 1, 2, (3, 4) + + check_syntax_error(self, "x + 1 = 1") + check_syntax_error(self, "a + 1 = b + 2") + + def testDelStmt(self): + # 'del' exprlist + abc = [1,2,3] + x, y, z = abc + xyz = x, y, z + + del abc + del x, y, (z, xyz) + + def testPassStmt(self): + # 'pass' + pass + + # flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt + # Tested below + + def testBreakStmt(self): + # 'break' + while 1: break + + def testContinueStmt(self): + # 'continue' + i = 1 + while i: i = 0; continue + + msg = "" + while not msg: + msg = "ok" + try: + continue + msg = "continue failed to continue inside try" + except: + msg = "continue inside try called except block" + if msg != "ok": + self.fail(msg) + + msg = "" + while not msg: + msg = "finally block not called" + try: + continue + finally: + msg = "ok" + if msg != "ok": + self.fail(msg) + + def test_break_continue_loop(self): + # This test warrants an explanation. It is a test specifically for SF bugs + # #463359 and #462937. The bug is that a 'break' statement executed or + # exception raised inside a try/except inside a loop, *after* a continue + # statement has been executed in that loop, will cause the wrong number of + # arguments to be popped off the stack and the instruction pointer reset to + # a very small number (usually 0.) Because of this, the following test + # *must* written as a function, and the tracking vars *must* be function + # arguments with default values. Otherwise, the test will loop and loop. + + def test_inner(extra_burning_oil = 1, count=0): + big_hippo = 2 + while big_hippo: + count += 1 + try: + if extra_burning_oil and big_hippo == 1: + extra_burning_oil -= 1 + break + big_hippo -= 1 + continue + except: + raise + if count > 2 or big_hippo != 1: + self.fail("continue then break in try/except in loop broken!") + test_inner() + + def testReturn(self): + # 'return' [testlist] + def g1(): return + def g2(): return 1 + g1() + x = g2() + check_syntax_error(self, "class foo:return 1") + + def testYield(self): + check_syntax_error(self, "class foo:yield 1") + + def testRaise(self): + # 'raise' test [',' test] + try: raise RuntimeError, 'just testing' + except RuntimeError: pass + try: raise KeyboardInterrupt + except KeyboardInterrupt: pass + + def testImport(self): + # 'import' dotted_as_names + import sys + import time, sys + # 'from' dotted_name 'import' ('*' | '(' import_as_names ')' | import_as_names) + from time import time + from time import (time) + # not testable inside a function, but already done at top of the module + # from sys import * + from sys import path, argv + from sys import (path, argv) + from sys import (path, argv,) + + def testGlobal(self): + # 'global' NAME (',' NAME)* + global a + global a, b + global one, two, three, four, five, six, seven, eight, nine, ten + + def testAssert(self): + # assert_stmt: 'assert' test [',' test] + assert 1 + assert 1, 1 + assert lambda x:x + assert 1, lambda x:x+1 + try: + assert 0, "msg" + except AssertionError as e: + self.assertEquals(e.args[0], "msg") + else: + if __debug__: + self.fail("AssertionError not raised by assert 0") + + ### compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef + # Tested below + + def testIf(self): + # 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] + if 1: pass + if 1: pass + else: pass + if 0: pass + elif 0: pass + if 0: pass + elif 0: pass + elif 0: pass + elif 0: pass + else: pass + + def testWhile(self): + # 'while' test ':' suite ['else' ':' suite] + while 0: pass + while 0: pass + else: pass + + def testFor(self): + # 'for' exprlist 'in' exprlist ':' suite ['else' ':' suite] + for i in 1, 2, 3: pass + for i, j, k in (): pass + else: pass + class Squares: + def __init__(self, max): + self.max = max + self.sofar = [] + def __len__(self): return len(self.sofar) + def __getitem__(self, i): + if not 0 <= i < self.max: raise IndexError + n = len(self.sofar) + while n <= i: + self.sofar.append(n*n) + n = n+1 + return self.sofar[i] + n = 0 + for x in Squares(10): n = n+x + if n != 285: + self.fail('for over growing sequence') + + result = [] + for x, in [(1,), (2,), (3,)]: + result.append(x) + self.assertEqual(result, [1, 2, 3]) + + def testTry(self): + ### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite] + ### | 'try' ':' suite 'finally' ':' suite + ### except_clause: 'except' [expr ['as' expr]] + try: + 1/0 + except ZeroDivisionError: + pass + else: + pass + try: 1/0 + except EOFError: pass + except TypeError as msg: pass + except RuntimeError as msg: pass + except: pass + else: pass + try: 1/0 + except (EOFError, TypeError, ZeroDivisionError): pass + try: 1/0 + except (EOFError, TypeError, ZeroDivisionError) as msg: pass + try: pass + finally: pass + + def testSuite(self): + # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT + if 1: pass + if 1: + pass + if 1: + # + # + # + pass + pass + # + pass + # + + def testTest(self): + ### and_test ('or' and_test)* + ### and_test: not_test ('and' not_test)* + ### not_test: 'not' not_test | comparison + if not 1: pass + if 1 and 1: pass + if 1 or 1: pass + if not not not 1: pass + if not 1 and 1 and 1: pass + if 1 and 1 or 1 and 1 and 1 or not 1 and 1: pass + + def testComparison(self): + ### comparison: expr (comp_op expr)* + ### comp_op: '<'|'>'|'=='|'>='|'<='|'!='|'in'|'not' 'in'|'is'|'is' 'not' + if 1: pass + x = (1 == 1) + if 1 == 1: pass + if 1 != 1: pass + if 1 < 1: pass + if 1 > 1: pass + if 1 <= 1: pass + if 1 >= 1: pass + if 1 is 1: pass + if 1 is not 1: pass + if 1 in (): pass + if 1 not in (): pass + if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in 1 is 1 is not 1: pass + + def testBinaryMaskOps(self): + x = 1 & 1 + x = 1 ^ 1 + x = 1 | 1 + + def testShiftOps(self): + x = 1 << 1 + x = 1 >> 1 + x = 1 << 1 >> 1 + + def testAdditiveOps(self): + x = 1 + x = 1 + 1 + x = 1 - 1 - 1 + x = 1 - 1 + 1 - 1 + 1 + + def testMultiplicativeOps(self): + x = 1 * 1 + x = 1 / 1 + x = 1 % 1 + x = 1 / 1 * 1 % 1 + + def testUnaryOps(self): + x = +1 + x = -1 + x = ~1 + x = ~1 ^ 1 & 1 | 1 & 1 ^ -1 + x = -1*1/1 + 1*1 - ---1*1 + + def testSelectors(self): + ### trailer: '(' [testlist] ')' | '[' subscript ']' | '.' NAME + ### subscript: expr | [expr] ':' [expr] + + import sys, time + c = sys.path[0] + x = time.time() + x = sys.modules['time'].time() + a = '01234' + c = a[0] + c = a[-1] + s = a[0:5] + s = a[:5] + s = a[0:] + s = a[:] + s = a[-5:] + s = a[:-1] + s = a[-4:-3] + # A rough test of SF bug 1333982. http://python.org/sf/1333982 + # The testing here is fairly incomplete. + # Test cases should include: commas with 1 and 2 colons + d = {} + d[1] = 1 + d[1,] = 2 + d[1,2] = 3 + d[1,2,3] = 4 + L = list(d) + L.sort(key=lambda x: x if isinstance(x, tuple) else ()) + self.assertEquals(str(L), '[1, (1,), (1, 2), (1, 2, 3)]') + + def testAtoms(self): + ### atom: '(' [testlist] ')' | '[' [testlist] ']' | '{' [dictsetmaker] '}' | NAME | NUMBER | STRING + ### dictsetmaker: (test ':' test (',' test ':' test)* [',']) | (test (',' test)* [',']) + + x = (1) + x = (1 or 2 or 3) + x = (1 or 2 or 3, 2, 3) + + x = [] + x = [1] + x = [1 or 2 or 3] + x = [1 or 2 or 3, 2, 3] + x = [] + + x = {} + x = {'one': 1} + x = {'one': 1,} + x = {'one' or 'two': 1 or 2} + x = {'one': 1, 'two': 2} + x = {'one': 1, 'two': 2,} + x = {'one': 1, 'two': 2, 'three': 3, 'four': 4, 'five': 5, 'six': 6} + + x = {'one'} + x = {'one', 1,} + x = {'one', 'two', 'three'} + x = {2, 3, 4,} + + x = x + x = 'x' + x = 123 + + ### exprlist: expr (',' expr)* [','] + ### testlist: test (',' test)* [','] + # These have been exercised enough above + + def testClassdef(self): + # 'class' NAME ['(' [testlist] ')'] ':' suite + class B: pass + class B2(): pass + class C1(B): pass + class C2(B): pass + class D(C1, C2, B): pass + class C: + def meth1(self): pass + def meth2(self, arg): pass + def meth3(self, a1, a2): pass + + def testListcomps(self): + # list comprehension tests + nums = [1, 2, 3, 4, 5] + strs = ["Apple", "Banana", "Coconut"] + spcs = [" Apple", " Banana ", "Coco nut "] + + self.assertEqual([s.strip() for s in spcs], ['Apple', 'Banana', 'Coco nut']) + self.assertEqual([3 * x for x in nums], [3, 6, 9, 12, 15]) + self.assertEqual([x for x in nums if x > 2], [3, 4, 5]) + self.assertEqual([(i, s) for i in nums for s in strs], + [(1, 'Apple'), (1, 'Banana'), (1, 'Coconut'), + (2, 'Apple'), (2, 'Banana'), (2, 'Coconut'), + (3, 'Apple'), (3, 'Banana'), (3, 'Coconut'), + (4, 'Apple'), (4, 'Banana'), (4, 'Coconut'), + (5, 'Apple'), (5, 'Banana'), (5, 'Coconut')]) + self.assertEqual([(i, s) for i in nums for s in [f for f in strs if "n" in f]], + [(1, 'Banana'), (1, 'Coconut'), (2, 'Banana'), (2, 'Coconut'), + (3, 'Banana'), (3, 'Coconut'), (4, 'Banana'), (4, 'Coconut'), + (5, 'Banana'), (5, 'Coconut')]) + self.assertEqual([(lambda a:[a**i for i in range(a+1)])(j) for j in range(5)], + [[1], [1, 1], [1, 2, 4], [1, 3, 9, 27], [1, 4, 16, 64, 256]]) + + def test_in_func(l): + return [0 < x < 3 for x in l if x > 2] + + self.assertEqual(test_in_func(nums), [False, False, False]) + + def test_nested_front(): + self.assertEqual([[y for y in [x, x + 1]] for x in [1,3,5]], + [[1, 2], [3, 4], [5, 6]]) + + test_nested_front() + + check_syntax_error(self, "[i, s for i in nums for s in strs]") + check_syntax_error(self, "[x if y]") + + suppliers = [ + (1, "Boeing"), + (2, "Ford"), + (3, "Macdonalds") + ] + + parts = [ + (10, "Airliner"), + (20, "Engine"), + (30, "Cheeseburger") + ] + + suppart = [ + (1, 10), (1, 20), (2, 20), (3, 30) + ] + + x = [ + (sname, pname) + for (sno, sname) in suppliers + for (pno, pname) in parts + for (sp_sno, sp_pno) in suppart + if sno == sp_sno and pno == sp_pno + ] + + self.assertEqual(x, [('Boeing', 'Airliner'), ('Boeing', 'Engine'), ('Ford', 'Engine'), + ('Macdonalds', 'Cheeseburger')]) + + def testGenexps(self): + # generator expression tests + g = ([x for x in range(10)] for x in range(1)) + self.assertEqual(g.next(), [x for x in range(10)]) + try: + g.next() + self.fail('should produce StopIteration exception') + except StopIteration: + pass + + a = 1 + try: + g = (a for d in a) + g.next() + self.fail('should produce TypeError') + except TypeError: + pass + + self.assertEqual(list((x, y) for x in 'abcd' for y in 'abcd'), [(x, y) for x in 'abcd' for y in 'abcd']) + self.assertEqual(list((x, y) for x in 'ab' for y in 'xy'), [(x, y) for x in 'ab' for y in 'xy']) + + a = [x for x in range(10)] + b = (x for x in (y for y in a)) + self.assertEqual(sum(b), sum([x for x in range(10)])) + + self.assertEqual(sum(x**2 for x in range(10)), sum([x**2 for x in range(10)])) + self.assertEqual(sum(x*x for x in range(10) if x%2), sum([x*x for x in range(10) if x%2])) + self.assertEqual(sum(x for x in (y for y in range(10))), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in (y for y in (z for z in range(10)))), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in [y for y in (z for z in range(10))]), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True)) if True), sum([x for x in range(10)])) + self.assertEqual(sum(x for x in (y for y in (z for z in range(10) if True) if False) if True), 0) + check_syntax_error(self, "foo(x for x in range(10), 100)") + check_syntax_error(self, "foo(100, x for x in range(10))") + + def testComprehensionSpecials(self): + # test for outmost iterable precomputation + x = 10; g = (i for i in range(x)); x = 5 + self.assertEqual(len(list(g)), 10) + + # This should hold, since we're only precomputing outmost iterable. + x = 10; t = False; g = ((i,j) for i in range(x) if t for j in range(x)) + x = 5; t = True; + self.assertEqual([(i,j) for i in range(10) for j in range(5)], list(g)) + + # Grammar allows multiple adjacent 'if's in listcomps and genexps, + # even though it's silly. Make sure it works (ifelse broke this.) + self.assertEqual([ x for x in range(10) if x % 2 if x % 3 ], [1, 5, 7]) + self.assertEqual(list(x for x in range(10) if x % 2 if x % 3), [1, 5, 7]) + + # verify unpacking single element tuples in listcomp/genexp. + self.assertEqual([x for x, in [(4,), (5,), (6,)]], [4, 5, 6]) + self.assertEqual(list(x for x, in [(7,), (8,), (9,)]), [7, 8, 9]) + + def testIfElseExpr(self): + # Test ifelse expressions in various cases + def _checkeval(msg, ret): + "helper to check that evaluation of expressions is done correctly" + print(x) + return ret + + self.assertEqual([ x() for x in lambda: True, lambda: False if x() ], [True]) + self.assertEqual([ x() for x in (lambda: True, lambda: False) if x() ], [True]) + self.assertEqual([ x(False) for x in (lambda x: False if x else True, lambda x: True if x else False) if x(False) ], [True]) + self.assertEqual((5 if 1 else _checkeval("check 1", 0)), 5) + self.assertEqual((_checkeval("check 2", 0) if 0 else 5), 5) + self.assertEqual((5 and 6 if 0 else 1), 1) + self.assertEqual(((5 and 6) if 0 else 1), 1) + self.assertEqual((5 and (6 if 1 else 1)), 6) + self.assertEqual((0 or _checkeval("check 3", 2) if 0 else 3), 3) + self.assertEqual((1 or _checkeval("check 4", 2) if 1 else _checkeval("check 5", 3)), 1) + self.assertEqual((0 or 5 if 1 else _checkeval("check 6", 3)), 5) + self.assertEqual((not 5 if 1 else 1), False) + self.assertEqual((not 5 if 0 else 1), 1) + self.assertEqual((6 + 1 if 1 else 2), 7) + self.assertEqual((6 - 1 if 1 else 2), 5) + self.assertEqual((6 * 2 if 1 else 4), 12) + self.assertEqual((6 / 2 if 1 else 3), 3) + self.assertEqual((6 < 4 if 0 else 2), 2) + + +def test_main(): + run_unittest(TokenTests, GrammarTests) + +if __name__ == '__main__': + test_main() Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Fri Mar 2 21:43:48 2007 @@ -1,7 +1,11 @@ #!/usr/bin/env python2.5 """ Test suite for Grammar.txt. This is the place to add tests for changes to 2to3's grammar, such as those merging the grammars for -Python 2 and 3. """ +Python 2 and 3. + +In addition to specific tests for parts of the grammar we've changed, +TestGrammarFiles also attempts to process the test_grammar.py files +from Python 2 and Python 3. """ # Author: Collin Winter # Testing imports @@ -17,8 +21,8 @@ from pgen2 import driver from pgen2.parse import ParseError - -grammar_path = os.path.join(os.path.dirname(__file__), "..", "Grammar.txt") +test_dir = os.path.dirname(__file__) +grammar_path = os.path.join(test_dir, "..", "Grammar.txt") grammar = driver.load_grammar(grammar_path) driver = driver.Driver(grammar, convert=pytree.convert) @@ -122,6 +126,16 @@ def test_4(self): self.validate("""x = {2, 3, 4,}""") + + +class TestGrammarFiles(GrammarTest): + def test_python2(self): + f = os.path.join(test_dir, "data", "py2_test_grammar.py") + driver.parse_file(f) + + def test_python3(self): + f = os.path.join(test_dir, "data", "py3_test_grammar.py") + driver.parse_file(f) if __name__ == "__main__": From buildbot at python.org Fri Mar 2 23:32:01 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 02 Mar 2007 22:32:01 +0000 Subject: [Python-checkins] buildbot failure in g4 osx.4 2.5 Message-ID: <20070302223201.F03B91E4005@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%25202.5/builds/236 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Cary': Sullivan Build Source Stamp: [branch Mitchel] Cortney Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From buildbot at python.org Fri Mar 2 23:34:33 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 02 Mar 2007 22:34:33 +0000 Subject: [Python-checkins] buildbot failure in sparc solaris10 gcc 2.5 Message-ID: <20070302223433.DB6D81E4005@bag.python.org> The Buildbot has detected a new failure of sparc solaris10 gcc 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/sparc%2520solaris10%2520gcc%25202.5/builds/245 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Dillon': Kerry Build Source Stamp: [branch Andreas] Marcos Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From buildbot at python.org Fri Mar 2 23:35:02 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 02 Mar 2007 22:35:02 +0000 Subject: [Python-checkins] buildbot failure in x86 gentoo 2.5 Message-ID: <20070302223502.45B1A1E4008@bag.python.org> The Buildbot has detected a new failure of x86 gentoo 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%25202.5/builds/250 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Dallin': Van Build Source Stamp: [branch Zachery] Gianni Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From buildbot at python.org Fri Mar 2 23:43:07 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 02 Mar 2007 22:43:07 +0000 Subject: [Python-checkins] buildbot failure in amd64 gentoo 2.5 Message-ID: <20070302224307.42B231E4005@bag.python.org> The Buildbot has detected a new failure of amd64 gentoo 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/amd64%2520gentoo%25202.5/builds/250 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Jonah': Dashawn Build Source Stamp: [branch Ibrahim] Mikhail Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From buildbot at python.org Fri Mar 2 23:49:12 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 02 Mar 2007 22:49:12 +0000 Subject: [Python-checkins] buildbot failure in x86 XP 2.5 Message-ID: <20070302224912.285AF1E4005@bag.python.org> The Buildbot has detected a new failure of x86 XP 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%25202.5/builds/136 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Adam': Colten Build Source Stamp: [branch Jean] Spenser Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From python-checkins at python.org Sat Mar 3 01:30:41 2007 From: python-checkins at python.org (eric.smith) Date: Sat, 3 Mar 2007 01:30:41 +0100 (CET) Subject: [Python-checkins] r54100 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070303003041.052AB1E400D@bag.python.org> Author: eric.smith Date: Sat Mar 3 01:30:36 2007 New Revision: 54100 Modified: sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Added character formatter, code cleanup, added to do items in README. Modified: sandbox/trunk/pep3101/README.txt ============================================================================== --- sandbox/trunk/pep3101/README.txt (original) +++ sandbox/trunk/pep3101/README.txt Sat Mar 3 01:30:36 2007 @@ -7,7 +7,7 @@ Current developers: Patrick Maupin (pmaupin at gmail.com) - Eric V. Smith + Eric V. Smith (eric at trueblade.com) Pete Shinner The code is only half-baked at present @@ -61,6 +61,10 @@ compatible template systems. - Play with possible options for specifying additional escape syntaxes + - Should we have stricter checking on format strings? For example + type "s" doesn't allow a sign character. Should specifying one + be an error? + - Test suite needs to check for specific exceptions. _flags options to consider adding: Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Sat Mar 3 01:30:36 2007 @@ -89,7 +89,7 @@ self.formatEquals("32_*>4d", "{0:{1}{2}4{3}}", 32, "*", ">", "d") def test_specifiers(self): - self.formatEquals("97_c", "{0:c}", ord("a")) + self.formatEquals("a", "{0:c}", ord("a")) self.formatEquals("8_08b", "{0:08b}", 8) self.formatEquals("8_ >3d", "{0: >3d}", 8) self.formatEquals("0.1515_.0%", "{0:.0%}", .1515) @@ -101,9 +101,11 @@ self.formatEquals("abc", "{0:.3s}", "abcdef") self.formatEquals("resultx", "{0:x<7s}", "result") + self.formatEquals("resultxx", "{0:x<8s}", "result") self.formatEquals("result ", "{0: <7s}", "result") self.formatEquals("result ", "{0:<7s}", "result") self.formatEquals(" result", "{0:>7s}", "result") + self.formatEquals(" result", "{0:>8s}", "result") def test_repr_specifiers(self): self.formatEquals("3", "{0:r}", 3) @@ -113,6 +115,30 @@ self.formatEquals("'abcdefg'", "{0:r}", "abcdefg") self.formatEquals("'abcdefg", "{0:8r}", "abcdefg") + def test_decimal_specifiers(self): + pass +# self.assertRaises(Exception, "{0:d}", "non-number") + +# self.formatEquals("0", "{0:d}", 0) +# self.formatEquals("1" + "0" * 100, "{0:d}", 10**100) + + def test_char_specifiers(self): + self.formatEquals("A", "{0:c}", "A") + self.formatEquals("8", "{0:c}", "8") + self.formatEquals(";", "{0:c}", ";") + self.formatEquals(";", "{0:c}", long(ord(";"))) + + self.formatRaises(TypeError, "{0:c}", "abcd") + + # XXX not sure why this doesn't raise + #self.formatRaises(TypeError, "{0:c}", [1, 2, 3]) + + # XXX not sure why this doesn't raise + #self.formatRaises(TypeError, "{0:c}", 1j) + + # XXX this should raise, but instead gives a DeprecationWarning + #self.formatRaises(TypeError, "{0:c}", 3.14) + def test_missing_type_specifier(self): # make sure floats use 'g', ints and longs 'd', and everything else 's' pass Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Sat Mar 3 01:30:36 2007 @@ -1,5 +1,3 @@ -#define DUMMY_FORMATTING 1 - /* unicodeformat.c -- implementation of PEP 3101 @@ -26,6 +24,7 @@ #define CH_TYPE Py_UNICODE #define CH_TYPE_ISDECIMAL Py_UNICODE_ISDECIMAL #define CH_TYPE_TODECIMAL Py_UNICODE_TODECIMAL +#define CH_TYPE_FILL Py_UNICODE_FILL #define STROBJ_AS_PTR PyUnicode_AS_UNICODE #define STROBJ_GET_SIZE PyUnicode_GET_SIZE #define STROBJ_NEW PyUnicode_FromUnicode @@ -37,6 +36,7 @@ #define CH_TYPE char #define CH_TYPE_ISDECIMAL(x) ((x >= '0') && (x <= '9')) #define CH_TYPE_TODECIMAL(x) (CH_TYPE_ISDECIMAL(x) ? (x - '0') : -1) +#define CH_TYPE_FILL Py_UNICODE_FILL #define STROBJ_AS_PTR PyString_AS_STRING #define STROBJ_GET_SIZE PyString_GET_SIZE #define STROBJ_NEW PyString_FromStringAndSize @@ -67,6 +67,19 @@ /*********** Global data structures and forward declarations *********/ /************************************************************************/ +/* FORMATBUFLEN is taken from stringobject.c, it should probably be + factored out */ +/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) + + FORMATBUFLEN is the length of the buffer in which the floats, ints, & + chars are formatted. XXX This is a magic number. Each formatting + routine does bounds checking to ensure no overflow, but a better + solution may be to malloc a buffer of appropriate size for each + format. For now, the current solution is sufficient. +*/ +#define FORMATBUFLEN (size_t)120 + + #ifdef __cplusplus extern "C" { #endif @@ -161,17 +174,6 @@ /************************** Utility functions ************************/ /************************************************************************/ -/* XXX probably a better way to do this. can't use memset, though, - because of Unicode and char* support */ -Py_LOCAL_INLINE(void) -charset(CH_TYPE* dst, CH_TYPE ch, Py_ssize_t len) -{ - CH_TYPE* end = dst + len; - for(; dst < end; dst++) { - *dst = ch; - } -} - /************************************************************************/ /*********** Error handling and exception generation **************/ @@ -748,7 +750,8 @@ /* used to output simple strings, only supports a maximum width and total field alignment */ static int -output_string_chars(FmtState *fs, CH_TYPE *src, Py_ssize_t len, const InternalFormatSpec *format) +output_string_chars(FmtState *fs, CH_TYPE *src, Py_ssize_t len, + const InternalFormatSpec *format) { Py_ssize_t ok; Py_ssize_t width; /* total field width */ @@ -762,6 +765,10 @@ if (format->width >= 0) { width = format->width; + /* don't write out more than width characters */ + if (len > width) { + len = width; + } } else { /* not specified, use all of the chars and no more */ width = len; @@ -773,11 +780,13 @@ /* now write into that space */ - /* if right aligning, increment the destination allow space on the left */ - memcpy(dst + (format->align == '>' ? (width - len) : 0), src, len * sizeof(CH_TYPE)); + /* if right aligning, increment the destination allow space on the + left */ + memcpy(dst + (format->align == '>' ? (width - len) : 0), src, + len * sizeof(CH_TYPE)); /* do any padding */ - if (len != width) { + if (width > len) { CH_TYPE fill_char = format->fill_char; if (fill_char == '\0') { /* use the default, if not specified */ @@ -786,27 +795,19 @@ if (format->align == '>') { /* right align, pad on left */ - charset(dst, fill_char, width - len); + CH_TYPE_FILL(dst, fill_char, width - len); } else { /* left align, pad on right */ - charset(dst + len, fill_char, width - len); + CH_TYPE_FILL(dst + len, fill_char, width - len); } } return 1; } -/* - Our internal conversion functions have this signature. - - returns 0 on failure, else 1 -*/ -typedef int -(*ConversionFunction)(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format); - /* XXX delete this when all internal conversions are implemented */ static int -convert_DUMMY(PyObject *fieldobj, FmtState *fs) +format_DUMMY(PyObject *fieldobj, FmtState *fs) { PyObject *myobj; int ok; @@ -832,23 +833,70 @@ return 1; } -/* conversion functions */ +/************************************************************************/ +/************************* Builtin formatters *************************/ +/************************************************************************/ + +/* + return 0 on failure, else 1 +*/ +typedef int +(*FormatFunction)(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format); + static int -convert_binary(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_binary(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_char(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_char(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + int ok; + CH_TYPE buf; + + if (PyString_Check(fieldobj)) { + if (!PyArg_Parse(fieldobj, "c;%c requires int or char", &buf)) + return 0; + } + else { + if (!PyArg_Parse(fieldobj, "b;%c requires int or char", &buf)) + return -1; + } + + return output_data(fs, &buf, 1); } static int -convert_decimal(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_decimal(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); +#if 0 + if (PyLong_Check(fieldobj)) { + int ilen; + temp = _PyString_FormatLong(v, flags, + prec, c, &pbuf, &ilen); + len = ilen; + if (!temp) + goto error; + sign = 1; + } + else { + pbuf = formatbuf; + len = formatint(pbuf, + sizeof(formatbuf), + flags, prec, c, v); + if (len < 0) + goto error; + sign = 1; + } + if (flags & F_ZERO) + fill = '0'; +#endif + return format_DUMMY(fieldobj, fs); #if 0 PyObject *intobj; PyObject *strobj; @@ -884,55 +932,64 @@ } static int -convert_exponent(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_exponent(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_exponentUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_exponentUC(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_fixed(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_fixed(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_fixedUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_fixedUC(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_general(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_general(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_generalUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_generalUC(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_number(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_number(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_octal(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_octal(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_repr(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_repr(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { int ok; PyObject *strobj; @@ -945,14 +1002,16 @@ strobj = STROBJ_STR(reprobj); Py_DECREF(reprobj); - ok = output_string_chars(fs, STROBJ_AS_PTR(strobj), STROBJ_GET_SIZE(strobj), format); + ok = output_string_chars(fs, STROBJ_AS_PTR(strobj), + STROBJ_GET_SIZE(strobj), format); Py_DECREF(strobj); return ok; } static int -convert_string(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_string(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { PyObject *strobj; int ok; @@ -961,54 +1020,58 @@ if (strobj == NULL) return 0; - ok = output_string_chars(fs, STROBJ_AS_PTR(strobj), STROBJ_GET_SIZE(strobj), format); + ok = output_string_chars(fs, STROBJ_AS_PTR(strobj), + STROBJ_GET_SIZE(strobj), format); Py_DECREF(strobj); return ok; } static int -convert_hex(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_hex(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_hexUC(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_hexUC(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } static int -convert_percentage(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) +format_percentage(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { - return convert_DUMMY(fieldobj, fs); + return format_DUMMY(fieldobj, fs); } /* returns a pointer to our conversion function, or NULL if invalid */ -Py_LOCAL_INLINE(ConversionFunction) -conversion_function(CH_TYPE c) +Py_LOCAL_INLINE(FormatFunction) +format_function(CH_TYPE c) { switch (c) { - case 'b': return convert_binary; /* base-2 */ - case 'c': return convert_char; /* as character */ - case 'd': return convert_decimal; /* decimal integer */ - case 'e': return convert_exponent; /* exponential notation */ - case 'E': return convert_exponentUC; /* exponential notation - with uppercase 'E' */ - case 'f': return convert_fixed; /* fixed-point */ - case 'F': return convert_fixedUC; /* fixed-point with uppercase */ - case 'g': return convert_general; /* general number notation */ - case 'G': return convert_generalUC; /* general number notation - with uppercase 'E' */ - case 'n': return convert_number; /* number in locale-specific - format */ - case 'o': return convert_octal; /* octal */ - case 'r': return convert_repr; /* in repr() format */ - case 's': return convert_string; /* convert using str() */ - case 'x': return convert_hex; /* base 16 */ - case 'X': return convert_hexUC; /* base 16 uppercase */ - case '%': return convert_percentage; /* as percentage */ + case 'b': return format_binary; /* base-2 */ + case 'c': return format_char; /* as character */ + case 'd': return format_decimal; /* decimal integer */ + case 'e': return format_exponent; /* exponential notation */ + case 'E': return format_exponentUC; /* exponential notation + with uppercase 'E' */ + case 'f': return format_fixed; /* fixed-point */ + case 'F': return format_fixedUC; /* fixed-point with uppercase */ + case 'g': return format_general; /* general number notation */ + case 'G': return format_generalUC; /* general number notation + with uppercase 'E' */ + case 'n': return format_number; /* number in locale-specific + format */ + case 'o': return format_octal; /* octal */ + case 'r': return format_repr; /* in repr() format */ + case 's': return format_string; /* convert using str() */ + case 'x': return format_hex; /* base 16 */ + case 'X': return format_hexUC; /* base 16 uppercase */ + case '%': return format_percentage; /* as percentage */ default: return NULL; } @@ -1020,7 +1083,7 @@ static int internal_render(FmtState *fs, PyObject *fieldobj) { InternalFormatSpec format; - ConversionFunction conversion; + FormatFunction formatter; if (!parse_internal_render_format_spec(fs, &format)) { return 0; @@ -1038,18 +1101,18 @@ } } - /* XXX handle conversion functions that logically map to - other conversion functions? percent is the only one, and I'm not wild + /* XXX handle conversion functions that logically map to other + conversion functions? percent is the only one, and I'm not wild about having percent at all*/ - conversion = conversion_function(format.type); - if (conversion == NULL) { + formatter = format_function(format.type); + if (formatter == NULL) { SetError(fs, "Invalid conversion character"); return 0; } - /* do the conversion, writing into the output string */ - return conversion(fieldobj, fs, &format); + /* do the formatting, writing into the output string */ + return formatter(fieldobj, fs, &format); #if 0 From python-checkins at python.org Sat Mar 3 01:42:19 2007 From: python-checkins at python.org (brett.cannon) Date: Sat, 3 Mar 2007 01:42:19 +0100 (CET) Subject: [Python-checkins] r54101 - peps/trunk/pep-0000.txt peps/trunk/pep-3113.txt Message-ID: <20070303004219.127141E4010@bag.python.org> Author: brett.cannon Date: Sat Mar 3 01:42:09 2007 New Revision: 54101 Added: peps/trunk/pep-3113.txt (contents, props changed) Modified: peps/trunk/pep-0000.txt Log: Add PEP 3113 (Removal of Tuple Parameter Unpacking). Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Sat Mar 3 01:42:09 2007 @@ -114,6 +114,8 @@ S 3101 Advanced String Formatting Talin S 3104 Access to Names in Outer Scopes Yee I 3108 Standard Library Reorganization Cannon + S 3113 Removal of Tuple Parameter Unpacking Cannon + Finished PEPs (done, implemented in Subversion) @@ -457,6 +459,8 @@ SA 3110 Catching Exceptions in Python 3000 Winter SA 3111 Simple input built-in in Python 3000 Roberge SA 3112 Bytes literals in Python 3000 Orendorff + S 3113 Removal of Tuple Parameter Unpacking Cannon + Key Added: peps/trunk/pep-3113.txt ============================================================================== --- (empty file) +++ peps/trunk/pep-3113.txt Sat Mar 3 01:42:09 2007 @@ -0,0 +1,266 @@ +PEP: 3113 +Title: Removal of Tuple Parameter Unpacking +Version: $Revision$ +Last-Modified: $Date$ +Author: Brett Cannon +Status: Draft +Type: Standards Track +Python-version: 3.0 +Content-Type: text/x-rst +Created: XX-XXX-XXXX + + +Abstract +======== + +Tuple parameter unpacking is the use of a tuple as a parameter in a +function signature so as to have a sequence argument automatically +unpacked. An example is:: + + def fxn(a, (b, c), d): + pass + +The use of ``(b, c)`` in the signature requires that the second +argument to the function be a sequence of length two (e.g., +``[42, -13]``). When such a sequence is passed it is unpacked and +has its values assigned to the parameters, just as if the statement +``b, c = [42, -13]`` had been executed in the parameter. + +Unfortunately this feature of Python's rich function signature +abilities, while handy in some situations, causes more issues than +they are worth. Thus this PEP proposes their removal from the +language in Python 3.0. + + +Why They Should Go +================== + +Introspection Issues +-------------------- + +Python has very powerful introspection capabilities. These extend to +function signatures. There are no hidden details as to what a +function's call signature is. In general it is fairly easy to figure +out various details about a function's signature by viewing the +function object and various attributes on it (including the function's +``func_code`` attribute). + +But there is great difficulty when it comes to tuple parameters. The +existence of a tuple parameter is denoted by it name being made of a +``.`` and a number in the ``co_varnames`` attribute of the function's +code object. This allows the tuple argument to be bound to a name +that only the bytecode is aware of and cannot be typed in Python +source. But this does not specify the format of the tuple: its +length, whether there are nested tuples, etc. + +In order to get all of the details about the tuple from the function +one must analyse the bytecode of the function. This is because the +first bytecode in the function literally translates into the tuple +argument being unpacked. Assuming the tuple parameter is +named ``.1`` and is expected to unpack to variables ``spam`` and +``monty`` (meaning it is the tuple ``(spam, monty)``), the first +bytecode in the function will be for the statement +``spam, monty = .1``. This means that to know all of the details of +the tuple parameter one must look at the initial bytecode of the +function to detect tuple unpacking for parameters formatted as +``\.\d+`` and deduce any and all information about the expected +argument. Bytecode analysis is how the ``inspect.getargspec`` +function is able to provide information on tuple parameters. This is +not easy to do and is burdensome on introspection tools as they must +know how Python bytecode works (an otherwise unneeded burden as all +other types of parameters do not require knowledge of Python +bytecode). + +The difficulty of analysing bytecode not withstanding, there is +another issue with the dependency on using Python bytecode. +IronPython [#ironpython]_ does not use Python's bytecode. Because it +is based on the .NET framework it instead stores MSIL [#MSIL]_ in +``func_code.co_code`` attribute of the function. This fact prevents +the ``inspect.getargspec`` function from working when run under +IronPython. It is unknown whether other Python implementations are +affected but is reasonable to assume if the implementation is not just +a re-implementation of the Python virtual machine. + + +No Loss of Abilities If Removed +------------------------------- + +As mentioned in `Introspection Issues`_, to handle tuple parameters +the function's bytecode starts with the bytecode required to unpack +the argument into the proper parameter names. This means that their +is no special support required to implement tuple parameters and thus +there is no loss of abilities if they were to be removed, only a +possible convenience (which is addressed in +`Why They Should (Supposedly) Stay`_). + +The example function at the beginning of this PEP could easily be +rewritten as:: + + def fxn(a, b_c, d): + b, c = b_c + pass + +and in no way lose functionality. + + +Exception To The Rule +--------------------- + +When looking at the various types of parameters that a Python function +can have, one will notice that tuple parameters tend to be an +exception rather than the rule. + +Consider PEP 3102 (keyword-only arguments) and PEP 3107 (function +annotations) [#pep-3102]_ [#pep-3107]_. Both PEPs have been accepted and +introduce new functionality within a function's signature. And yet +for both PEPs the new feature cannot be applied to tuple parameters. +This leads to tuple parameters not being on the same footing as +regular parameters that do not attempt to unpack their arguments. + +The existence of tuple parameters also places sequence objects +separately from mapping objects in a function signature. There is no +way to pass in a mapping object (e.g., a dict) as a parameter and have +it unpack in the same fashion as a sequence does into a tuple +parameter. + + +Uninformative Error Messages +---------------------------- + +Consider the following function:: + + def fxn((a, b), (c, d)): + pass + +If called as ``fxn(1, (2, 3))`` one is given the error message +``TypeError: unpack non-sequence``. This error message in no way +tells you which tuple was not unpacked properly. There is also no +indication that this was a result that occurred because of the +arguments. Other error messages regarding arguments to functions +explicitly state its relation to the signature: +``TypeError: fxn() takes exactly 2 arguments (0 given)``, etc. + + +Little Usage +------------ + +While an informal poll of the handful of Python programmers I know +personally and from the PyCon 2007 sprint indicates a huge majority of +people do not know of this feature and the rest just do not use it, +some hard numbers is needed to back up the claim that the feature is +not heavily used. + +Iterating over every line in Python's code repository in the ``Lib/`` +directory using the regular expression ``^\s*def\s*\w+\s*\(`` to +detect function and method definitions there were 22,252 matches in +the trunk. + +Tacking on ``.*,\s*\(`` to find ``def`` statements that contained a +tuple parameter, only 41 matches were found. This means that for +``def`` statements, only 0.18% of them seem to use a tuple parameter. + + +Why They Should (Supposedly) Stay +================================= + +Practical Use +------------- + +In certain instances tuple parameters can be useful. A common example +is code that expect a two-item tuple that reperesents a Cartesian +point. While true it is nice to be able to have the unpacking of the +x and y coordinates for you, the argument is that this small amount of +practical usefulness is heavily outweighed by other issues pertaining +to tuple parameters. And as shown in +`No Loss Of Abilities If Removed`_, their use is purely practical and +in no way provide a unique ability that cannot be handled in other +ways very easily. + + +Self-Documentation For Parameters +--------------------------------- + +It has been argued that tuple parameters provide a way of +self-documentation for parameters that are expected to be of a certain +sequence format. Using our Cartesian point example from +`Practical Use`_, seeing ``(x, y)`` as a parameter in a function makes +it obvious that a tuple of length two is expected as an argument for +that parameter. + +But Python provides several other ways to document what parameters are +for. Documentation strings are meant to provide enough information +needed to explain what arguments are expected. Tuple parameters might +tell you the expected length of a sequence argument, it does not tell +you what that data will be used for. One must also read the docstring +to know what other arguments are expected if not all parameters are +tuple parameters. + +Function annotations (which do not work with tuple parameters) can +also supply documentation. Because annotations can be of any form, +what was once a tuple parameter can be a single argument parameter +with an annotation of ``tuple``, ``tuple(2)``, ``Cartesian point``, +``(x, y)``, etc. Annotations provide great flexibility for +documenting what an argument is expected to be for a parameter, +including being a sequence of a certain length. + + +Transition Plan +=============== + +To transition Python 2.x code to 3.x where tuple parameters are +removed, two steps are suggested. First, the proper warning is to be +emitted when Python's compiler comes across a tuple parameter in +Python 2.6. This will be treated like any other syntactic change that +is to occur in Python 3.0 compared to Python 2.6. + +Second, the 2to3 refactoring tool [#2to3]_ will gain a rule for +translating tuple parameters to being a single parameter this is +unpacked as the first statement in the function. The name of the new +parameter will be a mangling of tuple parameter's names by joining +them with underscores. The new parameter will then be unpacked into +the names originally used in the tuple parameter. This means that the +following function:: + + def fxn((a, (b, c))): + pass + +will be translated into:: + + def fxn(a_b_c): + (a, (b, c)) = a_b_c + pass + + +References +========== + +.. [#2to3] 2to3 refactoring tool + (http://svn.python.org/view/sandbox/trunk/2to3/) + +.. [#ironpython] IronPython + (http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython) + +.. [#MSIL] Microsoft Intermediate Language + (http://msdn.microsoft.com/library/en-us/cpguide/html/cpconmicrosoftintermediatelanguagemsil.asp?frame=true) + +.. [#pep-3102] PEP 3102 (Keyword-Only Arguments) + (http://www.python.org/dev/peps/pep-3102/) + +.. [#pep-3107] PEP 3107 (Function Annotations) + (http://www.python.org/dev/peps/pep-3107/) + +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 + coding: utf-8 + End: From python-checkins at python.org Sat Mar 3 01:46:17 2007 From: python-checkins at python.org (brett.cannon) Date: Sat, 3 Mar 2007 01:46:17 +0100 (CET) Subject: [Python-checkins] r54102 - peps/trunk/pep-3113.txt Message-ID: <20070303004617.42D221E4008@bag.python.org> Author: brett.cannon Date: Sat Mar 3 01:46:14 2007 New Revision: 54102 Modified: peps/trunk/pep-3113.txt Log: Fix the creation date. Modified: peps/trunk/pep-3113.txt ============================================================================== --- peps/trunk/pep-3113.txt (original) +++ peps/trunk/pep-3113.txt Sat Mar 3 01:46:14 2007 @@ -7,7 +7,7 @@ Type: Standards Track Python-version: 3.0 Content-Type: text/x-rst -Created: XX-XXX-XXXX +Created: 02-Mar-2007 Abstract From python-checkins at python.org Sat Mar 3 04:27:44 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 3 Mar 2007 04:27:44 +0100 (CET) Subject: [Python-checkins] r54103 - sandbox/trunk/2to3/fixes/fix_except.py Message-ID: <20070303032744.093941E4008@bag.python.org> Author: collin.winter Date: Sat Mar 3 04:27:43 2007 New Revision: 54103 Modified: sandbox/trunk/2to3/fixes/fix_except.py Log: Style cleanup. Modified: sandbox/trunk/2to3/fixes/fix_except.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_except.py (original) +++ sandbox/trunk/2to3/fixes/fix_except.py Sat Mar 3 04:27:43 2007 @@ -30,8 +30,7 @@ from fixes.macros import Assign, Attr, Name def find_excepts(nodes): - for i in range(len(nodes)): - n = nodes[i] + for i, n in enumerate(nodes): if isinstance(n, pytree.Node): if n.children[0].value == 'except': yield (n, nodes[i+2]) From python-checkins at python.org Sat Mar 3 05:03:51 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 3 Mar 2007 05:03:51 +0100 (CET) Subject: [Python-checkins] r54104 - in sandbox/trunk/2to3: fixes/fix_arg_tuples.py tests/test_fixers.py Message-ID: <20070303040351.1BB001E4008@bag.python.org> Author: collin.winter Date: Sat Mar 3 05:03:44 2007 New Revision: 54104 Added: sandbox/trunk/2to3/fixes/fix_arg_tuples.py (contents, props changed) Modified: sandbox/trunk/2to3/tests/test_fixers.py Log: Add a fixer for tuple parameters (per PEP 3113). Added: sandbox/trunk/2to3/fixes/fix_arg_tuples.py ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/fixes/fix_arg_tuples.py Sat Mar 3 05:03:44 2007 @@ -0,0 +1,86 @@ +"""Fixer for function definitions with tuple parameters. + +def func(((a, b), c), d): + ... + + -> + +def func(x, d): + ((a, b), c) = x + ... +""" +# Author: Collin Winter + +# Local imports +import pytree +from pgen2 import token +from fixes import basefix +from fixes.macros import Assign, Name, Newline + +def is_docstring(stmt): + return isinstance(stmt, pytree.Node) and \ + stmt.children[0].type == token.STRING + +class FixArgTuples(basefix.BaseFix): + PATTERN = """funcdef< 'def' any parameters< '(' args=any ')' > + ['->' any] ':' suite=any+ >""" + + def transform(self, node): + syms = self.syms + results = self.match(node) + assert results + + new_lines = [] + suite = results["suite"] + args = results["args"] + # This crap is so "def foo(...): x = 5; y = 7" is handled correctly. + if suite[0].children[1].type == token.INDENT: + start = 2 + indent = suite[0].children[1].value + end = Newline() + else: + start = 0 + indent = "; " + end = pytree.Leaf(token.INDENT, "") + + # We need access to self for new_name(), and making this a method + # doesn't feel right. Closing over self and new_lines makes the + # code below cleaner. + def handle_tuple(tuple_arg, add_prefix=False): + n = Name(self.new_name()) + arg = tuple_arg.clone() + arg.set_prefix("") + stmt = Assign(arg, n.clone()) + if add_prefix: + n.set_prefix(" ") + tuple_arg.replace(n) + new_lines.append(pytree.Node(syms.simple_stmt, [stmt, end.clone()])) + + if args.type == syms.tfpdef: + handle_tuple(args) + elif args.type == syms.typedargslist: + for i, arg in enumerate(args.children): + if arg.type == syms.tfpdef: + # Without add_prefix, the emitted code is correct, + # just ugly. + handle_tuple(arg, add_prefix=(i > 0)) + + if not new_lines: + return node + + # This isn't strictly necessary, but it plays nicely with other fixers. + for line in new_lines: + line.parent = suite[0] + + after = start + if start == 0: + new_lines[0].set_prefix(" ") + elif is_docstring(suite[0].children[start]): + new_lines[0].set_prefix(indent) + after = start + 1 + + children = list(suite[0].children) + children[after:after] = new_lines + for i in range(after+1, after+len(new_lines)+1): + children[i].set_prefix(indent) + suite[0].children = tuple(children) Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Sat Mar 3 05:03:44 2007 @@ -496,8 +496,8 @@ def foo(): try: pass - except Exception as xxx_todo_changeme: - (f, e) = xxx_todo_changeme.message + except Exception as xxx_todo_changeme12: + (f, e) = xxx_todo_changeme12.message pass except ImportError as e: pass""" @@ -527,8 +527,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme1: - (a, b) = xxx_todo_changeme1.message + except Exception as xxx_todo_changeme13: + (a, b) = xxx_todo_changeme13.message pass""" self.check(b, a) @@ -542,8 +542,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme2: - d[5] = xxx_todo_changeme2 + except Exception as xxx_todo_changeme14: + d[5] = xxx_todo_changeme14 pass""" self.check(b, a) @@ -557,8 +557,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme3: - a.foo = xxx_todo_changeme3 + except Exception as xxx_todo_changeme15: + a.foo = xxx_todo_changeme15 pass""" self.check(b, a) @@ -572,8 +572,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme4: - a().foo = xxx_todo_changeme4 + except Exception as xxx_todo_changeme16: + a().foo = xxx_todo_changeme16 pass""" self.check(b, a) @@ -1111,6 +1111,123 @@ b = """x = input('prompt')""" a = """x = eval(input('prompt'))""" self.check(b, a) + + +class Test_arg_tuples(FixerTestCase): + fixer = "arg_tuples" + + def test_unchanged_1(self): + s = """def foo(): pass""" + self.check(s, s) + + def test_unchanged_2(self): + s = """def foo(a, b, c): pass""" + self.check(s, s) + + def test_unchanged_3(self): + s = """def foo(a=3, b=4, c=5): pass""" + self.check(s, s) + + def test_1(self): + b = """ + def foo(((a, b), c)): + x = 5""" + + a = """ + def foo(xxx_todo_changeme): + ((a, b), c) = xxx_todo_changeme + x = 5""" + self.check(b, a) + + def test_2(self): + b = """ + def foo(((a, b), c), d): + x = 5""" + + a = """ + def foo(xxx_todo_changeme1, d): + ((a, b), c) = xxx_todo_changeme1 + x = 5""" + self.check(b, a) + + def test_3(self): + b = """ + def foo(((a, b), c), d) -> e: + x = 5""" + + a = """ + def foo(xxx_todo_changeme2, d) -> e: + ((a, b), c) = xxx_todo_changeme2 + x = 5""" + self.check(b, a) + + def test_semicolon(self): + b = """ + def foo(((a, b), c)): x = 5; y = 7""" + + a = """ + def foo(xxx_todo_changeme10): ((a, b), c) = xxx_todo_changeme10; x = 5; y = 7""" + self.check(b, a) + + def test_keywords(self): + b = """ + def foo(((a, b), c), d, e=5) -> z: + x = 5""" + + a = """ + def foo(xxx_todo_changeme5, d, e=5) -> z: + ((a, b), c) = xxx_todo_changeme5 + x = 5""" + self.check(b, a) + + def test_varargs(self): + b = """ + def foo(((a, b), c), d, *vargs, **kwargs) -> z: + x = 5""" + + a = """ + def foo(xxx_todo_changeme11, d, *vargs, **kwargs) -> z: + ((a, b), c) = xxx_todo_changeme11 + x = 5""" + self.check(b, a) + + def test_multi_1(self): + b = """ + def foo(((a, b), c), (d, e, f)) -> z: + x = 5""" + + a = """ + def foo(xxx_todo_changeme6, xxx_todo_changeme7) -> z: + ((a, b), c) = xxx_todo_changeme6 + (d, e, f) = xxx_todo_changeme7 + x = 5""" + self.check(b, a) + + def test_multi_2(self): + b = """ + def foo(x, ((a, b), c), d, (e, f, g), y) -> z: + x = 5""" + + a = """ + def foo(x, xxx_todo_changeme8, d, xxx_todo_changeme9, y) -> z: + ((a, b), c) = xxx_todo_changeme8 + (e, f, g) = xxx_todo_changeme9 + x = 5""" + self.check(b, a) + + def test_docstring(self): + b = """ + def foo(((a, b), c), (d, e, f)) -> z: + "foo foo foo foo" + x = 5""" + + a = """ + def foo(xxx_todo_changeme3, xxx_todo_changeme4) -> z: + "foo foo foo foo" + ((a, b), c) = xxx_todo_changeme3 + (d, e, f) = xxx_todo_changeme4 + x = 5""" + self.check(b, a) if __name__ == "__main__": From python-checkins at python.org Sat Mar 3 05:19:14 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 3 Mar 2007 05:19:14 +0100 (CET) Subject: [Python-checkins] r54105 - in sandbox/trunk/2to3: fixes/fix_arg_tuples.py fixes/fix_tuple_params.py tests/test_fixers.py Message-ID: <20070303041914.EA11D1E4008@bag.python.org> Author: collin.winter Date: Sat Mar 3 05:19:11 2007 New Revision: 54105 Added: sandbox/trunk/2to3/fixes/fix_tuple_params.py - copied, changed from r54104, sandbox/trunk/2to3/fixes/fix_arg_tuples.py Removed: sandbox/trunk/2to3/fixes/fix_arg_tuples.py Modified: sandbox/trunk/2to3/tests/test_fixers.py Log: Rename tests/fix_arg_tuples.py; they're called tuple parameters, not tuple arguments. Deleted: /sandbox/trunk/2to3/fixes/fix_arg_tuples.py ============================================================================== --- /sandbox/trunk/2to3/fixes/fix_arg_tuples.py Sat Mar 3 05:19:11 2007 +++ (empty file) @@ -1,86 +0,0 @@ -"""Fixer for function definitions with tuple parameters. - -def func(((a, b), c), d): - ... - - -> - -def func(x, d): - ((a, b), c) = x - ... -""" -# Author: Collin Winter - -# Local imports -import pytree -from pgen2 import token -from fixes import basefix -from fixes.macros import Assign, Name, Newline - -def is_docstring(stmt): - return isinstance(stmt, pytree.Node) and \ - stmt.children[0].type == token.STRING - -class FixArgTuples(basefix.BaseFix): - PATTERN = """funcdef< 'def' any parameters< '(' args=any ')' > - ['->' any] ':' suite=any+ >""" - - def transform(self, node): - syms = self.syms - results = self.match(node) - assert results - - new_lines = [] - suite = results["suite"] - args = results["args"] - # This crap is so "def foo(...): x = 5; y = 7" is handled correctly. - if suite[0].children[1].type == token.INDENT: - start = 2 - indent = suite[0].children[1].value - end = Newline() - else: - start = 0 - indent = "; " - end = pytree.Leaf(token.INDENT, "") - - # We need access to self for new_name(), and making this a method - # doesn't feel right. Closing over self and new_lines makes the - # code below cleaner. - def handle_tuple(tuple_arg, add_prefix=False): - n = Name(self.new_name()) - arg = tuple_arg.clone() - arg.set_prefix("") - stmt = Assign(arg, n.clone()) - if add_prefix: - n.set_prefix(" ") - tuple_arg.replace(n) - new_lines.append(pytree.Node(syms.simple_stmt, [stmt, end.clone()])) - - if args.type == syms.tfpdef: - handle_tuple(args) - elif args.type == syms.typedargslist: - for i, arg in enumerate(args.children): - if arg.type == syms.tfpdef: - # Without add_prefix, the emitted code is correct, - # just ugly. - handle_tuple(arg, add_prefix=(i > 0)) - - if not new_lines: - return node - - # This isn't strictly necessary, but it plays nicely with other fixers. - for line in new_lines: - line.parent = suite[0] - - after = start - if start == 0: - new_lines[0].set_prefix(" ") - elif is_docstring(suite[0].children[start]): - new_lines[0].set_prefix(indent) - after = start + 1 - - children = list(suite[0].children) - children[after:after] = new_lines - for i in range(after+1, after+len(new_lines)+1): - children[i].set_prefix(indent) - suite[0].children = tuple(children) Copied: sandbox/trunk/2to3/fixes/fix_tuple_params.py (from r54104, sandbox/trunk/2to3/fixes/fix_arg_tuples.py) ============================================================================== --- sandbox/trunk/2to3/fixes/fix_arg_tuples.py (original) +++ sandbox/trunk/2to3/fixes/fix_tuple_params.py Sat Mar 3 05:19:11 2007 @@ -21,7 +21,7 @@ return isinstance(stmt, pytree.Node) and \ stmt.children[0].type == token.STRING -class FixArgTuples(basefix.BaseFix): +class FixTupleParams(basefix.BaseFix): PATTERN = """funcdef< 'def' any parameters< '(' args=any ')' > ['->' any] ':' suite=any+ >""" Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Sat Mar 3 05:19:11 2007 @@ -496,8 +496,8 @@ def foo(): try: pass - except Exception as xxx_todo_changeme12: - (f, e) = xxx_todo_changeme12.message + except Exception as xxx_todo_changeme: + (f, e) = xxx_todo_changeme.message pass except ImportError as e: pass""" @@ -527,8 +527,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme13: - (a, b) = xxx_todo_changeme13.message + except Exception as xxx_todo_changeme1: + (a, b) = xxx_todo_changeme1.message pass""" self.check(b, a) @@ -542,8 +542,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme14: - d[5] = xxx_todo_changeme14 + except Exception as xxx_todo_changeme2: + d[5] = xxx_todo_changeme2 pass""" self.check(b, a) @@ -557,8 +557,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme15: - a.foo = xxx_todo_changeme15 + except Exception as xxx_todo_changeme3: + a.foo = xxx_todo_changeme3 pass""" self.check(b, a) @@ -572,8 +572,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme16: - a().foo = xxx_todo_changeme16 + except Exception as xxx_todo_changeme4: + a().foo = xxx_todo_changeme4 pass""" self.check(b, a) @@ -1113,8 +1113,8 @@ self.check(b, a) -class Test_arg_tuples(FixerTestCase): - fixer = "arg_tuples" +class Test_tuple_params(FixerTestCase): + fixer = "tuple_params" def test_unchanged_1(self): s = """def foo(): pass""" @@ -1134,8 +1134,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme): - ((a, b), c) = xxx_todo_changeme + def foo(xxx_todo_changeme5): + ((a, b), c) = xxx_todo_changeme5 x = 5""" self.check(b, a) @@ -1145,8 +1145,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme1, d): - ((a, b), c) = xxx_todo_changeme1 + def foo(xxx_todo_changeme6, d): + ((a, b), c) = xxx_todo_changeme6 x = 5""" self.check(b, a) @@ -1156,8 +1156,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme2, d) -> e: - ((a, b), c) = xxx_todo_changeme2 + def foo(xxx_todo_changeme7, d) -> e: + ((a, b), c) = xxx_todo_changeme7 x = 5""" self.check(b, a) @@ -1166,7 +1166,7 @@ def foo(((a, b), c)): x = 5; y = 7""" a = """ - def foo(xxx_todo_changeme10): ((a, b), c) = xxx_todo_changeme10; x = 5; y = 7""" + def foo(xxx_todo_changeme15): ((a, b), c) = xxx_todo_changeme15; x = 5; y = 7""" self.check(b, a) def test_keywords(self): @@ -1175,8 +1175,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme5, d, e=5) -> z: - ((a, b), c) = xxx_todo_changeme5 + def foo(xxx_todo_changeme10, d, e=5) -> z: + ((a, b), c) = xxx_todo_changeme10 x = 5""" self.check(b, a) @@ -1186,8 +1186,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme11, d, *vargs, **kwargs) -> z: - ((a, b), c) = xxx_todo_changeme11 + def foo(xxx_todo_changeme16, d, *vargs, **kwargs) -> z: + ((a, b), c) = xxx_todo_changeme16 x = 5""" self.check(b, a) @@ -1197,9 +1197,9 @@ x = 5""" a = """ - def foo(xxx_todo_changeme6, xxx_todo_changeme7) -> z: - ((a, b), c) = xxx_todo_changeme6 - (d, e, f) = xxx_todo_changeme7 + def foo(xxx_todo_changeme11, xxx_todo_changeme12) -> z: + ((a, b), c) = xxx_todo_changeme11 + (d, e, f) = xxx_todo_changeme12 x = 5""" self.check(b, a) @@ -1209,9 +1209,9 @@ x = 5""" a = """ - def foo(x, xxx_todo_changeme8, d, xxx_todo_changeme9, y) -> z: - ((a, b), c) = xxx_todo_changeme8 - (e, f, g) = xxx_todo_changeme9 + def foo(x, xxx_todo_changeme13, d, xxx_todo_changeme14, y) -> z: + ((a, b), c) = xxx_todo_changeme13 + (e, f, g) = xxx_todo_changeme14 x = 5""" self.check(b, a) @@ -1222,10 +1222,10 @@ x = 5""" a = """ - def foo(xxx_todo_changeme3, xxx_todo_changeme4) -> z: + def foo(xxx_todo_changeme8, xxx_todo_changeme9) -> z: "foo foo foo foo" - ((a, b), c) = xxx_todo_changeme3 - (d, e, f) = xxx_todo_changeme4 + ((a, b), c) = xxx_todo_changeme8 + (d, e, f) = xxx_todo_changeme9 x = 5""" self.check(b, a) From python-checkins at python.org Sat Mar 3 19:14:04 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 3 Mar 2007 19:14:04 +0100 (CET) Subject: [Python-checkins] r54107 - sandbox/trunk/pep3101/test_simpleformat.py Message-ID: <20070303181404.107431E4009@bag.python.org> Author: georg.brandl Date: Sat Mar 3 19:14:00 2007 New Revision: 54107 Modified: sandbox/trunk/pep3101/test_simpleformat.py Log: Fix the test suite for simpleformat -- the wrong method was used, and per chance it succeeded. Also, use a specific exception type for assertRaises. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Sat Mar 3 19:14:00 2007 @@ -152,15 +152,17 @@ self.formatEquals("custom", "{0:{1}}", custom, "custom") def test_syntaxerror(self): - self.assertRaises(Exception, "}{", True) - self.assertRaises(Exception, "{0", True) - self.assertRaises(Exception, "{0.[]}", True) - self.assertRaises(Exception, "{0[0}", True) - self.assertRaises(Exception, "{0[0:foo}", True) - self.assertRaises(Exception, "{c]}", True) - self.assertRaises(Exception, "{{1}}", True, 0) - self.assertRaises(Exception, "{{ {{{0}}", True) - self.assertRaises(Exception, "{0}}", True) + self.formatRaises(ValueError, "}{", True) + self.formatRaises(ValueError, "{0", True) + self.formatRaises(ValueError, "{0.[]}", True) + # XXX: these raise the wrong exceptions + #self.formatRaises(ValueError, "{0[0}", True) + #self.formatRaises(ValueError, "{0[0:foo}", True) + self.formatRaises(ValueError, "{c]}", True) + # XXX: this should *not* raise + #self.formatRaises(ValueError, "{{1}}", True, 0) + self.formatRaises(ValueError, "{{ {{{0}}", True) + self.formatRaises(ValueError, "{0}}", True) def test_main(): From python-checkins at python.org Sat Mar 3 21:21:36 2007 From: python-checkins at python.org (patrick.maupin) Date: Sat, 3 Mar 2007 21:21:36 +0100 (CET) Subject: [Python-checkins] r54108 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/setup.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070303202136.1D8281E4008@bag.python.org> Author: patrick.maupin Date: Sat Mar 3 21:21:29 2007 New Revision: 54108 Modified: sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/setup.py sandbox/trunk/pep3101/unicodeformat.c Log: Added pep_differences.txt to document initial implementation target. Updated README.txt to move info into pep_differences. Cleaned up escape-to-markup processing to fix bug and enable easy alternate syntax testing. Changed version number in setup.py to reflect the fact we're not at 1.0 yet. Modified: sandbox/trunk/pep3101/README.txt ============================================================================== --- sandbox/trunk/pep3101/README.txt (original) +++ sandbox/trunk/pep3101/README.txt Sat Mar 3 21:21:29 2007 @@ -10,12 +10,10 @@ Eric V. Smith (eric at trueblade.com) Pete Shinner -The code is only half-baked at present -(development was started at PyCon 2007 and is in progress). - -Although the PEP3101 goal is a (unicode) string format method, since -this is a sandbox, we might do a few more ambitious things as well, -to see if people like them. +The code is only half-baked at present. Development was started at +PyCon 2007 and is steadily progressing. The feature set targeted +for the initial release is documented in pep_differences.txt in +this directory. The current plan of record is to make a pep3101 extension module. It will have at least the following features: @@ -25,53 +23,43 @@ - can be compiled against 2.4, 2.5, and Py3K - Works with the string object as well as unicode -The current code has a module which is progressing nicely, and some -unittests for the current version. - Files: - - unicodeformat.c is designed to be easily added to Python - as a method of the unicode object. - - stringformat.c is a wrapper around unicodeformat.c, which - "templatizes" the entire file to make it easy to add to Python - as a method of the string object. + - loadpep.py -- Attempts to add the appropriate build directory + to the Python path, then runs the tests. + - makefile -- At least one of the developers is a Luddite who + can barely make setup.py function. - pep3101.h contains definitions for the functions in stringformat and unicodeformat - pep3101.c contains a module implementation which can be linked with these method files for testing and/or use with earlier Python versions. + - pep_differences.txt documents differences between what is + built in this directory, and the original PEP + - README.txt -- this file. - setup.py -- Use "build" option to make the extension module - test_simpleformat.py -- initial unittests - StringFormat.py -- Talin's original implementation in Python. This is only for historical interest: it doesn't exactly match the PEP or C implementation. + - stringformat.c is a wrapper around unicodeformat.c, which + "templatizes" the entire file to make it easy to add to Python + as a method of the string object. + - unicodeformat.c is designed to be easily added to Python + as a method of the unicode object. Todo: - finish up format specifier handling - document differences between PEP and implementation + (in pep_differences.txt) - Add docstrings to module - - print string offset information on certain errors - - Add _flags options - - Play with possible implementations for formatting - strings against dictionaries as well as the format - (dangerous) + - Add keyword options and string metadata options + as described in pep_differences. - Play with possible implementations for exposing lowest level format specifier handler for use in compatible template systems. - - Play with possible options for specifying additional - escape syntaxes - Should we have stricter checking on format strings? For example type "s" doesn't allow a sign character. Should specifying one be an error? - Test suite needs to check for specific exceptions. - -_flags options to consider adding: - - - useall=1 means all arguments should be used - - allow_leading_under means leading underbars allowed - - syntax=0,1,2,3 -- different syntaxes - - hook=object -- callback hook as described in PEP - - informational mode to dump exceptions into string - (as described in pep) - - max_recursion=xxx (default 4) Modified: sandbox/trunk/pep3101/setup.py ============================================================================== --- sandbox/trunk/pep3101/setup.py (original) +++ sandbox/trunk/pep3101/setup.py Sat Mar 3 21:21:29 2007 @@ -6,6 +6,6 @@ ) setup (name = 'pep3101', - version = '1.0', + version = '0.01', description = 'Extension module to implement features of PEP 3101', ext_modules = [module1]) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Sat Mar 3 21:21:29 2007 @@ -161,6 +161,8 @@ /* For some interface functions, we could have a list or tuple of dictionaries to search, e.g. locals()/globals(). */ int keywords_is_tuple; + /* Support for different escape-to-markup syntaxes */ + int syntaxmode; } FmtState; /* Some forward declarations for recursion */ @@ -1220,6 +1222,25 @@ return result; } +/* + get_field_and_render calls get_field_and_spec to get + the field object and specification, then calls + render_field to output it. +*/ +static int +get_field_and_render(FmtState *fs) +{ + PyObject *myobj; + int ok; + + fs->fieldstart = fs->fmtstr.ptr; + myobj = get_field_and_spec(fs); + ok = (myobj != NULL) && render_field(fs, myobj); + Py_XDECREF(myobj); + Py_XDECREF(fs->fieldspec.obj); + return ok; +} + /************************************************************************/ /******* Output string allocation and escape-to-markup processing ******/ /************************************************************************/ @@ -1233,52 +1254,84 @@ static int do_markup(FmtState *fs) { - PyObject *myobj; - CH_TYPE c, *start; - Py_ssize_t count, total; SubString fmtstr; - int doubled, ok; - - fmtstr = fs->fmtstr; - ok = 1; - c = '\0'; /* Avoid compiler warning */ - while (fmtstr.ptr < fmtstr.end) { - start = fmtstr.ptr; - count = total = fmtstr.end - start; - while (count && ((c = *fmtstr.ptr) != '{') && (c != '}')) { - fmtstr.ptr++; - count--; - } - fs->fieldstart = fmtstr.ptr++; - count = total - count; - total -= count; - doubled = (total > 1) && (*fmtstr.ptr == c); - if (doubled) { - output_data(fs, start, count+1); - fmtstr.ptr++; - continue; - } else if (count) - output_data(fs, start, count); - fs->fmtstr.ptr = fmtstr.ptr; - if (c == '}') { - SetError(fs, "Single } encountered"); - ok = 0; + CH_TYPE c, *start, *ptr, *end; + Py_ssize_t count; + int syntaxmode, escape; + + end = fs->fmtstr.end; + syntaxmode = fs->syntaxmode; + + while (((start = ptr = fs->fmtstr.ptr) != NULL) && (ptr < end)) { + escape = 0; + while (ptr < end) { + switch (c = *ptr++) { + case '{': + if ((syntaxmode == 2) && + ((ptr == start) || (fmtstr.ptr[-2] != '$'))) + continue; + break; + case '}': + if (syntaxmode != 0) + continue; + break; + default: + continue; + } + escape = 1; break; } - if (total < 2) { - ok = !total || - (int)SetError(fs, "Single { encountered"); - break; + count = ptr - start; + if (ptr < end) { + switch (syntaxmode) { + case 0: + if ((c == '}') && (c != *ptr)) { + fs->fmtstr.ptr = ptr; + return (int)SetError(fs, "Single } encountered"); + } + case 1: + if (c == *ptr) { + ptr++; + escape = 0; + } + else + count--; + break; + case 2: + count -= 2; + escape = !count || (fmtstr.ptr[-3] != '$'); + if (!escape) + ptr--; + break; + case 3: + switch (*ptr) { + case ' ': + ptr++; + case '\n': case '\r': + escape = 0; + break; + default: + count--; + break; + } + break; + default: + fs->fmtstr.ptr = ptr; + return (int)SetError(fs, "Unsupported syntax mode"); + } + } + else if (escape) { + fs->fmtstr.ptr = ptr; + return (int)SetError(fs, "Unexpected escape to markup"); } - myobj = get_field_and_spec(fs); - ok = (myobj != NULL) && render_field(fs, myobj); - Py_XDECREF(fs->fieldspec.obj); - Py_XDECREF(myobj); - if (!ok) - break; - fmtstr.ptr = fs->fmtstr.ptr; + + fs->fmtstr.ptr = ptr; + if (count && !output_data(fs, start, count)) + return 0; + if (escape && !get_field_and_render(fs)) + return 0; } - return ok; + return 1; } /* @@ -1350,6 +1403,7 @@ fs->positional_arg_set = 0; fs->keyword_arg_set = NULL; fs->keywords_is_tuple = 0; + fs->syntaxmode = 0; fs->do_markup = do_markup; fs->keywords = keywords; From python-checkins at python.org Sat Mar 3 21:28:36 2007 From: python-checkins at python.org (patrick.maupin) Date: Sat, 3 Mar 2007 21:28:36 +0100 (CET) Subject: [Python-checkins] r54109 - sandbox/trunk/pep3101/pep_differences.txt Message-ID: <20070303202836.94DBD1E4008@bag.python.org> Author: patrick.maupin Date: Sat Mar 3 21:28:34 2007 New Revision: 54109 Added: sandbox/trunk/pep3101/pep_differences.txt Log: Added pep_differences.txt to document initial implementation target. Updated README.txt to move info into pep_differences. Cleaned up escape-to-markup processing to fix bug and enable easy alternate syntax testing. Changed version number in setup.py to reflect the fact we're not at 1.0 yet. Added: sandbox/trunk/pep3101/pep_differences.txt ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/pep_differences.txt Sat Mar 3 21:28:34 2007 @@ -0,0 +1,299 @@ + +This file describes differences between PEP 3101 and the C implementation +in this directory, and describes the reasoning behind the differences. + +PEP3101 is a well thought out, excellent starting point for advanced string +formatting, but as one might expect, there are a few gaps in it which were +not noticed until implementation, and there are almost certainly gaps in +the implementation which will not be noticed until the code is widely used. +Fortunately, the schedule for both Python 2.6 and Python 3.0 have enough +slack in them that if we work diligently, we can widely distribute a working +implementation, not just a theoretical document, well in advance of the code +freeze dates. This should allow for a robust discussion about the merits or +drawbacks of some of the fine points of the PEP and the implementation by +people who are actually **using** the code. + +This nice schedule has made at least one of the implementers bold enough +to consider the first cut of the implementation "experimental" in the sense +that, since there is time to correct any problems, the implementation can +diverge from the PEP (in documented ways!) both for perceived flaws in +the PEP, and also to add minor enhancements. The code is being structured +so that it should be easy to subsequently modify the operation to conform +to consensus opinion. + + +GOALS: + + Replace % + +The primary goal of the advanced string formatting is to replace the % +operator. Not in a coercive fashion. The goal is to be good enough +that nobody wants to use the % operator. + + + Modular design for subfunction reuse + +The PEP explicitly disclaims any attempt to replace string.Template, +concentrating exclusively on the % operator. While this narrow focus +is very useful in removing things like conditionals and looping from +the discussion about the PEP, it ignores the reality that it might +be useful to REUSE some of the C implementation code (particularly +the per-field formatting) in templating systems. So the design of +the implementation adds the goal of being able to expose some lower- +level functions. + + + Efficiency + +It is not claimed that the initial implementation is particularly +efficient, but it is desirable to tweak the specification in such +a fashion that an efficient implementation IS possible. Since the +goal is to replace the % operator, it is particularly important +that the formatting of small strings is not prohibitively expensive. + + + Security + +Security is a stated goal of the PEP, with an apparent goal of being +able to accept a string from J. Random User and format it without +potential adverse consequences. This may or may not be an achievable +goal; the PEP certainly has some features that should help with this +such as the restricted number of operators, and the implemetation has +some additional features, such as not allowing leading underscores +on attributes by default, but these may be attempts to solve an +intractable problem, similar to the original restricted Python +execution mode. + +In any case, security is a goal, and anything reasonable we can do to +support it should be done. Unreasonable things to support security +include things which would be very costly in terms of execution time, +and things which rely on the by now very much discredited "security +through obscurity" approach. + + + Older Python Versions + +Some of the implementers have very strong desires to use this formatting +on older Python versions, and Guido has mentioned that any 3.0 features +which do not break backward compatibility are potential candidates for +inclusion in 2.6. + + + No global state + +The PEP states "The string formatting system has two error handling modes, +which are controlled by the value of a class variable." As has been +discussed on the developer's list, this might be problematic, especially in +large systems where components are being aggregated from multiple sources. +One component might deliberately throw and catch exceptions in the string +processing, and disabling this on a global basis might cause this component +to stop working properly. If the ability to control this on a global +basis is desirable, it is easy enough to add in later, but if it is not +desirable, then deciding that after the fact and changing the code could +break code which has grown to rely on the feature. + + +FORMATTING METADATA + +The basic desired operation of the PEP is to be able to write: + + 'some format control string'.format(param1, param2, keyword1=whatever, ...) + +Unfortunately, there needs to be some mechanism to handle out of band +data for some formatting and error handling options. This could +be really costly, if multiple options are looked up in the **keywords +on every single call on even short strings, so some tweaks on the +initial implementation are designed to reduce the overhead of looking +up metadata. Two techniques are used: + + 1) Lazy evaluation where possible. For example, the code does not + need to look up error-handling options until an error occurs. + + 2) Metadata embedded in the string where appropriate. This + saves a dictionary lookup on every call. However this + is only appropriate when (a) the metadata arguably relates + to the actual control string and not the function where it + is being used; and (b) there are no security implications. + + +DIFFERENCES BETWEEN PEP AND INITIAL IMPLEMENTATION: + + Support for old Python versions + +The original PEP is Python 3000 only, which implies a lack of regular +string support (unicode only). To make the code compatible with 2.6, +it has been written to support regular strings as well, and to make +the code compatible with earlier versions, it has been written to be +usable as an extension module as well as/instead of as a string method: + + from pep3101 import format + format('control string', parameter1, ...) + + + format_item function + +A large portion of the code in the new advanced formatter is the code +which formats a single field according to the given format specifier. +(Thanks, Eric!) This code is useful on its own, especially for template +systems or other custom formatting solutions. The initial implementation +will have a format_item function which takes a format specifier and a +single object and returns a formatted result for that object and specifier. + + + comments + +The PEP does not have a mechanism for comments embedded in the format +strings. The usefulness of comments inside format strings may be +debatable, but the implementation is easy and easy to understand: + + {#This is a comment} + + + errors and exceptions + +The PEP defines a global flag for "strict" or "lenient" mode. The +implementation eschews the use of a global flag (see more information +in the goals section, above), and splits out the various error +features discussed by the PEP into different options. It also adds +an option. + +The first error option is controlled by the optional _leading_underscores +keyword argument. If this is present and evaluates non-zero, then leading +underscores are allowed on identifiers and attributes in the format string. +The implementation will lazily look for this argument the first time it +encounters a leading underscore. + +The next error option is controlled by metadata embedded in the string. +If "{!useall}" appears in the string, then a check is made that all +arguments are converted. The decision to embed this metadata in the +string can certainly be changed later; the reasons for doing it this +way in the initial implementation are as follows: + + 1) In the original % operator, the error reporting that an + extra argument is present is orthogonal to the error reporting + that not enough arguments are present. Both these errors are + easy to commit, because it is hard to count arguments and %s, + etc. In theory, the new string formatting should make it easier + to get the arguments right, because all arguments in the format + string are numbered or even named. + + 2) It is arguably not Pythonic to check that all arguments to + a function are actually used by the execution of the function, + and format() is, after all, just another function. So it seems + that the default should be to not check that all the arguments + are used. In fact, there are similar reasons for not using + all the arguments here as with any other function. For example, + for customization, the format method of a string might be called + with a superset of all the information which might be useful to + view. + + 3) Assuming that the normal case is to not check all arguments, + it is much cheaper (especially for small strings) to notice + the {! and process the metadata in the strings that want it + than it is to look for a keyword argument for every string. + +XXX -- need to add info on displaying exceptions in string vs. passing +them up for looked-up errors. Also adding or not of string position +information. + + + Getattr and getindex rely on underlying object exceptions + +For attribute and index lookup, the PEP specifies that digits will be +treated as numeric values, and non-digits should be valid Python +identifiers. The implementation does not rigorously enforce this, +instead deferring to the object's getattr or getindex to throw an +exception for an invalid lookup. The only time this is not true +is for leading underscores, which are disallowed by default. + + + User-defined Python format function + +The PEP specifies that an additional string method, cformat, can be +used to call the same formatting machinery, but with a "hook" function +that can intercept formatting on a per-field basis. + +The implementation does not have an additional cformat function/method. +Instead, user format hooks are accomplished as follows: + + 1) A format hook function, with call signature and semantics + as described in the PEP, may be passed to format() as the + keyword argument _hook. This argument will be lazily evaluated + the first time it is needed. + + 2) If "{!hook}" appears in the string, then the hook function + will be called on every single format field. + + 3) If the last character (the type specifier) in a format field + is "h" (for hook) then the hook function will be called for + that field, even if "{!hook}" has not been specified. + + + User-specified dictionary + +The call machinery to deal with keyword arguments is quite expensive, +especially for large numbers of arguments. For this reason, the +implementation supports the ability to pass in a dictionary as the +_dict argument. The _dict argument will be lazily retrieved the first +time the template requests a named parameter which was not passed +in as a keyword argument. + + + Name mapping + +To support the user-specified dictionary, a name mapper will first +look up names in the passed keywords arguments, then in the passed +_dict (if any). + + + Automatic locals/globals lookup + +This is likely to be a contentious feature, but it seems quite useful, +so in it goes for the initial implementation. For security reasons, +this happens only if format() is called with no parameters. Since +the whole purpose of format() is to apply parameters to a string, +a call to format() without any parameters would otherwise be a +silly thing to do. We can turn this degenerate case into something +useful by using the caller's locals and globals. An example from +Ian Bicking: + + assert x < 3, "x has the value of {x} (should be < 3)".format() + + + Syntax modes + +The PEP correctly notes that the mechanism used to delineate markup +vs. text is likely to be one of the most controversial features, +and gives reasons why the chosen mechanism is better than others. + +The chosen mechanism is quite readable and reasonable, but different +problem domains might have differing requirements. For example, +C code generated using the current mechanism could get quite ugly +with a large number of "{" and "}" characters. + +The initial implementation supports the notion of different syntax +modes. This is bad from the "more than one way to do it" perspective, +but is not quite so bad if the template itself has to indicate if it +is not using the default mechanism. To give reviewers an idea of +how this could work, the implementation supports 4 different modes: + + "{!syntax0}" -- the mode as described in the PEP + "{!syntax1}" -- same as mode 0, except close-braces + do not need to be doubled + "{!syntax2}" -- Uses "${" for escape to markup, "$${" for + literal "${" + "{!syntax3}" -- Like syntax0 "{" for escape to markup, + except literal "{" is denoted by "{ " + or "{\n" (where the space is removed but + the newline isn't). + + + Syntax for metadata in strings + +There have been several examples in this document of metadata +embedded inside strings, for "hook", "useall", and "syntax". + +The basic metadata syntax is "{!}", however to allow +more readable templates, in this case, if the "}" is immediately +followed by "\n" or "\r\n", this whitespace will not appear in +the formatted output. From python-checkins at python.org Sat Mar 3 23:09:15 2007 From: python-checkins at python.org (brett.cannon) Date: Sat, 3 Mar 2007 23:09:15 +0100 (CET) Subject: [Python-checkins] r54110 - peps/trunk/pep-3113.txt Message-ID: <20070303220915.0C1561E4008@bag.python.org> Author: brett.cannon Date: Sat Mar 3 23:09:12 2007 New Revision: 54110 Modified: peps/trunk/pep-3113.txt Log: Fix minor typo (thanks, Terry Reedy). Modified: peps/trunk/pep-3113.txt ============================================================================== --- peps/trunk/pep-3113.txt (original) +++ peps/trunk/pep-3113.txt Sat Mar 3 23:09:12 2007 @@ -214,7 +214,7 @@ is to occur in Python 3.0 compared to Python 2.6. Second, the 2to3 refactoring tool [#2to3]_ will gain a rule for -translating tuple parameters to being a single parameter this is +translating tuple parameters to being a single parameter that is unpacked as the first statement in the function. The name of the new parameter will be a mangling of tuple parameter's names by joining them with underscores. The new parameter will then be unpacked into From python-checkins at python.org Sun Mar 4 07:05:32 2007 From: python-checkins at python.org (david.goodger) Date: Sun, 4 Mar 2007 07:05:32 +0100 (CET) Subject: [Python-checkins] r54111 - peps/trunk/pep-3112.txt Message-ID: <20070304060532.0DB351E4015@bag.python.org> Author: david.goodger Date: Sun Mar 4 07:05:29 2007 New Revision: 54111 Modified: peps/trunk/pep-3112.txt Log: fixed markup; added PEP number to header Modified: peps/trunk/pep-3112.txt ============================================================================== --- peps/trunk/pep-3112.txt (original) +++ peps/trunk/pep-3112.txt Sun Mar 4 07:05:29 2007 @@ -1,4 +1,4 @@ -PEP: +PEP: 3112 Title: Bytes literals in Python 3000 Version: $Revision$ Last-Modified: $Date$ @@ -64,7 +64,7 @@ The proposed syntax is an extension of the existing string syntax. [#stringliterals]_ -The new syntax for strings, including the new bytes literal, is: +The new syntax for strings, including the new bytes literal, is:: stringliteral: [stringprefix] (shortstring | longstring) stringprefix: "b" | "r" | "br" | "B" | "R" | "BR" | "Br" | "bR" @@ -103,7 +103,7 @@ Each evaluation of a bytes literal produces a new ``bytes`` object. The bytes in the new object are the bytes represented by the -``shortstringitem``s or ``longstringitem``s in the literal, in the +``shortstringitem`` or ``longstringitem`` parts of the literal, in the same order. From python-checkins at python.org Sun Mar 4 07:05:43 2007 From: python-checkins at python.org (david.goodger) Date: Sun, 4 Mar 2007 07:05:43 +0100 (CET) Subject: [Python-checkins] r54112 - peps/trunk/pep-3100.txt Message-ID: <20070304060543.217831E4011@bag.python.org> Author: david.goodger Date: Sun Mar 4 07:05:40 2007 New Revision: 54112 Modified: peps/trunk/pep-3100.txt Log: fixed indentation errors Modified: peps/trunk/pep-3100.txt ============================================================================== --- peps/trunk/pep-3100.txt (original) +++ peps/trunk/pep-3100.txt Sun Mar 4 07:05:40 2007 @@ -143,19 +143,19 @@ literals with 'L' or 'l' suffix disappear [1]_ [done] * Make all strings be Unicode, and have a separate bytes() type [1]_ The new string type will be called 'str'. -* Return iterable views instead of lists where appropriate for atomic type methods - (e.g. ``dict.keys()``, ``dict.values()``, ``dict.items()``, etc.); iter* - methods will be removed. [done] +* Return iterable views instead of lists where appropriate for atomic + type methods (e.g. ``dict.keys()``, ``dict.values()``, + ``dict.items()``, etc.); iter* methods will be removed. [done] * Make ``string.join()`` stringify its arguments? [18]_ * Fix file() so it returns a ValueError if the mode is bad rather than IOError. (This probably affects lots of places, we should review the exceptions - and fix them if inappropriate.) + and fix them if inappropriate.) To be removed: * ``basestring.find()`` and ``basestring.rfind()``; use ``basestring.index()`` - or ``basestring.[r]partition()`` or - or ``basestring.rindex()`` in a try/except block??? [13]_ + or ``basestring.[r]partition()`` or + or ``basestring.rindex()`` in a try/except block??? [13]_ * ``file.xreadlines()`` method [#file-object]_ [done] * ``dict.setdefault()``? [15]_ * ``dict.has_key()`` method [done] From python-checkins at python.org Sun Mar 4 07:35:07 2007 From: python-checkins at python.org (david.goodger) Date: Sun, 4 Mar 2007 07:35:07 +0100 (CET) Subject: [Python-checkins] r54113 - peps/trunk/pep-3112.txt Message-ID: <20070304063507.295111E4006@bag.python.org> Author: david.goodger Date: Sun Mar 4 07:35:06 2007 New Revision: 54113 Modified: peps/trunk/pep-3112.txt Log: added Standards Track type Modified: peps/trunk/pep-3112.txt ============================================================================== --- peps/trunk/pep-3112.txt (original) +++ peps/trunk/pep-3112.txt Sun Mar 4 07:35:06 2007 @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Jason Orendorff Status: Accepted -Type: +Type: Standards Track Content-Type: text/x-rst Requires: 358 Created: 23-Feb-2007 From python-checkins at python.org Sun Mar 4 18:18:57 2007 From: python-checkins at python.org (georg.brandl) Date: Sun, 4 Mar 2007 18:18:57 +0100 (CET) Subject: [Python-checkins] r54114 - python/trunk/Lib/test/test_dict.py python/trunk/Lib/test/test_userdict.py Message-ID: <20070304171857.A76F51E4009@bag.python.org> Author: georg.brandl Date: Sun Mar 4 18:18:54 2007 New Revision: 54114 Modified: python/trunk/Lib/test/test_dict.py python/trunk/Lib/test/test_userdict.py Log: Fix a bug in test_dict and test_userdict, found at the PyPy sprint. Modified: python/trunk/Lib/test/test_dict.py ============================================================================== --- python/trunk/Lib/test/test_dict.py (original) +++ python/trunk/Lib/test/test_dict.py Sun Mar 4 18:18:54 2007 @@ -430,7 +430,7 @@ except RuntimeError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("e[42] didn't raise RuntimeError") + self.fail("e[42] didn't raise RuntimeError") class F(dict): def __init__(self): # An instance variable __missing__ should have no effect @@ -441,7 +441,7 @@ except KeyError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("f[42] didn't raise KeyError") + self.fail("f[42] didn't raise KeyError") class G(dict): pass g = G() @@ -450,7 +450,7 @@ except KeyError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("g[42] didn't raise KeyError") + self.fail("g[42] didn't raise KeyError") def test_tuple_keyerror(self): # SF #1576657 Modified: python/trunk/Lib/test/test_userdict.py ============================================================================== --- python/trunk/Lib/test/test_userdict.py (original) +++ python/trunk/Lib/test/test_userdict.py Sun Mar 4 18:18:54 2007 @@ -174,7 +174,7 @@ except RuntimeError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("e[42] didn't raise RuntimeError") + self.fail("e[42] didn't raise RuntimeError") class F(UserDict.UserDict): def __init__(self): # An instance variable __missing__ should have no effect @@ -186,7 +186,7 @@ except KeyError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("f[42] didn't raise KeyError") + self.fail("f[42] didn't raise KeyError") class G(UserDict.UserDict): pass g = G() @@ -195,7 +195,7 @@ except KeyError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("g[42] didn't raise KeyError") + self.fail("g[42] didn't raise KeyError") ########################## # Test Dict Mixin From python-checkins at python.org Sun Mar 4 18:19:04 2007 From: python-checkins at python.org (georg.brandl) Date: Sun, 4 Mar 2007 18:19:04 +0100 (CET) Subject: [Python-checkins] r54115 - python/branches/release25-maint/Lib/test/test_dict.py python/branches/release25-maint/Lib/test/test_userdict.py Message-ID: <20070304171904.56DC51E4009@bag.python.org> Author: georg.brandl Date: Sun Mar 4 18:19:02 2007 New Revision: 54115 Modified: python/branches/release25-maint/Lib/test/test_dict.py python/branches/release25-maint/Lib/test/test_userdict.py Log: Fix a bug in test_dict and test_userdict, found at the PyPy sprint. (backport from rev. 54114) Modified: python/branches/release25-maint/Lib/test/test_dict.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_dict.py (original) +++ python/branches/release25-maint/Lib/test/test_dict.py Sun Mar 4 18:19:02 2007 @@ -430,7 +430,7 @@ except RuntimeError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("e[42] didn't raise RuntimeError") + self.fail("e[42] didn't raise RuntimeError") class F(dict): def __init__(self): # An instance variable __missing__ should have no effect @@ -441,7 +441,7 @@ except KeyError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("f[42] didn't raise KeyError") + self.fail("f[42] didn't raise KeyError") class G(dict): pass g = G() @@ -450,7 +450,7 @@ except KeyError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("g[42] didn't raise KeyError") + self.fail("g[42] didn't raise KeyError") def test_tuple_keyerror(self): # SF #1576657 Modified: python/branches/release25-maint/Lib/test/test_userdict.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_userdict.py (original) +++ python/branches/release25-maint/Lib/test/test_userdict.py Sun Mar 4 18:19:02 2007 @@ -174,7 +174,7 @@ except RuntimeError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("e[42] didn't raise RuntimeError") + self.fail("e[42] didn't raise RuntimeError") class F(UserDict.UserDict): def __init__(self): # An instance variable __missing__ should have no effect @@ -186,7 +186,7 @@ except KeyError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("f[42] didn't raise KeyError") + self.fail("f[42] didn't raise KeyError") class G(UserDict.UserDict): pass g = G() @@ -195,7 +195,7 @@ except KeyError, err: self.assertEqual(err.args, (42,)) else: - self.fail_("g[42] didn't raise KeyError") + self.fail("g[42] didn't raise KeyError") ########################## # Test Dict Mixin From python-checkins at python.org Sun Mar 4 18:48:00 2007 From: python-checkins at python.org (patrick.maupin) Date: Sun, 4 Mar 2007 18:48:00 +0100 (CET) Subject: [Python-checkins] r54116 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070304174800.7408B1E4009@bag.python.org> Author: patrick.maupin Date: Sun Mar 4 18:47:54 2007 New Revision: 54116 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Removed compile warnings and bugs Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Sun Mar 4 18:47:54 2007 @@ -36,7 +36,7 @@ #define CH_TYPE char #define CH_TYPE_ISDECIMAL(x) ((x >= '0') && (x <= '9')) #define CH_TYPE_TODECIMAL(x) (CH_TYPE_ISDECIMAL(x) ? (x - '0') : -1) -#define CH_TYPE_FILL Py_UNICODE_FILL +#define CH_TYPE_FILL memset #define STROBJ_AS_PTR PyString_AS_STRING #define STROBJ_GET_SIZE PyString_GET_SIZE #define STROBJ_NEW PyString_FromStringAndSize @@ -755,7 +755,6 @@ output_string_chars(FmtState *fs, CH_TYPE *src, Py_ssize_t len, const InternalFormatSpec *format) { - Py_ssize_t ok; Py_ssize_t width; /* total field width */ CH_TYPE *dst; @@ -857,7 +856,6 @@ format_char(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - int ok; CH_TYPE buf; if (PyString_Check(fieldobj)) { @@ -1254,7 +1252,6 @@ static int do_markup(FmtState *fs) { - SubString fmtstr; CH_TYPE c, *start, *ptr, *end; Py_ssize_t count; int syntaxmode, escape; @@ -1268,7 +1265,7 @@ switch (c = *ptr++) { case '{': if ((syntaxmode == 2) && - ((ptr == start) || (fmtstr.ptr[-2] != '$'))) + ((ptr == start) || (ptr[-2] != '$'))) continue; break; case '}': @@ -1299,7 +1296,7 @@ break; case 2: count -= 2; - escape = !count || (fmtstr.ptr[-3] != '$'); + escape = !count || (ptr[-3] != '$'); if (!escape) ptr--; break; From python-checkins at python.org Sun Mar 4 20:26:52 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 4 Mar 2007 20:26:52 +0100 (CET) Subject: [Python-checkins] r54117 - peps/trunk/pep-3113.txt Message-ID: <20070304192652.E6F6E1E4007@bag.python.org> Author: brett.cannon Date: Sun Mar 4 20:26:52 2007 New Revision: 54117 Modified: peps/trunk/pep-3113.txt Log: Clarify how tuple parameters do not work with PEP 3102 and 3107. Modified: peps/trunk/pep-3113.txt ============================================================================== --- peps/trunk/pep-3113.txt (original) +++ peps/trunk/pep-3113.txt Sun Mar 4 20:26:52 2007 @@ -113,9 +113,12 @@ Consider PEP 3102 (keyword-only arguments) and PEP 3107 (function annotations) [#pep-3102]_ [#pep-3107]_. Both PEPs have been accepted and introduce new functionality within a function's signature. And yet -for both PEPs the new feature cannot be applied to tuple parameters. -This leads to tuple parameters not being on the same footing as -regular parameters that do not attempt to unpack their arguments. +for both PEPs the new feature cannot be applied to tuple parameters as +a whole. PEP 3102 has no support for tuple parameters at all (which +makes sense as there is no way to reference a tuple parameter by +name). PEP 3107 allows annotations for each item within the tuple +(e.g., ``(x:int, y:int)``), but not the whole tuple (e.g., +``(x, y):int``). The existence of tuple parameters also places sequence objects separately from mapping objects in a function signature. There is no From python-checkins at python.org Sun Mar 4 20:56:17 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 4 Mar 2007 20:56:17 +0100 (CET) Subject: [Python-checkins] r54118 - peps/trunk/pep-0000.txt peps/trunk/pep-3113.txt Message-ID: <20070304195617.CB3211E400F@bag.python.org> Author: brett.cannon Date: Sun Mar 4 20:56:13 2007 New Revision: 54118 Modified: peps/trunk/pep-0000.txt peps/trunk/pep-3113.txt Log: Mark PEP 3113 as accepted. Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Sun Mar 4 20:56:13 2007 @@ -84,6 +84,7 @@ SA 3110 Catching Exceptions in Python 3000 Winter SA 3111 Simple input built-in in Python 3000 Roberge SA 3112 Bytes literals in Python 3000 Orendorff + SA 3113 Removal of Tuple Parameter Unpacking Cannon Open PEPs (under consideration) @@ -114,7 +115,6 @@ S 3101 Advanced String Formatting Talin S 3104 Access to Names in Outer Scopes Yee I 3108 Standard Library Reorganization Cannon - S 3113 Removal of Tuple Parameter Unpacking Cannon Finished PEPs (done, implemented in Subversion) @@ -459,7 +459,7 @@ SA 3110 Catching Exceptions in Python 3000 Winter SA 3111 Simple input built-in in Python 3000 Roberge SA 3112 Bytes literals in Python 3000 Orendorff - S 3113 Removal of Tuple Parameter Unpacking Cannon + SA 3113 Removal of Tuple Parameter Unpacking Cannon Key Modified: peps/trunk/pep-3113.txt ============================================================================== --- peps/trunk/pep-3113.txt (original) +++ peps/trunk/pep-3113.txt Sun Mar 4 20:56:13 2007 @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Brett Cannon -Status: Draft +Status: Accepted Type: Standards Track Python-version: 3.0 Content-Type: text/x-rst From python-checkins at python.org Sun Mar 4 20:57:45 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 4 Mar 2007 20:57:45 +0100 (CET) Subject: [Python-checkins] r54119 - peps/trunk/pep-0000.txt peps/trunk/pep-3108.txt Message-ID: <20070304195745.62E281E4009@bag.python.org> Author: brett.cannon Date: Sun Mar 4 20:57:43 2007 New Revision: 54119 Modified: peps/trunk/pep-0000.txt peps/trunk/pep-3108.txt Log: Change the classification of PEP 3108 from Information to Standards Track since it needs acceptance and is not just explaining something. Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Sun Mar 4 20:57:43 2007 @@ -114,7 +114,7 @@ S 754 IEEE 754 Floating Point Special Values Warnes S 3101 Advanced String Formatting Talin S 3104 Access to Names in Outer Scopes Yee - I 3108 Standard Library Reorganization Cannon + S 3108 Standard Library Reorganization Cannon Finished PEPs (done, implemented in Subversion) @@ -454,7 +454,7 @@ SF 3105 Make print a function Brandl S 3106 Revamping dict.keys(), .values() and .items() GvR SA 3107 Function Annotations Winter, Lownds - I 3108 Standard Library Reorganization Cannon + S 3108 Standard Library Reorganization Cannon SA 3109 Raising Exceptions in Python 3000 Winter SA 3110 Catching Exceptions in Python 3000 Winter SA 3111 Simple input built-in in Python 3000 Roberge Modified: peps/trunk/pep-3108.txt ============================================================================== --- peps/trunk/pep-3108.txt (original) +++ peps/trunk/pep-3108.txt Sun Mar 4 20:57:43 2007 @@ -4,7 +4,7 @@ Last-Modified: $Date$ Author: Brett Cannon Status: Draft -Type: Informational +Type: Standards Track Python-Version: 3.0 Content-Type: text/x-rst Created: 01-Jan-2007 From python-checkins at python.org Sun Mar 4 20:59:37 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 4 Mar 2007 20:59:37 +0100 (CET) Subject: [Python-checkins] r54120 - peps/trunk/pep-0000.txt peps/trunk/pep-3106.txt Message-ID: <20070304195937.C35251E400D@bag.python.org> Author: brett.cannon Date: Sun Mar 4 20:59:36 2007 New Revision: 54120 Modified: peps/trunk/pep-0000.txt peps/trunk/pep-3106.txt Log: Fix up marking PEP 3106 as accepted (was already listed in the Accepted section of PEP 0). Not marking as Implemented as some Open Issues are still listed. Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Sun Mar 4 20:59:36 2007 @@ -78,7 +78,7 @@ Accepted PEPs (accepted; may not be implemented yet) SA 3102 Keyword-Only Arguments Talin - S 3106 Revamping dict.keys(), .values() and .items() GvR + SA 3106 Revamping dict.keys(), .values() and .items() GvR SA 3107 Function Annotations Winter, Lownds SA 3109 Raising Exceptions in Python 3000 Winter SA 3110 Catching Exceptions in Python 3000 Winter Modified: peps/trunk/pep-3106.txt ============================================================================== --- peps/trunk/pep-3106.txt (original) +++ peps/trunk/pep-3106.txt Sun Mar 4 20:59:36 2007 @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Guido van Rossum -Status: Draft +Status: Accepted Type: Standards Content-Type: text/x-rst Created: 19-Dec-2006 From python-checkins at python.org Sun Mar 4 21:02:58 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 4 Mar 2007 21:02:58 +0100 (CET) Subject: [Python-checkins] r54121 - peps/trunk/pep-0000.txt peps/trunk/pep-3104.txt Message-ID: <20070304200258.456CF1E400A@bag.python.org> Author: brett.cannon Date: Sun Mar 4 21:02:51 2007 New Revision: 54121 Modified: peps/trunk/pep-0000.txt peps/trunk/pep-3104.txt Log: Mark PEP 3104 as finished (implemented at PyCon 2007 sprint by Jeremy Hylton). Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Sun Mar 4 21:02:51 2007 @@ -113,7 +113,6 @@ S 362 Function Signature Object Cannon, Seo S 754 IEEE 754 Floating Point Special Values Warnes S 3101 Advanced String Formatting Talin - S 3104 Access to Names in Outer Scopes Yee S 3108 Standard Library Reorganization Cannon @@ -176,6 +175,7 @@ SF 352 Required Superclass for Exceptions GvR, Cannon SF 353 Using ssize_t as the index type von Loewis SF 357 Allowing Any Object to be Used for Slicing Oliphant + SF 3104 Access to Names in Outer Scopes Yee SF 3105 Make print a function Brandl Empty PEPs (or containing only an abstract) @@ -450,9 +450,9 @@ S 3101 Advanced String Formatting Talin SA 3102 Keyword-Only Arguments Talin SR 3103 A Switch/Case Statement GvR - S 3104 Access to Names in Outer Scopes Yee + SF 3104 Access to Names in Outer Scopes Yee SF 3105 Make print a function Brandl - S 3106 Revamping dict.keys(), .values() and .items() GvR + SA 3106 Revamping dict.keys(), .values() and .items() GvR SA 3107 Function Annotations Winter, Lownds S 3108 Standard Library Reorganization Cannon SA 3109 Raising Exceptions in Python 3000 Winter Modified: peps/trunk/pep-3104.txt ============================================================================== --- peps/trunk/pep-3104.txt (original) +++ peps/trunk/pep-3104.txt Sun Mar 4 21:02:51 2007 @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Ka-Ping Yee -Status: Draft +Status: Accepted Type: Standards Track Python-Version: 3.0 Content-Type: text/x-rst From python-checkins at python.org Sun Mar 4 21:04:15 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 4 Mar 2007 21:04:15 +0100 (CET) Subject: [Python-checkins] r54122 - peps/trunk/pep-0000.txt Message-ID: <20070304200415.3B4BB1E4009@bag.python.org> Author: brett.cannon Date: Sun Mar 4 21:04:12 2007 New Revision: 54122 Modified: peps/trunk/pep-0000.txt Log: Make PEP 3102 as finished. Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Sun Mar 4 21:04:12 2007 @@ -77,7 +77,6 @@ Accepted PEPs (accepted; may not be implemented yet) - SA 3102 Keyword-Only Arguments Talin SA 3106 Revamping dict.keys(), .values() and .items() GvR SA 3107 Function Annotations Winter, Lownds SA 3109 Raising Exceptions in Python 3000 Winter @@ -175,6 +174,7 @@ SF 352 Required Superclass for Exceptions GvR, Cannon SF 353 Using ssize_t as the index type von Loewis SF 357 Allowing Any Object to be Used for Slicing Oliphant + SF 3102 Keyword-Only Arguments Talin SF 3104 Access to Names in Outer Scopes Yee SF 3105 Make print a function Brandl @@ -448,7 +448,7 @@ I 3099 Things that will Not Change in Python 3000 Brandl I 3100 Python 3.0 Plans Kuchling, Cannon S 3101 Advanced String Formatting Talin - SA 3102 Keyword-Only Arguments Talin + SF 3102 Keyword-Only Arguments Talin SR 3103 A Switch/Case Statement GvR SF 3104 Access to Names in Outer Scopes Yee SF 3105 Make print a function Brandl From python-checkins at python.org Sun Mar 4 21:09:53 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 4 Mar 2007 21:09:53 +0100 (CET) Subject: [Python-checkins] r54123 - peps/trunk/pep-0000.txt Message-ID: <20070304200953.259851E4009@bag.python.org> Author: brett.cannon Date: Sun Mar 4 21:09:49 2007 New Revision: 54123 Modified: peps/trunk/pep-0000.txt Log: Mark PEP 3107 as finished. Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Sun Mar 4 21:09:49 2007 @@ -78,7 +78,6 @@ Accepted PEPs (accepted; may not be implemented yet) SA 3106 Revamping dict.keys(), .values() and .items() GvR - SA 3107 Function Annotations Winter, Lownds SA 3109 Raising Exceptions in Python 3000 Winter SA 3110 Catching Exceptions in Python 3000 Winter SA 3111 Simple input built-in in Python 3000 Roberge @@ -177,6 +176,7 @@ SF 3102 Keyword-Only Arguments Talin SF 3104 Access to Names in Outer Scopes Yee SF 3105 Make print a function Brandl + SF 3107 Function Annotations Winter, Lownds Empty PEPs (or containing only an abstract) @@ -453,7 +453,7 @@ SF 3104 Access to Names in Outer Scopes Yee SF 3105 Make print a function Brandl SA 3106 Revamping dict.keys(), .values() and .items() GvR - SA 3107 Function Annotations Winter, Lownds + SF 3107 Function Annotations Winter, Lownds S 3108 Standard Library Reorganization Cannon SA 3109 Raising Exceptions in Python 3000 Winter SA 3110 Catching Exceptions in Python 3000 Winter From python-checkins at python.org Sun Mar 4 21:52:31 2007 From: python-checkins at python.org (skip.montanaro) Date: Sun, 4 Mar 2007 21:52:31 +0100 (CET) Subject: [Python-checkins] r54124 - python/trunk/setup.py Message-ID: <20070304205231.4BD911E400A@bag.python.org> Author: skip.montanaro Date: Sun Mar 4 21:52:28 2007 New Revision: 54124 Modified: python/trunk/setup.py Log: Teach setup.py how to find Berkeley DB on Macs using MacPorts. Modified: python/trunk/setup.py ============================================================================== --- python/trunk/setup.py (original) +++ python/trunk/setup.py Sun Mar 4 21:52:28 2007 @@ -616,10 +616,11 @@ '/usr/include/db4', '/usr/local/include/db4', '/opt/sfw/include/db4', - '/sw/include/db4', '/usr/include/db3', '/usr/local/include/db3', '/opt/sfw/include/db3', + # Fink defaults (http://fink.sourceforge.net/) + '/sw/include/db4', '/sw/include/db3', ] # 4.x minor number specific paths @@ -630,6 +631,8 @@ db_inc_paths.append('/usr/local/include/db4%d' % x) db_inc_paths.append('/pkg/db-4.%d/include' % x) db_inc_paths.append('/opt/db-4.%d/include' % x) + # MacPorts default (http://www.macports.org/) + db_inc_paths.append('/opt/local/include/db4%d' % x) # 3.x minor number specific paths for x in (3,): db_inc_paths.append('/usr/include/db3%d' % x) @@ -654,7 +657,7 @@ std_variants.append(os.path.join(dn, "db3.%d"%x)) db_inc_paths = std_variants + db_inc_paths - + db_inc_paths = [p for p in db_inc_paths if os.path.exists(p)] db_ver_inc_map = {} @@ -677,7 +680,7 @@ if ( (not db_ver_inc_map.has_key(db_ver)) and (db_ver <= max_db_ver and db_ver >= min_db_ver) ): # save the include directory with the db.h version - # (first occurrance only) + # (first occurrence only) db_ver_inc_map[db_ver] = d if db_setup_debug: print "db.h: found", db_ver, "in", d @@ -686,7 +689,8 @@ if db_setup_debug: print "db.h: ignoring", d else: # ignore this header, it didn't contain a version number - if db_setup_debug: print "db.h: unsupported version", db_ver, "in", d + if db_setup_debug: + print "db.h: no version number version in", d db_found_vers = db_ver_inc_map.keys() db_found_vers.sort() @@ -697,10 +701,8 @@ # check lib directories parallel to the location of the header db_dirs_to_check = [ - os.path.join(db_incdir, '..', 'lib64'), - os.path.join(db_incdir, '..', 'lib'), - os.path.join(db_incdir, '..', '..', 'lib64'), - os.path.join(db_incdir, '..', '..', 'lib'), + db_incdir.replace("include", 'lib64'), + db_incdir.replace("include", 'lib'), ] db_dirs_to_check = filter(os.path.isdir, db_dirs_to_check) From python-checkins at python.org Sun Mar 4 21:54:15 2007 From: python-checkins at python.org (skip.montanaro) Date: Sun, 4 Mar 2007 21:54:15 +0100 (CET) Subject: [Python-checkins] r54125 - python/trunk/Misc/NEWS Message-ID: <20070304205415.3C4DC1E400A@bag.python.org> Author: skip.montanaro Date: Sun Mar 4 21:54:12 2007 New Revision: 54125 Modified: python/trunk/Misc/NEWS Log: note MacPorts/BerkDB change in setup.py Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sun Mar 4 21:54:12 2007 @@ -136,6 +136,8 @@ Library ------- +- Taught setup.py how to locate Berkeley DB on Macs using MacPorts. + - Added heapq.merge() for merging sorted input streams. - Added collections.NamedTuple() for assigning field names to tuples. From buildbot at python.org Sun Mar 4 22:38:26 2007 From: buildbot at python.org (buildbot at python.org) Date: Sun, 04 Mar 2007 21:38:26 +0000 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk Message-ID: <20070304213827.1A0721E400A@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%2520trunk/builds/1784 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: skip.montanaro Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Sun Mar 4 22:53:32 2007 From: python-checkins at python.org (eric.smith) Date: Sun, 4 Mar 2007 22:53:32 +0100 (CET) Subject: [Python-checkins] r54126 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070304215332.4CAFA1E400A@bag.python.org> Author: eric.smith Date: Sun Mar 4 22:53:27 2007 New Revision: 54126 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Decimal ('d') formatting complete, including test cases, for ascii. Unicode for decimal does not work yet, but it's next on my list to fix. Hex and octal may also work, but since I haven't written test cases I'm still classifying them as not working. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Sun Mar 4 22:53:27 2007 @@ -44,6 +44,10 @@ "My name is {0} :-{{}}", "Fred") self.formatEquals("abc", "{0:}", "abc") # is this allowed? + def test_no_substitutions(self): + self.formatEquals("", "") + self.formatEquals("how now brown cow", "how now brown cow") + def test_missingargs(self): #self.formatRaises(None, "Doesn't use all {0} args", 42, 24) self.formatRaises(ValueError, "There is no {4} arg", 42, 24) @@ -85,13 +89,14 @@ # "The shiny red {0[-2]}", t) def test_formatlookup(self): - self.formatEquals("32_0>4d", "{0:{1}}", 32, "0>4d") - self.formatEquals("32_*>4d", "{0:{1}{2}4{3}}", 32, "*", ">", "d") + pass +# self.formatEquals("32", "{0:{1}}", 32, "0>4d") +# self.formatEquals("32", "{0:{1}{2}4{3}}", 32, "*", ">", "d") def test_specifiers(self): self.formatEquals("a", "{0:c}", ord("a")) self.formatEquals("8_08b", "{0:08b}", 8) - self.formatEquals("8_ >3d", "{0: >3d}", 8) +# self.formatEquals("8", "{0: >3d}", 8) self.formatEquals("0.1515_.0%", "{0:.0%}", .1515) def test_string_specifiers(self): @@ -116,11 +121,43 @@ self.formatEquals("'abcdefg", "{0:8r}", "abcdefg") def test_decimal_specifiers(self): - pass -# self.assertRaises(Exception, "{0:d}", "non-number") + self.assertRaises(TypeError, "{0:d}", "non-number") -# self.formatEquals("0", "{0:d}", 0) -# self.formatEquals("1" + "0" * 100, "{0:d}", 10**100) + self.formatEquals("0", "{0:d}", 0) + self.formatEquals("123", "{0:d}", 123) + self.formatEquals("-123", "{0:d}", -123) + self.formatEquals("+123", "{0:+d}", 123) + self.formatEquals("-123", "{0:+d}", -123) + self.formatEquals("123", "{0:-d}", 123) + self.formatEquals("-123", "{0:-d}", -123) + self.formatEquals("123", "{0:()d}", 123) + self.formatEquals("(123)", "{0:()d}", -123) + + # need a long padding to force a reallocation (and hopefully a + # memory move) in 'd' handling + self.formatEquals(" " * 997 + "100", "{0:1000d}", 100) + + # now test with the 3 kinds of padding + self.formatEquals("0 ", "{0:<10d}", 0) + self.formatEquals("123 ", "{0:<10d}", 123) + self.formatEquals("-123 ", "{0:<10d}", -123) + self.formatEquals(" 123", "{0:>10d}", 123) + self.formatEquals(" -123", "{0:>10d}", -123) + self.formatEquals(" 123", "{0:=10d}", 123) + self.formatEquals("+ 123", "{0:=+10d}", 123) + self.formatEquals("- 123", "{0:=10d}", -123) + self.formatEquals("- 123", "{0:=+10d}", -123) + self.formatEquals(" 123", "{0:=()10d}", 123) + + # XXX I'm not sure this is correct, maybe it should be " (123)" + self.formatEquals("( 123)", "{0:=()10d}", -123) + + self.formatEquals("1" + "0" * 100, "{0:d}", 10**100) + self.formatEquals("-1" + "0" * 100, "{0:d}", -10**100) + self.formatEquals("+1" + "0" * 100, "{0:+d}", 10**100) + self.formatEquals("(1" + "0" * 100 + ")", "{0:()d}", -10**100) + self.formatEquals("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) + self.formatEquals("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) def test_char_specifiers(self): self.formatEquals("A", "{0:c}", "A") Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Sun Mar 4 22:53:27 2007 @@ -63,6 +63,16 @@ #define PySet_GET_SIZE PyDict_Size #endif + +/* MAXLEN_INT_STRING is the maximum length of an integer represented + * as a string. The analysis in stringobject.c shows that 24 is the + * worst case. Allocate more, just in case. */ +/* fmt = '%#.' + `prec` + 'l' + `type` + worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine) + + 1 + 1 = 24 */ +#define MAXLEN_INT_STRING 64 + + /************************************************************************/ /*********** Global data structures and forward declarations *********/ /************************************************************************/ @@ -102,7 +112,7 @@ typedef struct { CH_TYPE *ptr; CH_TYPE *end; - PyObject * obj; + PyObject *obj; } SubStringObj; /* @@ -281,12 +291,32 @@ output_data(FmtState *fs, const CH_TYPE *s, Py_ssize_t count) { CH_TYPE *dst; - if (output_allocate(fs, count, &dst) == 0) - return 0; + + /* there is some duplicate code here with output_allocate, + which is here to avoid a function call if there's already + enough allocated space */ + Py_ssize_t room = fs->outstr.end - fs->outstr.ptr; + if (count > room) { + if (output_allocate(fs, count, &dst) == 0) + return 0; + } else { + dst = fs->outstr.ptr; + fs->outstr.ptr += count; + } memcpy(dst, s, count * sizeof(CH_TYPE)); return 1; } + +/* + shrink the allocated output size by count bytes +*/ +Py_LOCAL_INLINE(void) +output_shrink(FmtState* fs, Py_ssize_t count) +{ + fs->outstr.ptr -= count; +} + /************************************************************************/ /*********** Format string parsing -- integers and identifiers *********/ /************************************************************************/ @@ -870,65 +900,274 @@ return output_data(fs, &buf, 1); } + +/* code liberally borrowed from stringobject.c's formatint() */ +/* into the output buffer, put . the caller will + justify as needed */ +/* return the total number of bytes written, or -1 for error + sets pbuf to point to the output buffer */ +static Py_ssize_t +_format_int(PyObject* v, FmtState *fs, CH_TYPE type, CH_TYPE **pbuf) +{ + CH_TYPE *ptr; + Py_ssize_t buflen = MAXLEN_INT_STRING; + Py_ssize_t len; + long x; + char format[3]; /* a temporary buffer to use to build the format + string. */ + + x = PyInt_AsLong(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "int argument required, not %.200s", + v->ob_type->tp_name); + return -1; + } + + if (output_allocate(fs, MAXLEN_INT_STRING, pbuf) == 0) { + return -1; + } + + /* remember the start of the string */ + ptr = *pbuf; + + if (x < 0 && (type == 'x' || type == 'X' || type == 'o')) { + **pbuf = '-'; + *pbuf++; + buflen--; + x = -x; + } + + /* build up the format string */ + format[0] = '%'; + format[1] = type; + format[2] = '\0'; + + PyOS_snprintf(*pbuf, buflen, format, x); + + /* compute the length. I believe this is done because the return value from + snprintf above is unreliable */ + + len = strlen(ptr); + + /* shrink the buffer down to how many characters we actually + wrote. this is cheap, just pointer arithmetic */ + output_shrink(fs, MAXLEN_INT_STRING - len); + + return len; +} + static int format_decimal(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { -#if 0 + Py_ssize_t width; + CH_TYPE align = format->align; + CH_TYPE *p_buf; + CH_TYPE *p_digits; /* pointer to the digits we have */ + CH_TYPE n_digits; /* count of digits we have */ + CH_TYPE sign; + Py_ssize_t n_lpadding; + Py_ssize_t n_spadding; + Py_ssize_t n_rpadding; + CH_TYPE lsign; + Py_ssize_t n_lsign = 0; + CH_TYPE rsign; + Py_ssize_t n_rsign = 0; + Py_ssize_t n_total; /* the total length we're going to write */ + Py_ssize_t n_allocated; /* how much space we actually allocated + when we wrote the digits into the + output */ + Py_ssize_t ofs_buf; + Py_ssize_t ofs_digits; + CH_TYPE *tmp; + + /*************************************************************************/ + /* first, do everything as ascii *****************************************/ if (PyLong_Check(fieldobj)) { - int ilen; - temp = _PyString_FormatLong(v, flags, - prec, c, &pbuf, &ilen); - len = ilen; - if (!temp) - goto error; - sign = 1; - } - else { - pbuf = formatbuf; - len = formatint(pbuf, - sizeof(formatbuf), - flags, prec, c, v); - if (len < 0) - goto error; - sign = 1; + /* a long integer */ + + /* XXX this should probably be Py_ssize_t, but that's not how + the function is declared */ + int len; + int ok; + PyObject *strobj = _PyString_FormatLong(fieldobj, 0, + 0, format->type, &p_buf, &len); + + if (!strobj) + return 0; + + n_allocated = STROBJ_GET_SIZE(strobj); + p_buf = fs->outstr.ptr; + + /* allocate space in the output, and copy the data */ + ok = output_data(fs, STROBJ_AS_PTR(strobj), n_allocated); + + /* we're done with the string representation */ + Py_DECREF(strobj); + + if (ok == 0) + return 0; + } else { + /* a regular integer, we can be quicker in this case */ + + /* n_allocated includes the total number of characters + written, including the sign, if any */ + n_allocated = _format_int(fieldobj, fs, format->type, &p_buf); + if (n_allocated < 0) + return 0; } - if (flags & F_ZERO) - fill = '0'; -#endif - return format_DUMMY(fieldobj, fs); + + /* if needed, convert from asci to unicode */ +#if C_UNICODE + /* taken from unicodeobject.c's strtounicode() */ #if 0 - PyObject *intobj; - PyObject *strobj; - CH_TYPE* src; - Py_ssize_t len; - int negative = 0; - int ok; +strtounicode(Py_UNICODE *buffer, const char *charbuffer) +{ + register Py_ssize_t i; + Py_ssize_t len = strlen(charbuffer); + for (i = len - 1; i >= 0; i--) + buffer[i] = (Py_UNICODE) charbuffer[i]; + return len; +} +#endif +#endif + /* end ascii conversion **************************************************/ - intobj = PyIntObject(fieldobj); - if (intobj == NULL) - return 0; + /* determine if a sign was written, and how many digits we wrote */ + n_digits = n_allocated; + p_digits = p_buf; + + /* is a sign character present in the output? if so, remember it + and skip it */ + sign = p_buf[0]; + if (sign == '-') { + p_digits++; + n_digits--; + } + else + sign = '\0'; + + /* the output will look like: + | | + | | + | | + + lsign and rsign are computed from format->sign and the actual + sign of the number - strobj = STROBJ_STR(intobj); - Py_DECREF(intobj); + digits is already known - /* see if we're negative. we know src must point to at least one - character, so skip that check */ - src = STROBJ_AS_PTR(strobj); - len = STROBJ_GET_SIZE(strobj); - if (src[0] == '-') { - /* remember that we're negative, and skip the char */ - negative = 1; - src++; - len--; + the total width is either given, or computed from the + actual digits + + only one of lpadding, spadding, and rpadding can be non-zero, + and it's calculated from the width and other fields + */ + + /* compute the various parts we're going to write */ + if (format->sign == '+') { + /* always put a + or - */ + n_lsign = 1; + lsign = (sign == '-' ? '-' : '+'); + } else if (format->sign == '(') { + if (sign == '-') { + n_lsign = 1; + lsign = '('; + n_rsign = 1; + rsign = ')'; + } + } else if (format->sign == ' ') { + n_lsign = 1; + lsign = (sign == '-' ? '-' : ' '); + } else { + /* non specified, or the default (-) */ + if (sign == '-') { + n_lsign = 1; + lsign = '-'; + } } - ok = output_string_chars(fs, src, len, format); - Py_DECREF(strobj); + /* now the number of padding characters */ + n_lpadding = n_spadding = n_rpadding = 0; + if (format->width == -1) { + /* no padding at all, nothing to do */ + } else { + /* see if any padding is needed */ + if (n_lsign + n_digits + n_rsign >= format->width) { + /* no padding needed, we're already bigger than the + requested width */ + } else { + /* determine which of left, space, or right padding is + needed */ + Py_ssize_t padding = format->width - (n_lsign + n_digits + n_rsign); + if (format->align == '<') + n_rpadding = padding; + else if (format->align == '>') + n_lpadding = padding; + else + /* must be '=' */ + n_spadding = padding; + } + } - return ok; + /* set the total length of the string */ + n_total = n_lpadding + n_lsign + n_spadding + n_digits + n_rsign + n_rpadding; + assert(n_total >= n_allocated); + + /* because we're going to reallocate, our pointers might be + invalidated. remember the offsets, then re-create the pointers + after the allocation. */ + tmp = STROBJ_AS_PTR(fs->outstr.obj); + ofs_buf = p_buf - tmp; + ofs_digits = p_digits - tmp; + + output_allocate(fs, n_total - n_allocated, &tmp); + + tmp = STROBJ_AS_PTR(fs->outstr.obj); + p_buf = tmp + ofs_buf; + p_digits = tmp + ofs_digits; + +#if 0 + printf("p_buf %p\n", p_buf); + printf("p_digits %p\n", p_digits); + printf("n_digits: %d\n", n_digits); + printf("n_lpadding: %d\n", n_lpadding); + printf("n_lsign: %d\n", n_lsign); + printf("lsign: %d(%c)\n", lsign, lsign); + printf("n_rsign: %d\n", n_rsign); + printf("rsign: %d(%c)\n", rsign, rsign); + printf("n_spadding: %d\n", n_spadding); + printf("n_rpadding: %d\n", n_rpadding); #endif + + /* copy the characters into position first, since we're going to + overwrite some of that space */ + /* short circuit test, in case we don't have to move anything */ + if (p_buf + (n_lpadding + n_lsign + n_spadding) != p_digits) + memmove(p_buf + (n_lpadding + n_lsign + n_spadding), p_digits, n_digits * sizeof(CH_TYPE)); + + if (n_lpadding) { + CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, n_lpadding); + p_buf += n_lpadding; + } + if (n_lsign == 1) { + *p_buf++ = lsign; + } + if (n_spadding) { + CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, n_spadding); + p_buf += n_spadding; + } + p_buf += n_digits; + if (n_rsign == 1) { + *p_buf++ = rsign; + } + if (n_rpadding) { + CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, n_rpadding); + p_buf += n_rpadding; + } + + return 1; } static int @@ -939,13 +1178,6 @@ } static int -format_exponentUC(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) -{ - return format_DUMMY(fieldobj, fs); -} - -static int format_fixed(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { @@ -953,13 +1185,6 @@ } static int -format_fixedUC(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) -{ - return format_DUMMY(fieldobj, fs); -} - -static int format_general(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { @@ -967,27 +1192,13 @@ } static int -format_generalUC(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) -{ - return format_DUMMY(fieldobj, fs); -} - -static int -format_number(PyObject *fieldobj, FmtState *fs, +format_locale_number(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { return format_DUMMY(fieldobj, fs); } static int -format_octal(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) -{ - return format_DUMMY(fieldobj, fs); -} - -static int format_repr(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { @@ -1028,20 +1239,6 @@ } static int -format_hex(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) -{ - return format_DUMMY(fieldobj, fs); -} - -static int -format_hexUC(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) -{ - return format_DUMMY(fieldobj, fs); -} - -static int format_percentage(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { @@ -1057,20 +1254,20 @@ case 'c': return format_char; /* as character */ case 'd': return format_decimal; /* decimal integer */ case 'e': return format_exponent; /* exponential notation */ - case 'E': return format_exponentUC; /* exponential notation + case 'E': return format_exponent; /* exponential notation with uppercase 'E' */ case 'f': return format_fixed; /* fixed-point */ - case 'F': return format_fixedUC; /* fixed-point with uppercase */ + case 'F': return format_fixed; /* fixed-point with uppercase */ case 'g': return format_general; /* general number notation */ - case 'G': return format_generalUC; /* general number notation + case 'G': return format_general; /* general number notation with uppercase 'E' */ - case 'n': return format_number; /* number in locale-specific + case 'n': return format_locale_number; /* number in locale-specific format */ - case 'o': return format_octal; /* octal */ + case 'o': return format_decimal; /* octal */ case 'r': return format_repr; /* in repr() format */ case 's': return format_string; /* convert using str() */ - case 'x': return format_hex; /* base 16 */ - case 'X': return format_hexUC; /* base 16 uppercase */ + case 'x': return format_decimal; /* base 16 */ + case 'X': return format_decimal; /* base 16 uppercase */ case '%': return format_percentage; /* as percentage */ default: return NULL; From buildbot at python.org Sun Mar 4 23:13:24 2007 From: buildbot at python.org (buildbot at python.org) Date: Sun, 04 Mar 2007 22:13:24 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070304221324.CE3F01E400A@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/78 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: skip.montanaro Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Mon Mar 5 00:37:38 2007 From: python-checkins at python.org (eric.smith) Date: Mon, 5 Mar 2007 00:37:38 +0100 (CET) Subject: [Python-checkins] r54127 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070304233738.4BD2E1E400A@bag.python.org> Author: eric.smith Date: Mon Mar 5 00:37:37 2007 New Revision: 54127 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Decimal ('d') unicode formatting complete. Modified test suite to test for both Unicode and string versions, for some tests. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 00:37:37 2007 @@ -20,6 +20,16 @@ val = pep3101.format(text, *args, **kwargs) self.assertEquals(val, result) + def formatEqualsWithUnicode(self, result, text, *args, **kwargs): + text = str(text) + result = str(result) + val = pep3101.format(text, *args, **kwargs) + self.assertEquals(val, result) + + # a quick check for unicode version + val = pep3101.format(unicode(text), *args, **kwargs) + self.assertEquals(val, unicode(result)) + def formatRaises(self, exc, text, *args, **kwargs): exc = exc or Exception #StringFormat.FormatError text = str(text) @@ -100,64 +110,64 @@ self.formatEquals("0.1515_.0%", "{0:.0%}", .1515) def test_string_specifiers(self): - self.formatEquals("abc", "{0:.3s}", "abc") + self.formatEqualsWithUnicode("abc", "{0:.3s}", "abc") - self.formatEquals("ab", "{0:.3s}", "ab") + self.formatEqualsWithUnicode("ab", "{0:.3s}", "ab") - self.formatEquals("abc", "{0:.3s}", "abcdef") - self.formatEquals("resultx", "{0:x<7s}", "result") - self.formatEquals("resultxx", "{0:x<8s}", "result") - self.formatEquals("result ", "{0: <7s}", "result") - self.formatEquals("result ", "{0:<7s}", "result") - self.formatEquals(" result", "{0:>7s}", "result") - self.formatEquals(" result", "{0:>8s}", "result") + self.formatEqualsWithUnicode("abc", "{0:.3s}", "abcdef") + self.formatEqualsWithUnicode("resultx", "{0:x<7s}", "result") + self.formatEqualsWithUnicode("resultxx", "{0:x<8s}", "result") + self.formatEqualsWithUnicode("result ", "{0: <7s}", "result") + self.formatEqualsWithUnicode("result ", "{0:<7s}", "result") + self.formatEqualsWithUnicode(" result", "{0:>7s}", "result") + self.formatEqualsWithUnicode(" result", "{0:>8s}", "result") def test_repr_specifiers(self): - self.formatEquals("3", "{0:r}", 3) - self.formatEquals("3.141", "{0:5r}", 3.141592654) + self.formatEqualsWithUnicode("3", "{0:r}", 3) + self.formatEqualsWithUnicode("3.141", "{0:5r}", 3.141592654) # I'm not sure this is a good test, since the quoting might change - self.formatEquals("'abcdefg'", "{0:r}", "abcdefg") - self.formatEquals("'abcdefg", "{0:8r}", "abcdefg") + self.formatEqualsWithUnicode("'abcdefg'", "{0:r}", "abcdefg") + self.formatEqualsWithUnicode("'abcdefg", "{0:8r}", "abcdefg") def test_decimal_specifiers(self): self.assertRaises(TypeError, "{0:d}", "non-number") - self.formatEquals("0", "{0:d}", 0) - self.formatEquals("123", "{0:d}", 123) - self.formatEquals("-123", "{0:d}", -123) - self.formatEquals("+123", "{0:+d}", 123) - self.formatEquals("-123", "{0:+d}", -123) - self.formatEquals("123", "{0:-d}", 123) - self.formatEquals("-123", "{0:-d}", -123) - self.formatEquals("123", "{0:()d}", 123) - self.formatEquals("(123)", "{0:()d}", -123) + self.formatEqualsWithUnicode("0", "{0:d}", 0) + self.formatEqualsWithUnicode("123", "{0:d}", 123) + self.formatEqualsWithUnicode("-123", "{0:d}", -123) + self.formatEqualsWithUnicode("+123", "{0:+d}", 123) + self.formatEqualsWithUnicode("-123", "{0:+d}", -123) + self.formatEqualsWithUnicode("123", "{0:-d}", 123) + self.formatEqualsWithUnicode("-123", "{0:-d}", -123) + self.formatEqualsWithUnicode("123", "{0:()d}", 123) + self.formatEqualsWithUnicode("(123)", "{0:()d}", -123) # need a long padding to force a reallocation (and hopefully a # memory move) in 'd' handling - self.formatEquals(" " * 997 + "100", "{0:1000d}", 100) + self.formatEqualsWithUnicode(" " * 997 + "100", "{0:1000d}", 100) # now test with the 3 kinds of padding - self.formatEquals("0 ", "{0:<10d}", 0) - self.formatEquals("123 ", "{0:<10d}", 123) - self.formatEquals("-123 ", "{0:<10d}", -123) - self.formatEquals(" 123", "{0:>10d}", 123) - self.formatEquals(" -123", "{0:>10d}", -123) - self.formatEquals(" 123", "{0:=10d}", 123) - self.formatEquals("+ 123", "{0:=+10d}", 123) - self.formatEquals("- 123", "{0:=10d}", -123) - self.formatEquals("- 123", "{0:=+10d}", -123) - self.formatEquals(" 123", "{0:=()10d}", 123) + self.formatEqualsWithUnicode("0 ", "{0:<10d}", 0) + self.formatEqualsWithUnicode("123 ", "{0:<10d}", 123) + self.formatEqualsWithUnicode("-123 ", "{0:<10d}", -123) + self.formatEqualsWithUnicode(" 123", "{0:>10d}", 123) + self.formatEqualsWithUnicode(" -123", "{0:>10d}", -123) + self.formatEqualsWithUnicode(" 123", "{0:=10d}", 123) + self.formatEqualsWithUnicode("+ 123", "{0:=+10d}", 123) + self.formatEqualsWithUnicode("- 123", "{0:=10d}", -123) + self.formatEqualsWithUnicode("- 123", "{0:=+10d}", -123) + self.formatEqualsWithUnicode(" 123", "{0:=()10d}", 123) # XXX I'm not sure this is correct, maybe it should be " (123)" - self.formatEquals("( 123)", "{0:=()10d}", -123) + self.formatEqualsWithUnicode("( 123)", "{0:=()10d}", -123) - self.formatEquals("1" + "0" * 100, "{0:d}", 10**100) - self.formatEquals("-1" + "0" * 100, "{0:d}", -10**100) - self.formatEquals("+1" + "0" * 100, "{0:+d}", 10**100) - self.formatEquals("(1" + "0" * 100 + ")", "{0:()d}", -10**100) - self.formatEquals("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) - self.formatEquals("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) + self.formatEqualsWithUnicode("1" + "0" * 100, "{0:d}", 10**100) + self.formatEqualsWithUnicode("-1" + "0" * 100, "{0:d}", -10**100) + self.formatEqualsWithUnicode("+1" + "0" * 100, "{0:+d}", 10**100) + self.formatEqualsWithUnicode("(1" + "0" * 100 + ")", "{0:()d}", -10**100) + self.formatEqualsWithUnicode("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) + self.formatEqualsWithUnicode("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) def test_char_specifiers(self): self.formatEquals("A", "{0:c}", "A") Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 00:37:37 2007 @@ -901,15 +901,40 @@ } +#if C_UNICODE +/* taken from unicodeobject.c */ +/* note that since we work backward, the ranges can overlap */ +static Py_ssize_t +strtounicode(Py_UNICODE *buffer, const char *charbuffer, Py_ssize_t len) +{ + register Py_ssize_t i; + + /* don't know the length, calculate it */ + if (len == -1) + len = strlen(charbuffer); + for (i = len - 1; i >= 0; i--) + buffer[i] = (Py_UNICODE) charbuffer[i]; + + return len; +} +#endif + /* code liberally borrowed from stringobject.c's formatint() */ /* into the output buffer, put . the caller will justify as needed */ -/* return the total number of bytes written, or -1 for error - sets pbuf to point to the output buffer */ +/* this code internally uses 8-bit chars, even when formatting + unicode. that's because we use PyOS_snprintf() from both 8-bit and + unicode. that means we need to cast the allocated pointer, which + is always in units of CH_TYPE */ +/* when this function returns, the result will be in char or unicode + (CH_TYPE), as needed */ +/* return the total number of characters written, or -1 for error sets + pbuf to point to the output buffer */ static Py_ssize_t -_format_int(PyObject* v, FmtState *fs, CH_TYPE type, CH_TYPE **pbuf) +_format_int(PyObject* v, FmtState *fs, char type, CH_TYPE **pbuf) { - CH_TYPE *ptr; + char *ptr; + char *start; Py_ssize_t buflen = MAXLEN_INT_STRING; Py_ssize_t len; long x; @@ -923,16 +948,17 @@ return -1; } - if (output_allocate(fs, MAXLEN_INT_STRING, pbuf) == 0) { + /* allocate as much space as we'll ever possibly need. note that + if we're doing unicode, we allocate as bytes, format as bytes, + but convert to unicode, all in the same buffer. */ + if (output_allocate(fs, MAXLEN_INT_STRING, pbuf) == 0) return -1; - } - /* remember the start of the string */ - ptr = *pbuf; + /* remember the start of the string, as 8-bit chars */ + start = ptr = (char*)*pbuf; if (x < 0 && (type == 'x' || type == 'X' || type == 'o')) { - **pbuf = '-'; - *pbuf++; + *ptr++ = '-'; buflen--; x = -x; } @@ -942,12 +968,17 @@ format[1] = type; format[2] = '\0'; - PyOS_snprintf(*pbuf, buflen, format, x); + PyOS_snprintf(ptr, buflen, format, x); + + /* convert from chars to unicode, if needed */ +#if C_UNICODE + len = strtounicode(*pbuf, start, -1); +#else /* compute the length. I believe this is done because the return value from snprintf above is unreliable */ - - len = strlen(ptr); + len = strlen(start); +#endif /* shrink the buffer down to how many characters we actually wrote. this is cheap, just pointer arithmetic */ @@ -956,11 +987,49 @@ return len; } +static Py_ssize_t +_format_long(PyObject* v, FmtState *fs, char type, CH_TYPE **pbuf) +{ + char* p_charbuf; + Py_ssize_t n_allocated; + CH_TYPE* ptr; + int ok; + /* XXX len should probably be Py_ssize_t, but that's not how the + function is declared in stringobject.c */ + int len; + PyObject *strobj; + + strobj = _PyString_FormatLong(v, 0, 0, type, &p_charbuf, &len); + if (!strobj) + return -1; + + n_allocated = len; + *pbuf = fs->outstr.ptr; + +#if C_UNICODE + /* allocate space in the output string, as CH_TYPE */ + ok = output_allocate(fs, n_allocated, &ptr); + if (ok != 0) { + strtounicode(ptr, p_charbuf, n_allocated); + } +#else + ok = output_data(fs, STROBJ_AS_PTR(strobj), n_allocated); +#endif + + /* we're done with the string representation */ + Py_DECREF(strobj); + + if (!ok) + return -1; + return n_allocated; +} + static int format_decimal(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { Py_ssize_t width; + char* p_abuf; CH_TYPE align = format->align; CH_TYPE *p_buf; CH_TYPE *p_digits; /* pointer to the digits we have */ @@ -981,58 +1050,20 @@ Py_ssize_t ofs_digits; CH_TYPE *tmp; - /*************************************************************************/ - /* first, do everything as ascii *****************************************/ - if (PyLong_Check(fieldobj)) { - /* a long integer */ - - /* XXX this should probably be Py_ssize_t, but that's not how - the function is declared */ - int len; - int ok; - PyObject *strobj = _PyString_FormatLong(fieldobj, 0, - 0, format->type, &p_buf, &len); + /* n_allocated includes the total number of characters written, + including the sign, if any */ + /* note that we're potentially converting format->type from + Unicode to char, but that's okay because we know what the valid + values can be */ - if (!strobj) - return 0; - - n_allocated = STROBJ_GET_SIZE(strobj); - p_buf = fs->outstr.ptr; - - /* allocate space in the output, and copy the data */ - ok = output_data(fs, STROBJ_AS_PTR(strobj), n_allocated); - - /* we're done with the string representation */ - Py_DECREF(strobj); - - if (ok == 0) - return 0; + if (PyLong_Check(fieldobj)) { + n_allocated = _format_long(fieldobj, fs, (char)format->type, &p_buf); } else { /* a regular integer, we can be quicker in this case */ - - /* n_allocated includes the total number of characters - written, including the sign, if any */ - n_allocated = _format_int(fieldobj, fs, format->type, &p_buf); - if (n_allocated < 0) - return 0; + n_allocated = _format_int(fieldobj, fs, (char)format->type, &p_buf); } - - /* if needed, convert from asci to unicode */ -#if C_UNICODE - /* taken from unicodeobject.c's strtounicode() */ -#if 0 -strtounicode(Py_UNICODE *buffer, const char *charbuffer) -{ - register Py_ssize_t i; - Py_ssize_t len = strlen(charbuffer); - for (i = len - 1; i >= 0; i--) - buffer[i] = (Py_UNICODE) charbuffer[i]; - - return len; -} -#endif -#endif - /* end ascii conversion **************************************************/ + if (n_allocated < 0) + return 0; /* determine if a sign was written, and how many digits we wrote */ n_digits = n_allocated; From python-checkins at python.org Mon Mar 5 01:22:43 2007 From: python-checkins at python.org (patrick.maupin) Date: Mon, 5 Mar 2007 01:22:43 +0100 (CET) Subject: [Python-checkins] r54128 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070305002243.9F5EB1E400A@bag.python.org> Author: patrick.maupin Date: Mon Mar 5 01:22:42 2007 New Revision: 54128 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Removed compiler warnings Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 01:22:42 2007 @@ -992,7 +992,9 @@ { char* p_charbuf; Py_ssize_t n_allocated; +#if C_UNICODE CH_TYPE* ptr; +#endif int ok; /* XXX len should probably be Py_ssize_t, but that's not how the function is declared in stringobject.c */ @@ -1028,9 +1030,6 @@ format_decimal(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - Py_ssize_t width; - char* p_abuf; - CH_TYPE align = format->align; CH_TYPE *p_buf; CH_TYPE *p_digits; /* pointer to the digits we have */ CH_TYPE n_digits; /* count of digits we have */ @@ -1038,9 +1037,9 @@ Py_ssize_t n_lpadding; Py_ssize_t n_spadding; Py_ssize_t n_rpadding; - CH_TYPE lsign; + CH_TYPE lsign = 0; Py_ssize_t n_lsign = 0; - CH_TYPE rsign; + CH_TYPE rsign = 0; Py_ssize_t n_rsign = 0; Py_ssize_t n_total; /* the total length we're going to write */ Py_ssize_t n_allocated; /* how much space we actually allocated From python-checkins at python.org Mon Mar 5 01:45:33 2007 From: python-checkins at python.org (eric.smith) Date: Mon, 5 Mar 2007 01:45:33 +0100 (CET) Subject: [Python-checkins] r54129 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070305004533.11CA81E401E@bag.python.org> Author: eric.smith Date: Mon Mar 5 01:45:26 2007 New Revision: 54129 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Fix hex and octal formatting. Added testcases. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 01:45:26 2007 @@ -30,6 +30,27 @@ val = pep3101.format(unicode(text), *args, **kwargs) self.assertEquals(val, unicode(result)) + def formatEqualsWithUnicodeUC(self, result, text, *args, **kwargs): + # test both the upper and lowercase versions. assume the + # result and text come in as lowercase + + text = str(text) + result = str(result) + val = pep3101.format(text, *args, **kwargs) + self.assertEquals(val, result) + + # a quick check for unicode version + val = pep3101.format(unicode(text), *args, **kwargs) + self.assertEquals(val, unicode(result)) + + # test the uppercase text version + val = pep3101.format(text.upper(), *args, **kwargs) + self.assertEquals(val, result.upper()) + + # test the uppercase unicode version + val = pep3101.format(unicode(text.upper()), *args, **kwargs) + self.assertEquals(val, unicode(result.upper())) + def formatRaises(self, exc, text, *args, **kwargs): exc = exc or Exception #StringFormat.FormatError text = str(text) @@ -169,6 +190,33 @@ self.formatEqualsWithUnicode("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) self.formatEqualsWithUnicode("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) + def test_octal_specifiers(self): + n = int("31415", 8) + + self.assertRaises(TypeError, "{0:o", "non-number") + + self.formatEqualsWithUnicode("0", "{0:o}", 0) + self.formatEqualsWithUnicode("31415", "{0:o}", n) + self.formatEqualsWithUnicode("-31415", "{0:o}", -n) + self.formatEqualsWithUnicode(" " * 995 + "31415", "{0:1000o}", n) + + n = int("314153141531415", 8) + self.formatEqualsWithUnicode("314153141531415", "{0:o}", n) + self.formatEqualsWithUnicode("-314153141531415", "{0:o}", -n) + + def test_hex_specifiers(self): + n = int("beef", 16) + + self.assertRaises(TypeError, "{0:x", "non-number") + + self.formatEqualsWithUnicodeUC("0", "{0:x}", 0) + self.formatEqualsWithUnicodeUC("beef", "{0:x}", n) + self.formatEqualsWithUnicodeUC("-beef", "{0:x}", -n) + + n = int("deadbeef", 16) + self.formatEqualsWithUnicodeUC("deadbeef", "{0:x}", n) + self.formatEqualsWithUnicodeUC("-deadbeef", "{0:x}", -n) + def test_char_specifiers(self): self.formatEquals("A", "{0:c}", "A") self.formatEquals("8", "{0:c}", "8") Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 01:45:26 2007 @@ -1008,6 +1008,19 @@ n_allocated = len; *pbuf = fs->outstr.ptr; + /* if we're hex or octal, check to see if 0 or 0x or 0X was at the + front of the string. if so, skip it. */ + if (type == 'o' && n_allocated >= 1 && *pbuf[0] == '0') { + p_charbuf++; + n_allocated -= 1; + } else if (type == 'x' && n_allocated >= 2 && *pbuf[1] == 'x') { + p_charbuf += 2; + n_allocated -= 1; + } else if (type == 'X' && n_allocated >= 2 && *pbuf[1] == 'X') { + p_charbuf += 2; + n_allocated -= 1; + } + #if C_UNICODE /* allocate space in the output string, as CH_TYPE */ ok = output_allocate(fs, n_allocated, &ptr); @@ -1015,7 +1028,7 @@ strtounicode(ptr, p_charbuf, n_allocated); } #else - ok = output_data(fs, STROBJ_AS_PTR(strobj), n_allocated); + ok = output_data(fs, p_charbuf, n_allocated); #endif /* we're done with the string representation */ From python-checkins at python.org Mon Mar 5 02:31:19 2007 From: python-checkins at python.org (eric.smith) Date: Mon, 5 Mar 2007 02:31:19 +0100 (CET) Subject: [Python-checkins] r54130 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070305013119.B0DBD1E400A@bag.python.org> Author: eric.smith Date: Mon Mar 5 02:31:11 2007 New Revision: 54130 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Removed dead code. Fixed unicode 'c' formatter and added test cases for it. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 02:31:11 2007 @@ -15,14 +15,10 @@ # overridden to change the class of string being tested # and the function being used. def formatEquals(self, result, text, *args, **kwargs): - text = str(text) - result = str(result) val = pep3101.format(text, *args, **kwargs) self.assertEquals(val, result) def formatEqualsWithUnicode(self, result, text, *args, **kwargs): - text = str(text) - result = str(result) val = pep3101.format(text, *args, **kwargs) self.assertEquals(val, result) @@ -34,8 +30,6 @@ # test both the upper and lowercase versions. assume the # result and text come in as lowercase - text = str(text) - result = str(result) val = pep3101.format(text, *args, **kwargs) self.assertEquals(val, result) @@ -120,14 +114,13 @@ # "The shiny red {0[-2]}", t) def test_formatlookup(self): - pass -# self.formatEquals("32", "{0:{1}}", 32, "0>4d") -# self.formatEquals("32", "{0:{1}{2}4{3}}", 32, "*", ">", "d") + self.formatEquals("0032", "{0:{1}}", 32, "0>4d") + self.formatEquals("**32", "{0:{1}{2}4{3}}", 32, "*", ">", "d") def test_specifiers(self): self.formatEquals("a", "{0:c}", ord("a")) self.formatEquals("8_08b", "{0:08b}", 8) -# self.formatEquals("8", "{0: >3d}", 8) + self.formatEquals(" 8", "{0: >3d}", 8) self.formatEquals("0.1515_.0%", "{0:.0%}", .1515) def test_string_specifiers(self): @@ -218,10 +211,11 @@ self.formatEqualsWithUnicodeUC("-deadbeef", "{0:x}", -n) def test_char_specifiers(self): - self.formatEquals("A", "{0:c}", "A") - self.formatEquals("8", "{0:c}", "8") - self.formatEquals(";", "{0:c}", ";") - self.formatEquals(";", "{0:c}", long(ord(";"))) + self.formatEqualsWithUnicode("A", "{0:c}", "A") + self.formatEqualsWithUnicode("8", "{0:c}", "8") + self.formatEqualsWithUnicode(";", "{0:c}", ";") + self.formatEqualsWithUnicode(";", "{0:c}", long(ord(";"))) + self.formatEquals(u"f", u"{0:c}", u"f") self.formatRaises(TypeError, "{0:c}", "abcd") Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 02:31:11 2007 @@ -886,18 +886,36 @@ format_char(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - CH_TYPE buf; + char ch; + CH_TYPE uch; if (PyString_Check(fieldobj)) { - if (!PyArg_Parse(fieldobj, "c;%c requires int or char", &buf)) + if (!PyArg_Parse(fieldobj, "c;\"c\" format requires int or char", &ch)) return 0; + /* convert to unicode, if needed */ + uch = (CH_TYPE)ch; +#if C_UNICODE + } else if (PyUnicode_Check(fieldobj)) { + CH_TYPE *ubuf; + int len; + if (!PyArg_Parse(fieldobj, "u#;\"c\" format requires int or char", &ubuf, &len)) + return 0; + + if (len != 1) { + PyErr_Format(PyExc_TypeError, "\"c\" format requires int or char"); + return 0; + } + uch = ubuf[0]; +#endif } else { - if (!PyArg_Parse(fieldobj, "b;%c requires int or char", &buf)) + if (!PyArg_Parse(fieldobj, "b;\"c\" format requires int or char", &ch)) return -1; + /* convert to unicode, if needed */ + uch = (CH_TYPE)ch; } - return output_data(fs, &buf, 1); + return output_data(fs, &uch, 1); } @@ -1353,46 +1371,6 @@ /* do the formatting, writing into the output string */ return formatter(fieldobj, fs, &format); - -#if 0 - - /* Handle the sign logic */ - prefix = '\0'; - suffix = '\0'; - if (sign == '-') { - if (format.sign == '(') { - prefix = '('; - suffix = ')'; - } else { - prefix = '-'; - } - } else if (sign == '+') { - if (format.sign == '+') { - prefix = '+'; - } else if (format.sign == ' ') { - prefix = ' '; - } - } - - /* Handle the padding logic */ - if (format.width != -1) { - padding = format.width - len - (prefix == '\0' ? 0 : 1) - - (suffix == '\0' ? 0 : 1); - if (padding > 0) { -#if 0 - if align == '>': - return fill_char * padding + prefix + result + suffix - elif align == '=' - return prefix + fill_char * padding + result + suffix - else: - return prefix + result + suffix + fill_char * padding - -#endif - } - } - - return 1; -#endif } /* From python-checkins at python.org Mon Mar 5 03:38:29 2007 From: python-checkins at python.org (patrick.maupin) Date: Mon, 5 Mar 2007 03:38:29 +0100 (CET) Subject: [Python-checkins] r54131 - sandbox/trunk/pep3101/pep3101.c sandbox/trunk/pep3101/pep3101.h sandbox/trunk/pep3101/pep_differences.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070305023829.AD13E1E400A@bag.python.org> Author: patrick.maupin Date: Mon Mar 5 03:38:25 2007 New Revision: 54131 Modified: sandbox/trunk/pep3101/pep3101.c sandbox/trunk/pep3101/pep3101.h sandbox/trunk/pep3101/pep_differences.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Reworked overall structure to support feature set as described in pep_differences.txt. All the old regression tests still pass; but I expect some of the new features enabled by the reworked structure will not work, so it's off to write lots of new regression tests. Modified: sandbox/trunk/pep3101/pep3101.c ============================================================================== --- sandbox/trunk/pep3101/pep3101.c (original) +++ sandbox/trunk/pep3101/pep3101.c Mon Mar 5 03:38:25 2007 @@ -10,6 +10,10 @@ "" ; +static char pep3101_formatitem__doc__[] = +"" +; + static PyObject * StringDispatch(ternaryfunc *table, PyObject *self, PyObject *args, PyObject *keywords) { @@ -42,11 +46,22 @@ return StringDispatch(table, self, args, keywords); } +static PyObject * +pep3101_format_item(PyObject *self, PyObject *args, PyObject *keywords) +{ + static ternaryfunc table[2] = + {PyUnicode_FormatItemMethod, PyString_FormatItemMethod}; + return StringDispatch(table, self, args, keywords); +} + /* List of methods defined in the module */ static struct PyMethodDef pep3101_methods[] = { - {"format", (PyCFunction)pep3101_format, METH_VARARGS | METH_KEYWORDS, pep3101_format__doc__}, - + {"format", (PyCFunction)pep3101_format, + METH_VARARGS | METH_KEYWORDS, pep3101_format__doc__}, + {"format_item", (PyCFunction)pep3101_format_item, + METH_VARARGS | METH_KEYWORDS, pep3101_formatitem__doc__}, + {NULL, (PyCFunction)NULL, 0, NULL} /* sentinel */ }; Modified: sandbox/trunk/pep3101/pep3101.h ============================================================================== --- sandbox/trunk/pep3101/pep3101.h (original) +++ sandbox/trunk/pep3101/pep3101.h Mon Mar 5 03:38:25 2007 @@ -9,4 +9,10 @@ PyObject * PyUnicode_FormatMethod(PyObject *self, PyObject *args, PyObject *keywords); +PyObject * +PyString_FormatItemMethod(PyObject *self, PyObject *args, PyObject *keywords); + +PyObject * +PyUnicode_FormatItemMethod(PyObject *self, PyObject *args, PyObject *keywords); + #endif Modified: sandbox/trunk/pep3101/pep_differences.txt ============================================================================== --- sandbox/trunk/pep3101/pep_differences.txt (original) +++ sandbox/trunk/pep3101/pep_differences.txt Mon Mar 5 03:38:25 2007 @@ -157,7 +157,7 @@ features discussed by the PEP into different options. It also adds an option. -The first error option is controlled by the optional _leading_underscores +The first error option is controlled by the optional _allow_leading_underscores keyword argument. If this is present and evaluates non-zero, then leading underscores are allowed on identifiers and attributes in the format string. The implementation will lazily look for this argument the first time it @@ -246,6 +246,12 @@ _dict (if any). + User specified tuple of dictionaries + +Since we need a name mapper to look up items in the keywords dictionary, +then in the passed-in dictionary, it is only a small feature creep to +allow _dict itself to be a tuple of dictionaries. + Automatic locals/globals lookup This is likely to be a contentious feature, but it seems quite useful, Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 03:38:25 2007 @@ -94,7 +94,7 @@ self.formatEquals( "Count with me; 1 2 4", "Count with me; {0.one} {item._two} {1.four4}", - Container, Container, item=Container, _flags=dict(allow_leading_under=1)) + Container, Container, item=Container, _allow_leading_underscores=1) self.formatEquals( "Five is 5", "Five is {c.five}", c=Container()) self.formatRaises(AttributeError, Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 03:38:25 2007 @@ -31,6 +31,7 @@ #define STROBJ_RESIZE PyUnicode_Resize #define STROBJ_CHECK PyUnicode_Check #define STROBJ_FORMAT PyUnicode_FormatMethod +#define STROBJ_FORMAT_ITEM PyUnicode_FormatItemMethod #define STROBJ_STR PyObject_Unicode #else #define CH_TYPE char @@ -43,6 +44,7 @@ #define STROBJ_RESIZE _PyString_Resize #define STROBJ_CHECK PyString_Check #define STROBJ_FORMAT PyString_FormatMethod +#define STROBJ_FORMAT_ITEM PyString_FormatItemMethod #define STROBJ_STR PyObject_Str #endif @@ -61,6 +63,7 @@ #define PySet_Discard PyDict_DelItem #define PySet_New PyDict_Copy #define PySet_GET_SIZE PyDict_Size +#define PySet_Contains PyDict_Contains #endif @@ -168,11 +171,14 @@ int positional_arg_set; /* Keyword arguments can be checked as well */ PyObject *keyword_arg_set; - /* For some interface functions, we could have a list or tuple of + /* For some interface functions, we could have a tuple of dictionaries to search, e.g. locals()/globals(). */ - int keywords_is_tuple; + PyObject *keywords_tuple; /* Support for different escape-to-markup syntaxes */ int syntaxmode; + /* Support for hooking render calls */ + PyObject *hookfunc; + int hookalways; } FmtState; /* Some forward declarations for recursion */ @@ -230,6 +236,176 @@ } /************************************************************************/ +/************** Keyword parameter retrieval functions *****************/ +/************************************************************************/ + +/* + Keyword parameters can come from several sources. These functions + find them. +*/ + +/* + get_keyword_tuple is called when we need to build a tuple of keyword + dictionaries. It returns 1 on success and 0 on failure. +*/ +static int +get_keyword_tuple(FmtState *fs) +{ + PyObject *dict, *temp, *keywords, *result; + int use_original, dict_is_tuple, dict_count, i; + + keywords = fs->keywords; + temp = PyString_FromString("_dict"); + if (temp == NULL) + return 0; + dict = PyDict_GetItem(keywords, temp); + Py_DECREF(temp); + if (dict == NULL) + return (int)SetError(fs, "_dict not found"); + use_original = PyDict_Size(keywords) > 1; + dict_is_tuple = PyTuple_Check(dict); + dict_count = dict_is_tuple ? PyTuple_GET_SIZE(dict) : 1; + for (i = 0; i < dict_count; i++) + if (!PyDict_Check(dict_is_tuple ? PyTuple_GET_ITEM(dict, i) : dict)) + return (int)SetError(fs, "Invalid _dict parameter"); + if (dict_is_tuple && !use_original) { + Py_INCREF(dict); + fs->keywords_tuple = dict; + return 1; + } + result = PyTuple_New(dict_count + use_original); + if (result == NULL) + return 0; + if (use_original) { + Py_INCREF(keywords); + PyTuple_SET_ITEM(result, 0, keywords); + } + for (i = 0; i < dict_count; i++) { + temp = dict_is_tuple ? PyTuple_GET_ITEM(dict, i) : dict; + Py_INCREF(temp); + PyTuple_SET_ITEM(result, i + use_original, temp); + } + fs->keywords_tuple = result; + return 1; +} + +static int +get_locals_globals(FmtState *fs) +{ + PyObject *locals, *globals, *result; + int gotglobals, gotlocals; + if ((fs->args != NULL)) + return (int)SetError(fs, "no keywords parameters available"); + locals = PyEval_GetLocals(); + gotlocals = locals != NULL; + globals = PyEval_GetGlobals(); + gotglobals = globals != NULL; + result = PyTuple_New(gotlocals + gotglobals); + if (result == NULL) + return 0; + if (gotlocals) { + Py_INCREF(locals); + PyTuple_SET_ITEM(result, 0, locals); + } + if (gotglobals) { + Py_INCREF(globals); + PyTuple_SET_ITEM(result, 0, globals); + } + fs->keywords_tuple = result; + return 1; +} + +/* + name_mapper searches the "namespace" for the given key and returns + the first object found bound to that name. + + The search of the namespace logically proceeds as follows: + + 1) The keywords argument dictionary passed into the main function + (if any) is searched. + 2) If a keyword argument _dict was given: + a) If it was a sequence, the dictionaries in the sequence + are searched in order; or + b) If it was a dictionary, it is searched. + 3) If no keywords arguments were passed into the main function, + and no positional arguments were passed in either, a search + of the caller's locals() and globals() is performed. + + For efficiency, the actual search does not proceed exactly like + this. +*/ +static PyObject * +name_mapper(FmtState *fs, PyObject *key) +{ + PyObject *result; + int index, lastindex; + + if (fs->keywords_tuple == NULL) { + if (fs->keywords != NULL) { + if ((result = PyDict_GetItem(fs->keywords, key)) != NULL) { + Py_INCREF(result); + return result; + } + if (!get_keyword_tuple(fs)) + return NULL; + } + else if (!get_locals_globals(fs)) + return NULL; + } + lastindex = PyTuple_GET_SIZE(fs->keywords_tuple)-1; + for (index=0; index <= lastindex; index++) { + result = PyDict_GetItem(PyTuple_GET_ITEM(fs->keywords_tuple, index), key); + if (result != NULL) { + Py_INCREF(result); + return result; + } + } + return SetError(fs, "name lookup failed"); +} + +static PyObject * +read_parameter(FmtState *fs, const char *keyword) +{ + PyObject *result; + PyObject *k = PyString_FromString(keyword); + if (k == NULL) + return NULL; + result = name_mapper(fs, k); + Py_DECREF(k); + return result; +} + +static int +read_bool_parameter(FmtState *fs, const char *keyword) +{ + PyObject *obj; + int result; + obj = read_parameter(fs, keyword); + if (obj == NULL) + return -1; + result = PyObject_IsTrue(obj); + Py_DECREF(obj); + return result; +} + +static int +read_allow_under_parameter(FmtState *fs) +{ + int result = read_bool_parameter(fs, "_allow_leading_underscores"); + result = fs->allow_leading_under = (result > 0); + return result; +} + +static int +read_hook_parameter(FmtState *fs) +{ + if (fs->hookfunc != NULL) + fs->hookfunc = read_parameter(fs, "_hook"); + return (fs->hookfunc != NULL) || + SetError(fs, "No _hook function supplied"); +} + +/************************************************************************/ /*********** Output string management functions ****************/ /************************************************************************/ @@ -392,7 +568,7 @@ /* This little bit of mutual recursion allows nested dictionary lookups and computed attribute names */ - if (--fs->max_recursion < 0) + if (--(fs->max_recursion) < 0) return SetError(fs, "Maximum string recursion limit exceeded"); result = get_field_object(fs); fs->max_recursion++; @@ -402,7 +578,9 @@ } if (end_identifier(*fs->fmtstr.ptr)) return SetError(fs, "Expected attribute or index"); - if ((*fs->fmtstr.ptr == '_') && !fs->allow_leading_under) + if ((*fs->fmtstr.ptr == '_') && + !fs->allow_leading_under && + !read_allow_under_parameter(fs)) return SetError(fs, "Leading underscores not allowed in attribute/index strings"); @@ -446,37 +624,14 @@ */ /* - If keywords are supplied as a sequence of dictionaries - (e.g. locals/globals) then name_mapper will do multiple - lookups until it finds the right information. This - should not be called (keywords_is_tuple should not be - set) unless fs->keywords is a tuple. -*/ -static PyObject * -name_mapper(PyObject *keywords, PyObject *key) -{ - PyObject *result; - int index; - int lastindex = PyTuple_GET_SIZE(keywords)-1; - - for (index=0;; index++) { - result = PyObject_GetItem(PyTuple_GET_ITEM(keywords, index), key); - if (result != NULL) { - Py_INCREF(result); - return result; - } - if (index >= lastindex) - return NULL; - PyErr_Clear(); - } -} - -/* get_specifier retrieves the part of the format string between the colon and trailing }. + + It is also used to parse past comments and format + metadata. */ static int -get_specifier(FmtState *fs) +get_specifier(FmtState *fs, int allow_recursion) { CH_TYPE c; @@ -501,7 +656,7 @@ } } fs->fieldspec.end = fs->fmtstr.ptr - 1; - if (gotcurly) { + if (gotcurly && allow_recursion) { PyObject *myobject; SubString savefmt = fs->fmtstr; fs->fmtstr.ptr = fs->fieldspec.ptr; @@ -527,27 +682,20 @@ PyObject *myobj, *subobj, *newobj; CH_TYPE c; Py_ssize_t index; - int isindex, expectclose, isnumeric, isargument; + int isindex, isnumeric, isargument; - index = 0; /* Just to shut up the compiler warning */ - if (!check_fmtstr(fs)) - return NULL; - isargument=1; - isnumeric = (CH_TYPE_ISDECIMAL(*fs->fmtstr.ptr)); - myobj = isnumeric ? fs->args : fs->keywords; - if (myobj == NULL) - goto ERROR; + index = isnumeric = 0; /* Just to shut up the compiler warnings */ + ; + myobj = fs->args; Py_INCREF(myobj); - for (isindex=1, expectclose=0;;) { + for (isindex=1, isargument=1;;) { if (!check_fmtstr(fs)) break; if (!isindex) { if ((subobj = get_python_identifier(fs, isargument)) == NULL) break; - newobj = (isargument && fs->keywords_is_tuple) - ? name_mapper(myobj, subobj) - : PyObject_GetAttr(myobj, subobj); + newobj = PyObject_GetAttr(myobj, subobj); Py_DECREF(subobj); } else { @@ -570,7 +718,9 @@ get_python_identifier(fs, isargument); if (subobj == NULL) break; - newobj = PyObject_GetItem(myobj, subobj); + newobj = isargument + ? name_mapper(fs, subobj) + : PyObject_GetItem(myobj, subobj); Py_DECREF(subobj); } } @@ -578,7 +728,7 @@ myobj = newobj; if (myobj == NULL) break; - if (expectclose) + if (!isargument && isindex) if ((!check_fmtstr(fs)) || (*fs->fmtstr.ptr++ != ']')) { SetError(fs, "Expected ]"); break; @@ -590,13 +740,12 @@ return myobj; fs->fmtstr.ptr++; isargument = 0; - isindex = expectclose = (c == '['); + isindex = (c == '['); if (!isindex && (c != '.')) { SetError(fs, "Expected ., [, :, or }"); break; } } -ERROR: if ((myobj == NULL) && isargument) { PyErr_Clear(); @@ -626,7 +775,7 @@ if (myobj != NULL) { if (check_fmtstr(fs)) { c = *fs->fmtstr.ptr++; - if ((c == '}') || ((c == ':') && (get_specifier(fs)))) + if ((c == '}') || ((c == ':') && (get_specifier(fs, 1)))) return myobj; } Py_DECREF(myobj); @@ -643,7 +792,7 @@ object and field specification string generated by get_field_and_spec, and renders the field into the output string. - The two main subfunctions of render_field are caller_render (which + The two main subfunctions of render_field are object_self_render (which calls the object-supplied __format__ hook), and internal_render, which renders objects which don't have format hooks. */ @@ -1373,24 +1522,28 @@ return formatter(fieldobj, fs, &format); } +static PyObject * +get_field_spec_obj(FmtState *fs) +{ + PyObject *result = fs->fieldspec.obj; + if (result == NULL) { + result = STROBJ_NEW(fs->fieldspec.ptr, + fs->fieldspec.end - fs->fieldspec.ptr); + fs->fieldspec.obj = result; /* Owned by someone else now... */ + } + return result; +} + /* - caller_render is invoked to format an object with a defined __format__ + object_self_render is invoked to format an object with a defined __format__ attribute. */ static int -caller_render(FmtState *fs, PyObject *__format__) +object_self_render(FmtState *fs, PyObject *__format__) { - PyObject *myobj; int ok; + PyObject *myobj = get_field_spec_obj(fs); - myobj = fs->fieldspec.obj; - if (myobj == NULL) { - myobj = STROBJ_NEW(fs->fieldspec.ptr, - fs->fieldspec.end - fs->fieldspec.ptr); - if (myobj == NULL) - return 0; - fs->fieldspec.obj = myobj; /* Owned by our caller now */ - } /* XXX -- possible optimization to CallFunctionWithArgs */ myobj = PyObject_CallFunction(__format__, "(O)", myobj); if (myobj == NULL) @@ -1406,6 +1559,41 @@ } /* + hook_render is invoked to format an object with the hook callback. + Returns -1 for err, 1 if did it, 0 if didn't +*/ +static int +hook_render(FmtState *fs, PyObject *fieldobj) +{ + int result; + PyObject *strobj; + PyObject *specobj = get_field_spec_obj(fs); + + if ((specobj == NULL) || + ((fs->hookfunc == NULL) && + !read_hook_parameter(fs))) + return -1; + + /* XXX -- possible optimization to CallFunctionWithArgs */ + strobj = PyObject_CallFunction(fs->hookfunc, "(OO)", fieldobj, specobj); + if (strobj == NULL) + return -1; + result = (strobj != Py_None); + if (result) { + if (!STROBJ_CHECK(strobj)) { + result = -1; + SetError(fs, + "hook or __format__ method did not return correct string type"); + } + else + result = output_data(fs, STROBJ_AS_PTR(strobj), + STROBJ_GET_SIZE(strobj)) ? 1 : -1; + } + Py_DECREF(strobj); + return result; +} + +/* render_field determines if the field object has a defined __format__ method, and dispatches to the appropriate subfunction. */ @@ -1414,10 +1602,19 @@ { int result; SubString savefmt; + PyObject *__format__; - PyObject *__format__ = PyObject_GetAttrString(fieldobj, "__format__"); + if (fs->hookalways || + ((fs->fieldspec.ptr < fs->fieldspec.end) && + fs->fieldspec.end[-1] == 'p')) { + result = hook_render(fs, fieldobj); + if (result != 0) + return result == 1; + } + + __format__ = PyObject_GetAttrString(fieldobj, "__format__"); if (__format__ != NULL) { - result = caller_render(fs, __format__); + result = object_self_render(fs, __format__); Py_DECREF(__format__); } else { @@ -1438,6 +1635,60 @@ return result; } +static int +check_keyword(const CH_TYPE *ptr, const char *expected, int count) +{ + while (count--) + if (*ptr++ != *expected++) + return 0; + return 1; +} + +static int +process_metadata(FmtState *fs) +{ + CH_TYPE *ptr; + int count; + + if (!get_specifier(fs, 0)) + return 0; + if ((fs->fmtstr.ptr < fs->fmtstr.end) && (*fs->fmtstr.ptr == '\r')) + fs->fmtstr.ptr++; + if ((fs->fmtstr.ptr < fs->fmtstr.end) && (*fs->fmtstr.ptr == '\n')) + fs->fmtstr.ptr++; + ptr = fs->fieldspec.ptr; + count = fs->fieldspec.end - ptr; + switch (*ptr) { + case 'u': + if ((count == 6) && check_keyword(ptr, "useall", count)) { + fs->positional_arg_set = (1 << fs->num_args) - 1; + if (fs->keywords) { + Py_XDECREF(fs->keyword_arg_set); + fs->keyword_arg_set = PySet_New(fs->keywords); + if (fs->keyword_arg_set == NULL) + return 0; + } + return 1; + } + break; + case 'h': + if ((count == 4) && check_keyword(ptr, "hook", count)) { + fs->hookalways = 1; + return read_hook_parameter(fs); + } + break; + case 's': + if ((count == 7) && check_keyword(ptr, "syntax", 6)) { + int mode = CH_TYPE_TODECIMAL(ptr[6]); + if ((mode < 0) || (mode > 3)) + return (int)SetError(fs, "Invalid syntax mode"); + fs->syntaxmode = mode; + return 1; + } + } + return (int)SetError(fs, "Invalid string metadata keyword"); +} + /* get_field_and_render calls get_field_and_spec to get the field object and specification, then calls @@ -1446,15 +1697,20 @@ static int get_field_and_render(FmtState *fs) { - PyObject *myobj; - int ok; - fs->fieldstart = fs->fmtstr.ptr; - myobj = get_field_and_spec(fs); - ok = (myobj != NULL) && render_field(fs, myobj); - Py_XDECREF(myobj); - Py_XDECREF(fs->fieldspec.obj); - return ok; + switch (*fs->fmtstr.ptr) { + case '#': + return get_specifier(fs, 0); + case '!': + return process_metadata(fs); + default: { + PyObject *myobj = get_field_and_spec(fs); + int ok = (myobj != NULL) && render_field(fs, myobj); + Py_XDECREF(myobj); + Py_XDECREF(fs->fieldspec.obj); + return ok; + } + } } /************************************************************************/ @@ -1550,11 +1806,11 @@ } /* - do_format allocates the output string and then + build_string allocates the output string and then calls a markup handler to do the dirty work. */ static PyObject * -do_format(FmtState *fs) +build_string(FmtState *fs) { PyObject *myobj; int ok; @@ -1581,7 +1837,7 @@ /* recurse_format is called for nested format specifiers, e.g. {1:{2}}. It saves off the current information, - and recursively calls do_format. + and recursively calls build_string. */ static PyObject * recurse_format(FmtState *fs) @@ -1591,7 +1847,7 @@ int saveincrement = fs->size_increment; if (--(fs->max_recursion) < 0) return SetError(fs, "Max string recursion exceeded"); - result = do_format(fs); + result = build_string(fs); fs->max_recursion++; fs->outstr = saveoutstr; fs->size_increment = saveincrement; @@ -1603,58 +1859,11 @@ /************************************************************************/ static int -get_options(PyObject *keywords, FmtState *fs) -{ - static char* keys[3] = { - "useall", "allow_leading_under", NULL - }; - int values[2]; - int index; - - PyObject *flags, *myobj; - - fs->max_recursion = 4; - fs->allow_leading_under = 0; - fs->positional_arg_set = 0; - fs->keyword_arg_set = NULL; - fs->keywords_is_tuple = 0; - fs->syntaxmode = 0; - fs->do_markup = do_markup; - fs->keywords = keywords; - - if (keywords == NULL) - return 1; - - flags = PyDict_GetItemString(keywords, "_flags"); - if (flags == NULL) - return 1; - - for (index=0; keys[index] != NULL; index++) { - myobj = PyDict_GetItemString(flags, keys[index]); - if (myobj == NULL) - values[index] = 0; - else if (PyInt_Check(myobj)) - values[index] = PyInt_AS_LONG(myobj); - else { - PyErr_SetString(PyExc_TypeError, - "All flags values must be integers"); - return 0; - } - } - if (values[0]) { - fs->positional_arg_set = (1 << fs->num_args) - 1; - fs->keyword_arg_set = PySet_New(keywords); - if (!fs->keyword_arg_set) - return 0; - } - fs->allow_leading_under = values[1]; - return 1; -} - -static int get_self_args(PyObject *self, PyObject *args, FmtState *fs) { + memset(fs, 0, sizeof(*fs)); fs->num_args = PyTuple_GET_SIZE(args); + fs->args = args; if (self == NULL) { if (!fs->num_args) { PyErr_SetString(PyExc_TypeError, @@ -1670,49 +1879,110 @@ fs->arg_param_offset = 1; fs->num_args -= 1; } - else - fs->arg_param_offset = 0; - fs->args = args; fs->fmtstr.ptr = fs->fmtstart = STROBJ_AS_PTR(self); fs->fmtstr.end = fs->fmtstr.ptr + STROBJ_GET_SIZE(self); return 1; } static PyObject * -fs_cleanup(PyObject *result, FmtState *fs) +check_args_consumed(FmtState *fs, PyObject *result) { - PyObject *used; - int ok = result != NULL; - used = fs->keyword_arg_set; - if (ok && used) { - ok = (PySet_GET_SIZE(used) <= 1) && !fs->positional_arg_set; - if (!ok) { + static const char* ignore[] = { + "_dict", + "_allow_leading_underscores", + "_hook", + NULL}; + + int num_unused, i, contains; + PyObject *used = fs->keyword_arg_set; + if (result != NULL) { + num_unused = fs->positional_arg_set; + if (!num_unused) { + num_unused = PySet_GET_SIZE(used); + i = 0; + while (num_unused && (ignore[i] != NULL)) { + PyObject *temp= PyString_FromString(ignore[i++]); + if ((temp==NULL) || + ((contains = PySet_Contains(used, temp)) < 0)) { + Py_DECREF(used); + Py_XDECREF(temp); + return NULL; + } + num_unused -= contains; + } + } + if (num_unused) { Py_DECREF(result); result = SetError(fs, "Not all arguments consumed"); } } - Py_XDECREF(used); + Py_DECREF(used); return result; } /* STROBJ_FORMAT (actually PyUnicode_FormatMethod or PyString_FormatMethod) - is the public interface to the module. - - XXX -- do we need to check input types here, or are we guaranteed - they are right???? + is the main public interface to the module. */ PyObject * STROBJ_FORMAT(PyObject *self, PyObject *args, PyObject *keywords) { FmtState fs; + PyObject *result; + + if (!get_self_args(self, args, &fs)) + return NULL; + + fs.max_recursion = 4; + fs.do_markup = do_markup; + fs.keywords = keywords; + + result = build_string(&fs); + Py_XDECREF(fs.keywords_tuple); + Py_XDECREF(fs.hookfunc); + return (fs.keyword_arg_set != NULL) + ? check_args_consumed(&fs, result) + : result; +} + +/* + single_field_markup is the markup processor for FormatItem +*/ +static int +single_field_markup(FmtState *fs) +{ + return render_field(fs, PyTuple_GET_ITEM(fs->args, fs->arg_param_offset)); +} + +/* + STROBJ_FORMAT_ITEM (actually PyUnicode_FormatItemMethod or + PyString_FormatItemMethod) is another interface to this + module, to allow external code to access our internal + single-field formatter. +*/ +PyObject * +STROBJ_FORMAT_ITEM(PyObject *self, PyObject *args, PyObject *keywords) +{ + FmtState fs; + PyObject *result; - /* This function can be called as a python function or as a method */ - if (!get_self_args(self, args, &fs) || - !get_options(keywords, &fs)) + if (!get_self_args(self, args, &fs)) return NULL; - return fs_cleanup(do_format(&fs), &fs); + if (fs.num_args != 1) { + PyErr_SetString(PyExc_TypeError, + "Function self plus one positional argument"); + return 0; + } + fs.do_markup = single_field_markup; + fs.keywords = keywords; + fs.fieldspec.ptr = fs.fmtstr.ptr; + fs.fieldspec.end = fs.fmtstr.end; + + result = build_string(&fs); + Py_XDECREF(fs.keywords_tuple); + Py_XDECREF(fs.hookfunc); + return result; } #ifdef __cplusplus From python-checkins at python.org Mon Mar 5 04:23:05 2007 From: python-checkins at python.org (patrick.maupin) Date: Mon, 5 Mar 2007 04:23:05 +0100 (CET) Subject: [Python-checkins] r54132 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070305032305.3D3D11E400A@bag.python.org> Author: patrick.maupin Date: Mon Mar 5 04:23:01 2007 New Revision: 54132 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Added tests for name_mapper and made them pass Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 04:23:01 2007 @@ -3,6 +3,10 @@ import pep3101 +# Variables used for testing name mapper +global1 = 10 +global2 = 20 +global3 = 30 # The test implementation does not allow an argument # index or keyword name to be used more than once. The @@ -253,6 +257,21 @@ self.formatRaises(ValueError, "{{ {{{0}}", True) self.formatRaises(ValueError, "{0}}", True) + def test_name_mapper(self): + mydict = dict(foo=1, bar=2) + dict2 = mydict, dict(foobar=3) + foo = 27 + global3 = 50 + self.formatRaises(ValueError, "{foo}") + self.formatRaises(ValueError, "{foo} {foobar}", _dict=mydict) + self.formatEquals("1", "{foo}", _dict=mydict) + self.formatEquals("1 2", "{foo} {bar}", _dict=mydict) + self.formatRaises(ValueError, "{foo} {bar} {global3}", _dict=mydict) + self.formatEquals("1 2 3", "{foo} {bar} {foobar}", _dict=dict2) + self.formatEquals("27 2", "{foo} {bar}", _dict=mydict, foo=foo) + self.assertEquals( + pep3101.format("{foo} {global3} {global1}"), + "27 50 10") def test_main(): test_support.run_unittest(FormatTest) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 04:23:01 2007 @@ -294,7 +294,8 @@ { PyObject *locals, *globals, *result; int gotglobals, gotlocals; - if ((fs->args != NULL)) + + if (!PyTuple_GET_SIZE(fs->args)) return (int)SetError(fs, "no keywords parameters available"); locals = PyEval_GetLocals(); gotlocals = locals != NULL; @@ -309,7 +310,7 @@ } if (gotglobals) { Py_INCREF(globals); - PyTuple_SET_ITEM(result, 0, globals); + PyTuple_SET_ITEM(result, gotlocals, globals); } fs->keywords_tuple = result; return 1; @@ -1971,7 +1972,7 @@ if (fs.num_args != 1) { PyErr_SetString(PyExc_TypeError, - "Function self plus one positional argument"); + "Function expects self plus one positional argument"); return 0; } fs.do_markup = single_field_markup; From python-checkins at python.org Mon Mar 5 05:02:13 2007 From: python-checkins at python.org (patrick.maupin) Date: Mon, 5 Mar 2007 05:02:13 +0100 (CET) Subject: [Python-checkins] r54133 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070305040213.DB1961E400A@bag.python.org> Author: patrick.maupin Date: Mon Mar 5 05:02:08 2007 New Revision: 54133 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Added tests for {!useall} and made them pass. Also, removed call that was failing for Eric under Python 2.3. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 05:02:08 2007 @@ -273,6 +273,23 @@ pep3101.format("{foo} {global3} {global1}"), "27 50 10") + def test_check_unused(self): + mydict = dict(foo=1, foo2=1) + bar = 3 + bar2 = 4 + s = '{0} {1} {foo} {bar}' + s2 = '{!useall}' + s + self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals('a b 1 3', s2, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals('a b 1 3', s, 'a', 'b', 3, bar=bar, _dict=mydict) + self.formatRaises(ValueError, s2, 'a', 'b', 3, bar=bar, _dict=mydict) + self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, _dict=mydict, sam=27) + self.formatRaises(ValueError, s2, 'a', 'b', bar=bar, _dict=mydict, sam=27) + self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, foo=1) + self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, foo=1) + self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, foo=1, sam=27) + self.formatRaises(ValueError, s2, 'a', 'b', bar=bar, foo=1, sam=27) + def test_main(): test_support.run_unittest(FormatTest) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 05:02:08 2007 @@ -63,7 +63,6 @@ #define PySet_Discard PyDict_DelItem #define PySet_New PyDict_Copy #define PySet_GET_SIZE PyDict_Size -#define PySet_Contains PyDict_Contains #endif @@ -1703,6 +1702,7 @@ case '#': return get_specifier(fs, 0); case '!': + fs->fmtstr.ptr++; return process_metadata(fs); default: { PyObject *myobj = get_field_and_spec(fs); @@ -1894,7 +1894,7 @@ "_hook", NULL}; - int num_unused, i, contains; + int i, num_unused; PyObject *used = fs->keyword_arg_set; if (result != NULL) { num_unused = fs->positional_arg_set; @@ -1903,13 +1903,13 @@ i = 0; while (num_unused && (ignore[i] != NULL)) { PyObject *temp= PyString_FromString(ignore[i++]); - if ((temp==NULL) || - ((contains = PySet_Contains(used, temp)) < 0)) { + if (temp==NULL) { Py_DECREF(used); - Py_XDECREF(temp); return NULL; } - num_unused -= contains; + PySet_Discard(used, temp); + Py_DECREF(temp); + num_unused = PySet_GET_SIZE(used); } } if (num_unused) { From python-checkins at python.org Mon Mar 5 06:53:30 2007 From: python-checkins at python.org (patrick.maupin) Date: Mon, 5 Mar 2007 06:53:30 +0100 (CET) Subject: [Python-checkins] r54134 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070305055330.1D52B1E400B@bag.python.org> Author: patrick.maupin Date: Mon Mar 5 06:53:26 2007 New Revision: 54134 Modified: sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: More tests; fixed bugs in hook function and alternate syntax 2 Modified: sandbox/trunk/pep3101/README.txt ============================================================================== --- sandbox/trunk/pep3101/README.txt (original) +++ sandbox/trunk/pep3101/README.txt Mon Mar 5 06:53:26 2007 @@ -54,12 +54,11 @@ - document differences between PEP and implementation (in pep_differences.txt) - Add docstrings to module - - Add keyword options and string metadata options - as described in pep_differences. - - Play with possible implementations for exposing - lowest level format specifier handler for use in - compatible template systems. - Should we have stricter checking on format strings? For example type "s" doesn't allow a sign character. Should specifying one be an error? - Test suite needs to check for specific exceptions. + - Add capability to control exception handling to pep_differences + and to code: 1) ability to dump exceptions into string, 2) + ability to re-do lower exceptions or "pile-on" + Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 06:53:26 2007 @@ -277,19 +277,53 @@ mydict = dict(foo=1, foo2=1) bar = 3 bar2 = 4 - s = '{0} {1} {foo} {bar}' + result = ' a b 1 3' + s = ' {0} {1} {foo} {bar}' s2 = '{!useall}' + s - self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, _dict=mydict) - self.formatEquals('a b 1 3', s2, 'a', 'b', bar=bar, _dict=mydict) - self.formatEquals('a b 1 3', s, 'a', 'b', 3, bar=bar, _dict=mydict) + s3 = '{!useall}\r\n' + s + s4 = '{!useall}\n' + s + s5 = '{!useall}\r\n' + s + self.formatEquals(result, s, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s2, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s3, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s4, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s5, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s, 'a', 'b', 3, bar=bar, _dict=mydict) self.formatRaises(ValueError, s2, 'a', 'b', 3, bar=bar, _dict=mydict) - self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, _dict=mydict, sam=27) + self.formatEquals(result, s, 'a', 'b', bar=bar, _dict=mydict, sam=27) self.formatRaises(ValueError, s2, 'a', 'b', bar=bar, _dict=mydict, sam=27) - self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, foo=1) - self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, foo=1) - self.formatEquals('a b 1 3', s, 'a', 'b', bar=bar, foo=1, sam=27) + self.formatEquals(result, s, 'a', 'b', bar=bar, foo=1) + self.formatEquals(result, s, 'a', 'b', bar=bar, foo=1) + self.formatEquals(result, s, 'a', 'b', bar=bar, foo=1, sam=27) self.formatRaises(ValueError, s2, 'a', 'b', bar=bar, foo=1, sam=27) + def test_comments(self): + self.formatEquals('Hi there','''{#Comment}Hi{# + This is a comment}{#Another} th{#comment}ere{#}''') + + def test_format_hook(self): + def hookfunc(obj, spec): + if obj > 100: + return None + return '_%s_' % (obj, spec)[obj==3] + self.formatEquals('_a_ _4_ 123', + '{!hook}{0:a} {1:b}{2:>10d}', + 3, 4, 123, _hook=hookfunc) + self.formatEquals('_ap_ _4_ 123', + '{0:ap} {1:bp}{2:>10d}', + 3, 4, 123, _hook=hookfunc) + self.formatRaises(ValueError, '{0:ap}') + self.formatEquals('_ap_', '{0:ap}', 3, _hook=hookfunc) + self.formatRaises(ValueError, '{0:ap}', 123, _hook=hookfunc) + + def test_alt_syntax(self): + self.formatEquals('{}1', '{!syntax1}{{}{0}', 1) + self.formatEquals('{ ${ 1 $1 $${0}', + '{!syntax2}{ $${ ${0} $$${0} $$$${0}', + 1) + self.formatEquals('1 {0} {\n0}', + '{!syntax3}{0} { 0} {\n0}', 1) + def test_main(): test_support.run_unittest(FormatTest) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 06:53:26 2007 @@ -399,7 +399,7 @@ static int read_hook_parameter(FmtState *fs) { - if (fs->hookfunc != NULL) + if (fs->hookfunc == NULL) fs->hookfunc = read_parameter(fs, "_hook"); return (fs->hookfunc != NULL) || SetError(fs, "No _hook function supplied"); @@ -1740,7 +1740,7 @@ switch (c = *ptr++) { case '{': if ((syntaxmode == 2) && - ((ptr == start) || (ptr[-2] != '$'))) + ((ptr == start+1) || (ptr[-2] != '$'))) continue; break; case '}': @@ -1769,12 +1769,19 @@ else count--; break; - case 2: - count -= 2; - escape = !count || (ptr[-3] != '$'); + case 2: { + CH_TYPE *first_dollar = ptr - 2; + int num_dollars; + while ((first_dollar > start) && + (first_dollar[-1] == '$')) + first_dollar--; + num_dollars = ptr - 1 - first_dollar; + count = first_dollar - start + (num_dollars / 2); + escape = num_dollars & 1; if (!escape) ptr--; break; + } case 3: switch (*ptr) { case ' ': @@ -1800,8 +1807,12 @@ fs->fmtstr.ptr = ptr; if (count && !output_data(fs, start, count)) return 0; - if (escape && !get_field_and_render(fs)) - return 0; + if (escape) { + if (!get_field_and_render(fs)) + return 0; + else + syntaxmode = fs->syntaxmode; + } } return 1; } From python-checkins at python.org Mon Mar 5 07:34:26 2007 From: python-checkins at python.org (patrick.maupin) Date: Mon, 5 Mar 2007 07:34:26 +0100 (CET) Subject: [Python-checkins] r54135 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070305063426.5F3351E400B@bag.python.org> Author: patrick.maupin Date: Mon Mar 5 07:34:22 2007 New Revision: 54135 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: More alt-syntax checks and a fix for markup escape at string end on syntax 2 Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 07:34:22 2007 @@ -318,11 +318,22 @@ def test_alt_syntax(self): self.formatEquals('{}1', '{!syntax1}{{}{0}', 1) - self.formatEquals('{ ${ 1 $1 $${0}', - '{!syntax2}{ $${ ${0} $$${0} $$$${0}', + self.formatEquals('{ ${ 1 $1 $${0} ${', + '{!syntax2}{ $${ ${0} $$${0} $$$${0} $${', 1) self.formatEquals('1 {0} {\n0}', '{!syntax3}{0} { 0} {\n0}', 1) + self.formatRaises(ValueError, '}') + self.formatRaises(ValueError, '{') + self.formatEquals('}', '{!syntax1}}') + self.formatRaises(ValueError, '{!syntax1}{') + self.formatEquals('}', '{!syntax2}}') + self.formatEquals('{', '{!syntax2}{') + self.formatRaises(ValueError, '{!syntax1}${') + self.formatEquals('${', '{!syntax2}$${') + self.formatEquals('}', '{!syntax3}}') + self.formatRaises(ValueError, '{!syntax3}{') + self.formatEquals('{', '{!syntax3}{ ') def test_main(): test_support.run_unittest(FormatTest) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 07:34:22 2007 @@ -1729,7 +1729,7 @@ { CH_TYPE c, *start, *ptr, *end; Py_ssize_t count; - int syntaxmode, escape; + int syntaxmode, escape, at_end; end = fs->fmtstr.end; syntaxmode = fs->syntaxmode; @@ -1753,61 +1753,61 @@ escape = 1; break; } + fs->fmtstr.ptr = ptr; count = ptr - start; - if (ptr < end) { - switch (syntaxmode) { - case 0: - if ((c == '}') && (c != *ptr)) { - fs->fmtstr.ptr = ptr; - return (int)SetError(fs, "Single } encountered"); - } - case 1: - if (c == *ptr) { - ptr++; - escape = 0; - } - else - count--; - break; - case 2: { - CH_TYPE *first_dollar = ptr - 2; - int num_dollars; - while ((first_dollar > start) && - (first_dollar[-1] == '$')) - first_dollar--; - num_dollars = ptr - 1 - first_dollar; - count = first_dollar - start + (num_dollars / 2); - escape = num_dollars & 1; - if (!escape) - ptr--; + at_end = ptr >= end; + switch (syntaxmode) { + case 0: + if ((c == '}') && (!at_end) && (c != *ptr)) + return (int)SetError(fs, "Single } encountered"); + case 1: + if (at_end) break; + if (c == *ptr) { + fs->fmtstr.ptr++; + escape = 0; } - case 3: - switch (*ptr) { - case ' ': - ptr++; - case '\n': case '\r': - escape = 0; - break; - default: - count--; - break; - } + else + count--; + break; + case 2: { + CH_TYPE *first_dollar = ptr - 2; + int num_dollars; + if (!escape) break; - default: - fs->fmtstr.ptr = ptr; - return (int)SetError(fs, "Unsupported syntax mode"); + while ((first_dollar > start) && + (first_dollar[-1] == '$')) + first_dollar--; + num_dollars = ptr - 1 - first_dollar; + count = first_dollar - start + (num_dollars / 2); + escape = num_dollars & 1; + if (!escape) + fs->fmtstr.ptr--; + break; } - } - else if (escape) { - fs->fmtstr.ptr = ptr; - return (int)SetError(fs, "Unexpected escape to markup"); + case 3: + if (at_end) + break; + switch (*ptr) { + case ' ': + fs->fmtstr.ptr++; + case '\n': case '\r': + escape = 0; + break; + default: + count--; + break; + } + break; + default: + return (int)SetError(fs, "Unsupported syntax mode"); } - fs->fmtstr.ptr = ptr; if (count && !output_data(fs, start, count)) return 0; if (escape) { + if (at_end) + return (int)SetError(fs, "Unexpected escape to markup"); if (!get_field_and_render(fs)) return 0; else From python-checkins at python.org Mon Mar 5 08:52:03 2007 From: python-checkins at python.org (neal.norwitz) Date: Mon, 5 Mar 2007 08:52:03 +0100 (CET) Subject: [Python-checkins] r54136 - python/trunk/Misc/developers.txt Message-ID: <20070305075203.4E8511E400B@bag.python.org> Author: neal.norwitz Date: Mon Mar 5 08:52:01 2007 New Revision: 54136 Modified: python/trunk/Misc/developers.txt Log: Added Pete for 3101 too Modified: python/trunk/Misc/developers.txt ============================================================================== --- python/trunk/Misc/developers.txt (original) +++ python/trunk/Misc/developers.txt Mon Mar 5 08:52:01 2007 @@ -17,6 +17,9 @@ Permissions History ------------------- +- Pete Shinners was given SVN access on 04 Mar 2007 by NCN, + for PEP 3101 work in the sandbox. + - Pat Maupin and Eric V. Smith were given SVN access on 28 Feb 2007 by NCN, for PEP 3101 work in the sandbox. From python-checkins at python.org Mon Mar 5 13:05:30 2007 From: python-checkins at python.org (eric.smith) Date: Mon, 5 Mar 2007 13:05:30 +0100 (CET) Subject: [Python-checkins] r54137 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070305120530.941B91E4015@bag.python.org> Author: eric.smith Date: Mon Mar 5 13:05:29 2007 New Revision: 54137 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Completed all floating point formats, with tests. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 5 13:05:29 2007 @@ -125,7 +125,7 @@ self.formatEquals("a", "{0:c}", ord("a")) self.formatEquals("8_08b", "{0:08b}", 8) self.formatEquals(" 8", "{0: >3d}", 8) - self.formatEquals("0.1515_.0%", "{0:.0%}", .1515) + self.formatEquals("15%", "{0:.0%}", .1515) def test_string_specifiers(self): self.formatEqualsWithUnicode("abc", "{0:.3s}", "abc") @@ -232,6 +232,22 @@ # XXX this should raise, but instead gives a DeprecationWarning #self.formatRaises(TypeError, "{0:c}", 3.14) + def test_exponent_specifiers(self): + self.formatEqualsWithUnicodeUC("3.141500e+00", "{0:e}", 3.1415) + self.formatEqualsWithUnicodeUC("3.1415000000e+00", "{0:.10e}", 3.1415) + + def test_fixed_specifiers(self): + self.formatEqualsWithUnicode("3.141500", "{0:f}", 3.1415) + self.formatEqualsWithUnicode("3.1415000000", "{0:.10f}", 3.1415) + self.formatEqualsWithUnicode("3.1415e+200", "{0:f}", 3.1415e200) + self.formatEqualsWithUnicode("3.1415e+200", "{0:F}", 3.1415e200) + + def test_general_specifiers(self): + self.formatEqualsWithUnicodeUC("3.1415", "{0:g}", 3.1415) + self.formatEqualsWithUnicodeUC("3.1415", "{0:.10g}", 3.1415) + self.formatEqualsWithUnicodeUC("3.1415e+200", "{0:g}", 3.1415e200) + self.formatEqualsWithUnicodeUC("3.1415e+200", "{0:g}", 3.1415e200) + def test_missing_type_specifier(self): # make sure floats use 'g', ints and longs 'd', and everything else 's' pass Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 5 13:05:29 2007 @@ -60,9 +60,10 @@ #define MAX_SIZE_INCREMENT 3200 #if PYTHON_API_VERSION < 1013 -#define PySet_Discard PyDict_DelItem -#define PySet_New PyDict_Copy -#define PySet_GET_SIZE PyDict_Size +#define PySet_Discard PyDict_DelItem +#define PySet_New PyDict_Copy +#define PySet_GET_SIZE PyDict_Size +#define PyOS_ascii_formatd PyOS_snprintf #endif @@ -74,7 +75,6 @@ + 1 + 1 = 24 */ #define MAXLEN_INT_STRING 64 - /************************************************************************/ /*********** Global data structures and forward declarations *********/ /************************************************************************/ @@ -1142,8 +1142,8 @@ #if C_UNICODE len = strtounicode(*pbuf, start, -1); #else - /* compute the length. I believe this is done because the return value from - snprintf above is unreliable */ + /* compute the length. I believe this is done because the return + value from snprintf above is unreliable */ len = strlen(start); #endif @@ -1207,7 +1207,7 @@ } static int -format_decimal(PyObject *fieldobj, FmtState *fs, +format_integer(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { CH_TYPE *p_buf; @@ -1322,7 +1322,8 @@ } /* set the total length of the string */ - n_total = n_lpadding + n_lsign + n_spadding + n_digits + n_rsign + n_rpadding; + n_total = n_lpadding + n_lsign + n_spadding + n_digits + + n_rsign + n_rpadding; assert(n_total >= n_allocated); /* because we're going to reallocate, our pointers might be @@ -1355,17 +1356,20 @@ overwrite some of that space */ /* short circuit test, in case we don't have to move anything */ if (p_buf + (n_lpadding + n_lsign + n_spadding) != p_digits) - memmove(p_buf + (n_lpadding + n_lsign + n_spadding), p_digits, n_digits * sizeof(CH_TYPE)); + memmove(p_buf + (n_lpadding + n_lsign + n_spadding), p_digits, + n_digits * sizeof(CH_TYPE)); if (n_lpadding) { - CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, n_lpadding); + CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, + n_lpadding); p_buf += n_lpadding; } if (n_lsign == 1) { *p_buf++ = lsign; } if (n_spadding) { - CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, n_spadding); + CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, + n_spadding); p_buf += n_spadding; } p_buf += n_digits; @@ -1373,7 +1377,8 @@ *p_buf++ = rsign; } if (n_rpadding) { - CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, n_rpadding); + CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, + n_rpadding); p_buf += n_rpadding; } @@ -1381,24 +1386,87 @@ } static int -format_exponent(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) -{ - return format_DUMMY(fieldobj, fs); -} - -static int -format_fixed(PyObject *fieldobj, FmtState *fs, +format_float(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return format_DUMMY(fieldobj, fs); -} + /* first, do the conversion as 8-bit chars, using the platform's + snprintf. then, if needed, convert to unicode. */ -static int -format_general(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) -{ - return format_DUMMY(fieldobj, fs); + /* fmt = '%.' + `prec` + `type` + '%%' + worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/ + char fmt[20]; + + double x; + CH_TYPE type = format->type; + Py_ssize_t precision = format->precision; + CH_TYPE *buf; + int buflen; + int len; + char* trailing = ""; + + /* 'F' is the same as 'f', per the PEP */ + if (type == 'F') + type = 'f'; + + x = PyFloat_AsDouble(fieldobj); + if (x == -1.0 && PyErr_Occurred()) + return 0; + + if (type == '%') { + type = 'f'; + x *= 100; + trailing = "%%"; + } + + if (precision < 0) + precision = 6; + if (type == 'f' && (fabs(x) / 1e25) >= 1e25) + type = 'g'; + + /* cast "type", because if we're in unicode we need to pass a + 8-bit char. this is safe, because we've restricted what "type" + can be */ + PyOS_snprintf(fmt, sizeof(fmt), "%%.%d%c%s", precision, (char)type, trailing); + + /* this is taken from unicodeobject.c, except we don't force a + limit here, we dynamically allocate instead */ + /* Worst case length calc to ensure no buffer overrun: + + 'g' formats: + fmt = %#.g + buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp + for any double rep.) + len = 1 + prec + 1 + 2 + 5 = 9 + prec + + 'f' formats: + buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50) + len = 1 + 50 + 1 + prec = 52 + prec + + If prec=0 the effective precision is 1 (the leading digit is + always given), therefore increase the length by one. + + */ + /* so, allocate the precision plus 54 chars (we add one additional + for the trailing percent). do this allocation as the native + type, because we're going to convert to unicode anyway */ + buflen = 54 + precision; + if (output_allocate(fs, buflen, &buf) == 0) + return 0; + PyOS_ascii_formatd((char *)buf, buflen, fmt, x); + +#if C_UNICODE + len = strtounicode(buf, (char*)buf, -1); +#else + /* compute the length. I believe this is done because the return + value from snprintf above is unreliable */ + len = strlen(buf); +#endif + + /* shrink the buffer down to how many characters we actually + wrote. this is cheap, just pointer arithmetic */ + output_shrink(fs, buflen - len); + + return 1; } static int @@ -1448,13 +1516,6 @@ return ok; } -static int -format_percentage(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) -{ - return format_DUMMY(fieldobj, fs); -} - /* returns a pointer to our conversion function, or NULL if invalid */ Py_LOCAL_INLINE(FormatFunction) format_function(CH_TYPE c) @@ -1462,23 +1523,23 @@ switch (c) { case 'b': return format_binary; /* base-2 */ case 'c': return format_char; /* as character */ - case 'd': return format_decimal; /* decimal integer */ - case 'e': return format_exponent; /* exponential notation */ - case 'E': return format_exponent; /* exponential notation - with uppercase 'E' */ - case 'f': return format_fixed; /* fixed-point */ - case 'F': return format_fixed; /* fixed-point with uppercase */ - case 'g': return format_general; /* general number notation */ - case 'G': return format_general; /* general number notation - with uppercase 'E' */ case 'n': return format_locale_number; /* number in locale-specific format */ - case 'o': return format_decimal; /* octal */ + case 'd': /* decimal integer */ + case 'o': /* octal */ + case 'x': /* base 16 */ + case 'X': return format_integer; /* base 16 uppercase */ case 'r': return format_repr; /* in repr() format */ case 's': return format_string; /* convert using str() */ - case 'x': return format_decimal; /* base 16 */ - case 'X': return format_decimal; /* base 16 uppercase */ - case '%': return format_percentage; /* as percentage */ + case 'e': /* exponential notation */ + case 'E': /* exponential notation + with uppercase 'E' */ + case 'f': /* fixed-point */ + case 'F': /* fixed-point with uppercase */ + case 'g': /* general number notation */ + case 'G': /* general number notation + with uppercase 'E' */ + case '%': return format_float; /* as percentage */ default: return NULL; } @@ -1727,7 +1788,7 @@ static int do_markup(FmtState *fs) { - CH_TYPE c, *start, *ptr, *end; + CH_TYPE c = 0, *start, *ptr, *end; Py_ssize_t count; int syntaxmode, escape, at_end; From python-checkins at python.org Mon Mar 5 17:31:55 2007 From: python-checkins at python.org (facundo.batista) Date: Mon, 5 Mar 2007 17:31:55 +0100 (CET) Subject: [Python-checkins] r54138 - python/trunk/Lib/urllib2.py Message-ID: <20070305163155.02BB31E400B@bag.python.org> Author: facundo.batista Date: Mon Mar 5 17:31:54 2007 New Revision: 54138 Modified: python/trunk/Lib/urllib2.py Log: Minor corrections to docs, and an explanation comentary Modified: python/trunk/Lib/urllib2.py ============================================================================== --- python/trunk/Lib/urllib2.py (original) +++ python/trunk/Lib/urllib2.py Mon Mar 5 17:31:54 2007 @@ -14,36 +14,36 @@ HTTP 301, 302, 303 and 307 redirect errors, and the HTTPDigestAuthHandler deals with digest authentication. -urlopen(url, data=None) -- basic usage is the same as original +urlopen(url, data=None) -- Basic usage is the same as original urllib. pass the url and optionally data to post to an HTTP URL, and get a file-like object back. One difference is that you can also pass a Request instance instead of URL. Raises a URLError (subclass of IOError); for HTTP errors, raises an HTTPError, which can also be treated as a valid response. -build_opener -- function that creates a new OpenerDirector instance. -will install the default handlers. accepts one or more Handlers as +build_opener -- Function that creates a new OpenerDirector instance. +Will install the default handlers. Accepts one or more Handlers as arguments, either instances or Handler classes that it will -instantiate. if one of the argument is a subclass of the default +instantiate. If one of the argument is a subclass of the default handler, the argument will be installed instead of the default. -install_opener -- installs a new opener as the default opener. +install_opener -- Installs a new opener as the default opener. objects of interest: -OpenerDirector -- +OpenerDirector -- -Request -- an object that encapsulates the state of a request. the -state can be a simple as the URL. it can also include extra HTTP +Request -- An object that encapsulates the state of a request. The +state can be as simple as the URL. It can also include extra HTTP headers, e.g. a User-Agent. BaseHandler -- exceptions: -URLError-- a subclass of IOError, individual protocols have their own -specific subclass +URLError -- A subclass of IOError, individual protocols have their own +specific subclass. -HTTPError-- also a valid HTTP response, so you can treat an HTTP error -as an exceptional event or valid response +HTTPError -- Also a valid HTTP response, so you can treat an HTTP error +as an exceptional event or valid response. internals: BaseHandler and parent @@ -334,7 +334,8 @@ added = True if added: - # XXX why does self.handlers need to be sorted? + # the handlers must work in an specific order, the order + # is specified in a Handler attribute bisect.insort(self.handlers, handler) handler.add_parent(self) From python-checkins at python.org Mon Mar 5 23:28:10 2007 From: python-checkins at python.org (georg.brandl) Date: Mon, 5 Mar 2007 23:28:10 +0100 (CET) Subject: [Python-checkins] r54139 - in python/trunk: Lib/test/test_descr.py Misc/NEWS Python/ceval.c Message-ID: <20070305222810.37D261E400C@bag.python.org> Author: georg.brandl Date: Mon Mar 5 23:28:08 2007 New Revision: 54139 Modified: python/trunk/Lib/test/test_descr.py python/trunk/Misc/NEWS python/trunk/Python/ceval.c Log: Patch #1674228: when assigning a slice (old-style), check for the sq_ass_slice instead of the sq_slice slot. Modified: python/trunk/Lib/test/test_descr.py ============================================================================== --- python/trunk/Lib/test/test_descr.py (original) +++ python/trunk/Lib/test/test_descr.py Mon Mar 5 23:28:08 2007 @@ -4206,6 +4206,19 @@ check(iexpr, c, N1) check(iexpr, c, N2) +def test_assign_slice(): + # ceval.c's assign_slice used to check for + # tp->tp_as_sequence->sq_slice instead of + # tp->tp_as_sequence->sq_ass_slice + + class C(object): + def __setslice__(self, start, stop, value): + self.value = value + + c = C() + c[1:2] = 3 + vereq(c.value, 3) + def test_main(): weakref_segfault() # Must be first, somehow wrapper_segfault() @@ -4301,6 +4314,7 @@ test_init() methodwrapper() notimplemented() + test_assign_slice() from test import test_descr run_doctest(test_descr, verbosity=True) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Mon Mar 5 23:28:08 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #1674228: when assigning a slice (old-style), check for the + sq_ass_slice instead of the sq_slice slot. + - When printing an unraisable error, don't print exceptions. before the name. This duplicates the behavior whening normally printing exceptions. Modified: python/trunk/Python/ceval.c ============================================================================== --- python/trunk/Python/ceval.c (original) +++ python/trunk/Python/ceval.c Mon Mar 5 23:28:08 2007 @@ -3927,7 +3927,7 @@ PyTypeObject *tp = u->ob_type; PySequenceMethods *sq = tp->tp_as_sequence; - if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) { + if (sq && sq->sq_ass_slice && ISINDEX(v) && ISINDEX(w)) { Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; if (!_PyEval_SliceIndex(v, &ilow)) return -1; From python-checkins at python.org Mon Mar 5 23:28:14 2007 From: python-checkins at python.org (georg.brandl) Date: Mon, 5 Mar 2007 23:28:14 +0100 (CET) Subject: [Python-checkins] r54140 - in python/branches/release25-maint: Lib/test/test_descr.py Misc/NEWS Python/ceval.c Message-ID: <20070305222814.B3EDD1E400C@bag.python.org> Author: georg.brandl Date: Mon Mar 5 23:28:13 2007 New Revision: 54140 Modified: python/branches/release25-maint/Lib/test/test_descr.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Python/ceval.c Log: Patch #1674228: when assigning a slice (old-style), check for the sq_ass_slice instead of the sq_slice slot. (backport from rev. 54139) Modified: python/branches/release25-maint/Lib/test/test_descr.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_descr.py (original) +++ python/branches/release25-maint/Lib/test/test_descr.py Mon Mar 5 23:28:13 2007 @@ -4143,6 +4143,19 @@ check(iexpr, c, N1) check(iexpr, c, N2) +def test_assign_slice(): + # ceval.c's assign_slice used to check for + # tp->tp_as_sequence->sq_slice instead of + # tp->tp_as_sequence->sq_ass_slice + + class C(object): + def __setslice__(self, start, stop, value): + self.value = value + + c = C() + c[1:2] = 3 + vereq(c.value, 3) + def test_main(): weakref_segfault() # Must be first, somehow wrapper_segfault() @@ -4239,6 +4252,7 @@ test_init() methodwrapper() notimplemented() + test_assign_slice() if verbose: print "All OK" Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Mon Mar 5 23:28:13 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #1674228: when assigning a slice (old-style), check for the + sq_ass_slice instead of the sq_slice slot. + - Bug #1669182: prevent crash when trying to print an unraisable error from a string exception. Modified: python/branches/release25-maint/Python/ceval.c ============================================================================== --- python/branches/release25-maint/Python/ceval.c (original) +++ python/branches/release25-maint/Python/ceval.c Mon Mar 5 23:28:13 2007 @@ -3926,7 +3926,7 @@ PyTypeObject *tp = u->ob_type; PySequenceMethods *sq = tp->tp_as_sequence; - if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) { + if (sq && sq->sq_ass_slice && ISINDEX(v) && ISINDEX(w)) { Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; if (!_PyEval_SliceIndex(v, &ilow)) return -1; From nnorwitz at gmail.com Mon Mar 5 23:33:18 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Mon, 5 Mar 2007 17:33:18 -0500 Subject: [Python-checkins] Python Regression Test Failures all (1) Message-ID: <20070305223318.GA2434@python.psfb.org> test_grammar test_opcodes test_operations test_builtin test_exceptions test_types test_MimeWriter test_StringIO test___all__ test___future__ test__locale test_aepack test_aepack skipped -- No module named aepack test_al test_al skipped -- No module named al test_anydbm test_applesingle test_applesingle skipped -- No module named macostools test_array test_ast test_asynchat test_atexit test_audioop test_augassign test_base64 test_bastion test_bigaddrspace test_bigmem test_binascii test_binhex test_binop test_bisect test_bool test_bsddb test_bsddb185 test_bsddb185 skipped -- No module named bsddb185 test_bsddb3 test_bufio test_bz2 test_cProfile test_calendar test_call test_capi test_cd test_cd skipped -- No module named cd test_cfgparser test_cgi test_charmapcodec test_cl test_cl skipped -- No module named cl test_class test_cmath test_cmd_line test_code test_codeccallbacks test_codecencodings_cn test_codecencodings_hk test_codecencodings_jp test_codecencodings_kr test_codecencodings_tw test_codecmaps_cn test_codecmaps_hk test_codecmaps_jp test_codecmaps_kr test_codecmaps_tw test_codecs test_codeop test_coding test_coercion test_collections test_colorsys test_commands test_compare test_compile test_compiler test_complex test_complex_args test_contains test_contextlib test_cookie test_cookielib test_copy test_copy_reg test_cpickle test_crypt test_csv test_ctypes test_datetime test_dbm test_decimal test_decorators test_defaultdict test_deque test_descr test_descrtut test_dict test_difflib test_dircache test_dis test_distutils test_dl test_doctest test_doctest2 test_dumbdbm test_dummy_thread test_dummy_threading test_email test_email_codecs test_email_renamed test_enumerate test_eof test_errno test_exception_variations test_extcall test_fcntl test_file test_filecmp test_fileinput test_float test_fnmatch test_fork1 test_format test_fpformat test_frozen test_funcattrs test_functools test_future test_gc test_gdbm test_generators test_genericpath test_genexps test_getargs test_getargs2 test_getopt test_gettext test_gl test_gl skipped -- No module named gl test_glob test_global test_grp test_gzip test_hash test_hashlib test_heapq test_hexoct test_hmac test_hotshot test_htmllib test_htmlparser test_httplib test_imageop test_imaplib test_imgfile test_imgfile skipped -- No module named imgfile test_imp test_import test_importhooks test_index test_inspect test_ioctl test_ioctl skipped -- Unable to open /dev/tty test_isinstance test_iter test_iterlen test_itertools test_largefile test_list test_locale test_logging test_long test_long_future test_longexp test_macfs test_macfs skipped -- No module named macfs test_macostools test_macostools skipped -- No module named macostools test_macpath test_mailbox test_marshal test_math test_md5 test_mhlib test_mimetools test_mimetypes test_minidom test_mmap test_module test_modulefinder test_multibytecodec test_multibytecodec_support test_multifile test_mutants test_netrc test_new test_nis test_normalization test_ntpath test_old_mailbox test_openpty test_operator test_optparse test_os test_parser test_peepholer test_pep247 test_pep263 test_pep277 test_pep277 skipped -- test works only on NT+ test_pep292 test_pep352 test_pickle test_pickletools test_pkg test_pkgimport test_platform test_plistlib test_plistlib skipped -- No module named plistlib test_poll test_popen [7321 refs] [7321 refs] [7321 refs] test_popen2 test_posix test_posixpath test_pow test_pprint test_profile test_profilehooks test_pty test_pwd test_pyclbr test_pyexpat test_queue test_quopri [7696 refs] [7696 refs] test_random test_re test_repr test_resource test_rfc822 test_rgbimg test_richcmp test_robotparser test_runpy test_sax test_scope test_scriptpackages test_scriptpackages skipped -- No module named aetools test_select test_set test_sets test_sgmllib test_sha test_shelve test_shlex test_shutil test_signal test_site test_slice test_socket test_socket_ssl test test_socket_ssl crashed -- : [Errno socket error] (110, 'Connection timed out') test_socketserver test_softspace test_sort test_sqlite test_startfile test_startfile skipped -- cannot import name startfile test_str test_strftime test_string test_stringprep test_strop test_strptime test_struct test_structmembers test_structseq test_subprocess [7316 refs] [7317 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7317 refs] [8865 refs] [7532 refs] [7317 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] . [7316 refs] [7316 refs] this bit of output is from a test of stdout in a different process ... [7316 refs] [7316 refs] [7532 refs] test_sunaudiodev test_sunaudiodev skipped -- No module named sunaudiodev test_sundry test_symtable test_syntax test_sys [7316 refs] [7316 refs] test_tarfile test_tcl test_tcl skipped -- No module named _tkinter test_tempfile [7323 refs] test_textwrap test_thread test_threaded_import test_threadedtempfile test_threading test_threading_local test_threadsignals test_time test_timeout test_tokenize test_trace test_traceback test_transformer test_tuple test_ucn test_unary test_unicode test_unicode_file test_unicode_file skipped -- No Unicode filesystem semantics on this platform. test_unicodedata test_unittest test_univnewlines test_unpack test_urllib test_urllib2 test_urllib2net test_urllibnet test_urlparse test_userdict test_userlist test_userstring test_uu test_uuid WARNING: uuid.getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. WARNING: uuid._ifconfig_getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. WARNING: uuid._unixdll_getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. test_wait3 test_wait4 test_warnings test_wave test_weakref test_whichdb test_winreg test_winreg skipped -- No module named _winreg test_winsound test_winsound skipped -- No module named winsound test_with test_wsgiref test_xdrlib test_xml_etree test_xml_etree_c test_xmllib test_xmlrpc test_xpickle test_xrange test_zipfile test_zipfile64 test_zipfile64 skipped -- test requires loads of disk-space bytes and a long time to run test_zipimport test_zlib 299 tests OK. 1 test failed: test_socket_ssl 21 tests skipped: test_aepack test_al test_applesingle test_bsddb185 test_cd test_cl test_gl test_imgfile test_ioctl test_macfs test_macostools test_pep277 test_plistlib test_scriptpackages test_startfile test_sunaudiodev test_tcl test_unicode_file test_winreg test_winsound test_zipfile64 1 skip unexpected on linux2: test_ioctl [463190 refs] From buildbot at python.org Mon Mar 5 23:57:48 2007 From: buildbot at python.org (buildbot at python.org) Date: Mon, 05 Mar 2007 22:57:48 +0000 Subject: [Python-checkins] buildbot warnings in x86 gentoo trunk Message-ID: <20070305225749.1ED401E4016@bag.python.org> The Buildbot has detected a new failure of x86 gentoo trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%2520trunk/builds/1965 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 864, in endheaders self._send_output() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 736, in _send_output self.send(msg) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 695, in send self.connect() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 1152, in connect sock.connect((self.host, self.port)) File "", line 1, in connect IOError: [Errno socket error] (110, 'Connection timed out') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 00:15:07 2007 From: buildbot at python.org (buildbot at python.org) Date: Mon, 05 Mar 2007 23:15:07 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable trunk Message-ID: <20070305231508.1B2FA1E4016@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%2520trunk/builds/116 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_bsddb3 make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 00:22:21 2007 From: buildbot at python.org (buildbot at python.org) Date: Mon, 05 Mar 2007 23:22:21 +0000 Subject: [Python-checkins] buildbot warnings in x86 gentoo 2.5 Message-ID: <20070305232221.A80491E400C@bag.python.org> The Buildbot has detected a new failure of x86 gentoo 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%25202.5/builds/253 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/httplib.py", line 856, in endheaders self._send_output() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/httplib.py", line 728, in _send_output self.send(msg) File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/httplib.py", line 695, in send self.connect() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/httplib.py", line 1130, in connect sock.connect((self.host, self.port)) File "", line 1, in connect IOError: [Errno socket error] (110, 'Connection timed out') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 01:10:41 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 00:10:41 +0000 Subject: [Python-checkins] buildbot warnings in ia64 Ubuntu trunk trunk Message-ID: <20070306001041.6DFD71E400C@bag.python.org> The Buildbot has detected a new failure of ia64 Ubuntu trunk trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ia64%2520Ubuntu%2520trunk%2520trunk/builds/425 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/httplib.py", line 864, in endheaders self._send_output() File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/httplib.py", line 736, in _send_output self.send(msg) File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/httplib.py", line 695, in send self.connect() File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/httplib.py", line 1153, in connect ssl = socket.ssl(sock, self.key_file, self.cert_file) File "/home/pybot/buildarea/trunk.klose-debian-ia64/build/Lib/socket.py", line 74, in ssl return _realssl(sock, keyfile, certfile) IOError: [Errno socket error] (8, 'EOF occurred in violation of protocol') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 02:47:57 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 01:47:57 +0000 Subject: [Python-checkins] buildbot warnings in ia64 Ubuntu trunk 2.5 Message-ID: <20070306014757.660C11E400C@bag.python.org> The Buildbot has detected a new failure of ia64 Ubuntu trunk 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/ia64%2520Ubuntu%2520trunk%25202.5/builds/204 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/httplib.py", line 856, in endheaders self._send_output() File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/httplib.py", line 728, in _send_output self.send(msg) File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/httplib.py", line 695, in send self.connect() File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/httplib.py", line 1131, in connect ssl = socket.ssl(sock, self.key_file, self.cert_file) File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/socket.py", line 74, in ssl return _realssl(sock, keyfile, certfile) IOError: [Errno socket error] (8, 'EOF occurred in violation of protocol') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 02:50:46 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 01:50:46 +0000 Subject: [Python-checkins] buildbot warnings in MIPS Debian trunk Message-ID: <20070306015046.7F53D1E400C@bag.python.org> The Buildbot has detected a new failure of MIPS Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/MIPS%2520Debian%2520trunk/builds/652 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/httplib.py", line 864, in endheaders self._send_output() File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/httplib.py", line 736, in _send_output self.send(msg) File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/httplib.py", line 695, in send self.connect() File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/httplib.py", line 1153, in connect ssl = socket.ssl(sock, self.key_file, self.cert_file) File "/home/pybot/buildarea/trunk.klose-debian-mips/build/Lib/socket.py", line 74, in ssl return _realssl(sock, keyfile, certfile) IOError: [Errno socket error] (8, 'EOF occurred in violation of protocol') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 03:36:51 2007 From: python-checkins at python.org (eric.smith) Date: Tue, 6 Mar 2007 03:36:51 +0100 (CET) Subject: [Python-checkins] r54141 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070306023651.6275A1E400D@bag.python.org> Author: eric.smith Date: Tue Mar 6 03:36:49 2007 New Revision: 54141 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Added binary formatting. Factored out _calc_integer_widths() and _fill_integer(), so they can be shared by format_integer() and format_binary(). Added test cases for binary. This code accesses PyLongObject's ob_digit[] directly, that might not be the best way to go about binary formatting. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Tue Mar 6 03:36:49 2007 @@ -123,7 +123,7 @@ def test_specifiers(self): self.formatEquals("a", "{0:c}", ord("a")) - self.formatEquals("8_08b", "{0:08b}", 8) + self.formatEquals("00001000", "{0:08b}", 8) self.formatEquals(" 8", "{0: >3d}", 8) self.formatEquals("15%", "{0:.0%}", .1515) @@ -152,6 +152,7 @@ self.assertRaises(TypeError, "{0:d}", "non-number") self.formatEqualsWithUnicode("0", "{0:d}", 0) + self.formatEqualsWithUnicode("0", "{0:d}", long(0)) self.formatEqualsWithUnicode("123", "{0:d}", 123) self.formatEqualsWithUnicode("-123", "{0:d}", -123) self.formatEqualsWithUnicode("+123", "{0:+d}", 123) @@ -204,7 +205,7 @@ def test_hex_specifiers(self): n = int("beef", 16) - self.assertRaises(TypeError, "{0:x", "non-number") + self.formatRaises(TypeError, "{0:x}", "non-number") self.formatEqualsWithUnicodeUC("0", "{0:x}", 0) self.formatEqualsWithUnicodeUC("beef", "{0:x}", n) @@ -248,6 +249,31 @@ self.formatEqualsWithUnicodeUC("3.1415e+200", "{0:g}", 3.1415e200) self.formatEqualsWithUnicodeUC("3.1415e+200", "{0:g}", 3.1415e200) + def test_percent_specifiers(self): + self.formatEqualsWithUnicode("314.15%", "{0:.2%}", 3.1415) + self.formatEqualsWithUnicode("3.14e+202%", "{0:.3%}", 3.1415e200) + + def test_binary_specifiers(self): + self.formatRaises(TypeError, "{0:b}", "string") + + self.formatEqualsWithUnicode("0", "{0:b}", 0) + self.formatEqualsWithUnicode("0", "{0:b}", long(0)) + self.formatEqualsWithUnicode("1", "{0:b}", 1) + self.formatEqualsWithUnicode("1", "{0:b}", long(1)) + self.formatEqualsWithUnicode("-1", "{0:b}", -1) + self.formatEqualsWithUnicode("-1", "{0:b}", long(-1)) + self.formatEqualsWithUnicode("0 ", "{0:<10b}", 0) + self.formatEqualsWithUnicode(" 0", "{0:>10b}", 0) + self.formatEqualsWithUnicode("1001 ", "{0:<10b}", 9) + self.formatEqualsWithUnicode(" 1001", "{0:>10b}", 9) + self.formatEqualsWithUnicode("1" + "0" * 100, "{0:b}", 2**100) + self.formatEqualsWithUnicode("-1" + "0" * 100, "{0:b}", -2**100) + self.formatEqualsWithUnicode("1" + "0" * 98 + "11", "{0:b}", 2**100 + 3) + self.formatEqualsWithUnicode("1" * 100, "{0:b}", 2**100 - 1) + self.formatEqualsWithUnicode("-" + "1" * 100, "{0:b}", -(2**100 - 1)) + self.formatEqualsWithUnicode("(" + "1" * 100 + ")", "{0:()b}", -(2**100 - 1)) + self.formatEqualsWithUnicode("(" + " " * 98 + "1" * 100 + ")", "{0:=()200b}", -(2**100 - 1)) + def test_missing_type_specifier(self): # make sure floats use 'g', ints and longs 'd', and everything else 's' pass Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Tue Mar 6 03:36:49 2007 @@ -20,6 +20,9 @@ #define C_UNICODE 1 #endif +/* we need access to a PyLongObject's internals */ +#include "longintrepr.h" + #if C_UNICODE #define CH_TYPE Py_UNICODE #define CH_TYPE_ISDECIMAL Py_UNICODE_ISDECIMAL @@ -91,6 +94,7 @@ */ #define FORMATBUFLEN (size_t)120 +#define ABS(x) ((x) < 0 ? -(x) : (x)) #ifdef __cplusplus extern "C" { @@ -806,6 +810,20 @@ CH_TYPE type; } InternalFormatSpec; +/* describes the layout for an integer, see the comment in + _calc_integer_widths() for details */ +typedef struct { + Py_ssize_t n_lpadding; + Py_ssize_t n_spadding; + Py_ssize_t n_rpadding; + char lsign; + Py_ssize_t n_lsign; + char rsign; + Py_ssize_t n_rsign; + Py_ssize_t n_total; /* just a convenience, it's derivable from the + other fields */ +} IntegerFieldWidths; + /* returns true if this character is a specifier alignment token */ Py_LOCAL_INLINE(int) alignment_token(CH_TYPE c) @@ -1024,11 +1042,233 @@ (*FormatFunction)(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format); +static void +_calc_integer_widths(IntegerFieldWidths *r, CH_TYPE sign, Py_ssize_t n_digits, + const InternalFormatSpec *format) +{ + r->n_lpadding = 0; + r->n_spadding = 0; + r->n_rpadding = 0; + r->lsign = '\0'; + r->n_lsign = 0; + r->rsign = '\0'; + r->n_rsign = 0; + + /* the output will look like: + | | + | | + | | + + lsign and rsign are computed from format->sign and the actual + sign of the number + + digits is already known + + the total width is either given, or computed from the + actual digits + + only one of lpadding, spadding, and rpadding can be non-zero, + and it's calculated from the width and other fields + */ + + /* compute the various parts we're going to write */ + if (format->sign == '+') { + /* always put a + or - */ + r->n_lsign = 1; + r->lsign = (sign == '-' ? '-' : '+'); + } else if (format->sign == '(') { + if (sign == '-') { + r->n_lsign = 1; + r->lsign = '('; + r->n_rsign = 1; + r->rsign = ')'; + } + } else if (format->sign == ' ') { + r->n_lsign = 1; + r->lsign = (sign == '-' ? '-' : ' '); + } else { + /* non specified, or the default (-) */ + if (sign == '-') { + r->n_lsign = 1; + r->lsign = '-'; + } + } + + /* now the number of padding characters */ + if (format->width == -1) { + /* no padding at all, nothing to do */ + } else { + /* see if any padding is needed */ + if (r->n_lsign + n_digits + r->n_rsign >= format->width) { + /* no padding needed, we're already bigger than the + requested width */ + } else { + /* determine which of left, space, or right padding is + needed */ + Py_ssize_t padding = format->width - (r->n_lsign + n_digits + r->n_rsign); + if (format->align == '<') + r->n_rpadding = padding; + else if (format->align == '>') + r->n_lpadding = padding; + else + /* must be '=' */ + r->n_spadding = padding; + } + } + r->n_total = r->n_lpadding + r->n_lsign + r->n_spadding + + n_digits + r->n_rsign + r->n_rpadding; +} + +/* fill in the non-digit parts of an integer's string representation, + as determined in _calc_integer_widths(). returns the pointer to + where the digits go. */ +static CH_TYPE* +_fill_integer(CH_TYPE *p_buf, const IntegerFieldWidths *spec, + Py_ssize_t n_digits, CH_TYPE fill_char) +{ + CH_TYPE* p_digits; + + if (spec->n_lpadding) { + CH_TYPE_FILL(p_buf, fill_char, spec->n_lpadding); + p_buf += spec->n_lpadding; + } + if (spec->n_lsign == 1) { + *p_buf++ = spec->lsign; + } + if (spec->n_spadding) { + CH_TYPE_FILL(p_buf, fill_char, spec->n_spadding); + p_buf += spec->n_spadding; + } + p_digits = p_buf; + p_buf += n_digits; + if (spec->n_rsign == 1) { + *p_buf++ = spec->rsign; + } + if (spec->n_rpadding) { + CH_TYPE_FILL(p_buf, fill_char, spec->n_rpadding); + p_buf += spec->n_rpadding; + } + return p_digits; +} + +static int +_format_long_binary(PyObject *v, FmtState *fs, const InternalFormatSpec *format) +{ + /* we know that v is a PyLongObject */ + PyLongObject* l = (PyLongObject*)v; + + IntegerFieldWidths spec; + CH_TYPE *pbuf; + CH_TYPE *start; + char sign = _PyLong_Sign(v) >= 0 ? '\0' : '-'; + Py_ssize_t n_digits = _PyLong_NumBits(v); + Py_ssize_t i; + + /* special case for zero */ + if (l->ob_size == 0) + n_digits = 1; + + _calc_integer_widths(&spec, sign, n_digits, format); + + /* allocate space */ + if (output_allocate(fs, spec.n_total, &pbuf) == 0) + return 0; + + /* fill in the non-digit parts, and return a pointer where the digits go */ + start = _fill_integer(pbuf, &spec, n_digits, + format->fill_char == '\0' ? ' ' : format->fill_char); + + /* degenerate case for zero. handle it and get out */ + if (l->ob_size == 0) { + *pbuf = '0'; + return 1; + } + + /* finally, fill in the digits, starting at the right and working left */ + pbuf = start + n_digits - 1; + + for (i = 0; i < ABS(l->ob_size); i++) { + Py_ssize_t j; + digit d = l->ob_digit[i]; + for (j = 0; j < SHIFT; j++, d >>= 1) { + if (d & 1) + *pbuf = '1'; + else + *pbuf = '0'; + + /* see if we're done mid-digit */ + pbuf--; + if (pbuf < start) + goto DONE; + } + } + +DONE: + return 1; +} + +static int +_format_int_binary(PyObject *v, FmtState *fs, const InternalFormatSpec *format) +{ + /* see http://graphics.stanford.edu/~seander/bithacks.html for + various bit related hacks used here */ + + long x; + char sign = '\0'; + unsigned n_digits; + long tmp; + IntegerFieldWidths spec; + CH_TYPE *pbuf; + + x = PyInt_AsLong(v); + if (x == -1 && PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, "int argument required, not %.200s", + v->ob_type->tp_name); + return 0; + } + + if (x < 0) { + sign = '-'; + x *= -1; + } + + /* number of binary digits is one more than lg(x). this also works for 0 */ + n_digits = 1; + tmp = x; + while (tmp >>= 1) + n_digits++; + + _calc_integer_widths(&spec, sign, n_digits, format); + + /* allocate space */ + if (output_allocate(fs, spec.n_total, &pbuf) == 0) + return 0; + + /* fill in the non-digit parts, and return a pointer where the digits go */ + pbuf = _fill_integer(pbuf, &spec, n_digits, + format->fill_char == '\0' ? ' ' : format->fill_char); + + /* finally, fill in the digits, starting at the right and working left */ + /* note that if x == 0, n_digits will be 1 and this loop will still work */ + pbuf += n_digits-1; + for (; n_digits; pbuf--, n_digits--, x >>= 1) { + if (x & 1) + *pbuf = '1'; + else + *pbuf = '0'; + } + + return 1; +} + static int format_binary(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return format_DUMMY(fieldobj, fs); + if (PyLong_Check(fieldobj)) + return _format_long_binary(fieldobj, fs, format); + else + return _format_int_binary(fieldobj, fs, format); } static int @@ -1137,7 +1377,6 @@ PyOS_snprintf(ptr, buflen, format, x); - /* convert from chars to unicode, if needed */ #if C_UNICODE len = strtounicode(*pbuf, start, -1); @@ -1177,13 +1416,13 @@ /* if we're hex or octal, check to see if 0 or 0x or 0X was at the front of the string. if so, skip it. */ - if (type == 'o' && n_allocated >= 1 && *pbuf[0] == '0') { + if (type == 'o' && n_allocated >= 1 && (*pbuf)[0] == '0') { p_charbuf++; n_allocated -= 1; - } else if (type == 'x' && n_allocated >= 2 && *pbuf[1] == 'x') { + } else if (type == 'x' && n_allocated >= 2 && (*pbuf)[1] == 'x') { p_charbuf += 2; n_allocated -= 1; - } else if (type == 'X' && n_allocated >= 2 && *pbuf[1] == 'X') { + } else if (type == 'X' && n_allocated >= 2 && (*pbuf)[1] == 'X') { p_charbuf += 2; n_allocated -= 1; } @@ -1214,14 +1453,7 @@ CH_TYPE *p_digits; /* pointer to the digits we have */ CH_TYPE n_digits; /* count of digits we have */ CH_TYPE sign; - Py_ssize_t n_lpadding; - Py_ssize_t n_spadding; - Py_ssize_t n_rpadding; - CH_TYPE lsign = 0; - Py_ssize_t n_lsign = 0; - CH_TYPE rsign = 0; - Py_ssize_t n_rsign = 0; - Py_ssize_t n_total; /* the total length we're going to write */ + IntegerFieldWidths spec; Py_ssize_t n_allocated; /* how much space we actually allocated when we wrote the digits into the output */ @@ -1258,73 +1490,7 @@ else sign = '\0'; - /* the output will look like: - | | - | | - | | - - lsign and rsign are computed from format->sign and the actual - sign of the number - - digits is already known - - the total width is either given, or computed from the - actual digits - - only one of lpadding, spadding, and rpadding can be non-zero, - and it's calculated from the width and other fields - */ - - /* compute the various parts we're going to write */ - if (format->sign == '+') { - /* always put a + or - */ - n_lsign = 1; - lsign = (sign == '-' ? '-' : '+'); - } else if (format->sign == '(') { - if (sign == '-') { - n_lsign = 1; - lsign = '('; - n_rsign = 1; - rsign = ')'; - } - } else if (format->sign == ' ') { - n_lsign = 1; - lsign = (sign == '-' ? '-' : ' '); - } else { - /* non specified, or the default (-) */ - if (sign == '-') { - n_lsign = 1; - lsign = '-'; - } - } - - /* now the number of padding characters */ - n_lpadding = n_spadding = n_rpadding = 0; - if (format->width == -1) { - /* no padding at all, nothing to do */ - } else { - /* see if any padding is needed */ - if (n_lsign + n_digits + n_rsign >= format->width) { - /* no padding needed, we're already bigger than the - requested width */ - } else { - /* determine which of left, space, or right padding is - needed */ - Py_ssize_t padding = format->width - (n_lsign + n_digits + n_rsign); - if (format->align == '<') - n_rpadding = padding; - else if (format->align == '>') - n_lpadding = padding; - else - /* must be '=' */ - n_spadding = padding; - } - } - - /* set the total length of the string */ - n_total = n_lpadding + n_lsign + n_spadding + n_digits - + n_rsign + n_rpadding; - assert(n_total >= n_allocated); + _calc_integer_widths(&spec, sign, n_digits, format); /* because we're going to reallocate, our pointers might be invalidated. remember the offsets, then re-create the pointers @@ -1333,7 +1499,7 @@ ofs_buf = p_buf - tmp; ofs_digits = p_digits - tmp; - output_allocate(fs, n_total - n_allocated, &tmp); + output_allocate(fs, spec.n_total - n_allocated, &tmp); tmp = STROBJ_AS_PTR(fs->outstr.obj); p_buf = tmp + ofs_buf; @@ -1342,46 +1508,27 @@ #if 0 printf("p_buf %p\n", p_buf); printf("p_digits %p\n", p_digits); + printf("digits '%.*s'\n", n_digits, p_digits); printf("n_digits: %d\n", n_digits); - printf("n_lpadding: %d\n", n_lpadding); - printf("n_lsign: %d\n", n_lsign); - printf("lsign: %d(%c)\n", lsign, lsign); - printf("n_rsign: %d\n", n_rsign); - printf("rsign: %d(%c)\n", rsign, rsign); - printf("n_spadding: %d\n", n_spadding); - printf("n_rpadding: %d\n", n_rpadding); + printf("n_lpadding: %d\n", spec.n_lpadding); + printf("n_lsign: %d\n", spec.n_lsign); + printf("lsign: %d(%c)\n", spec.lsign, spec.lsign); + printf("n_rsign: %d\n", spec.n_rsign); + printf("rsign: %d(%c)\n", spec.rsign, spec.rsign); + printf("n_spadding: %d\n", spec.n_spadding); + printf("n_rpadding: %d\n", spec.n_rpadding); #endif /* copy the characters into position first, since we're going to overwrite some of that space */ /* short circuit test, in case we don't have to move anything */ - if (p_buf + (n_lpadding + n_lsign + n_spadding) != p_digits) - memmove(p_buf + (n_lpadding + n_lsign + n_spadding), p_digits, - n_digits * sizeof(CH_TYPE)); - - if (n_lpadding) { - CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, - n_lpadding); - p_buf += n_lpadding; - } - if (n_lsign == 1) { - *p_buf++ = lsign; - } - if (n_spadding) { - CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, - n_spadding); - p_buf += n_spadding; - } - p_buf += n_digits; - if (n_rsign == 1) { - *p_buf++ = rsign; - } - if (n_rpadding) { - CH_TYPE_FILL(p_buf, format->fill_char == '\0' ? ' ' : format->fill_char, - n_rpadding); - p_buf += n_rpadding; - } - + if (p_buf + (spec.n_lpadding + spec.n_lsign + spec.n_spadding) != p_digits) + memmove(p_buf + (spec.n_lpadding + spec.n_lsign + spec.n_spadding), + p_digits, n_digits * sizeof(CH_TYPE)); + + /* now fill in the non-digit parts */ + _fill_integer(p_buf, &spec, n_digits, + format->fill_char == '\0' ? ' ' : format->fill_char); return 1; } @@ -1569,10 +1716,7 @@ } } - /* XXX handle conversion functions that logically map to other - conversion functions? percent is the only one, and I'm not wild - about having percent at all*/ - + /* find the formatter function */ formatter = format_function(format.type); if (formatter == NULL) { SetError(fs, "Invalid conversion character"); From buildbot at python.org Tue Mar 6 03:38:19 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 02:38:19 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 Message-ID: <20070306023819.2BD171E400D@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/38 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/httplib.py", line 856, in endheaders self._send_output() File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/httplib.py", line 728, in _send_output self.send(msg) File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/httplib.py", line 695, in send self.connect() File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/httplib.py", line 1131, in connect ssl = socket.ssl(sock, self.key_file, self.cert_file) File "/home/pybot/buildarea/2.5.klose-ubuntu-hppa/build/Lib/socket.py", line 74, in ssl return _realssl(sock, keyfile, certfile) IOError: [Errno socket error] (8, 'EOF occurred in violation of protocol') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 03:43:11 2007 From: python-checkins at python.org (eric.smith) Date: Tue, 6 Mar 2007 03:43:11 +0100 (CET) Subject: [Python-checkins] r54142 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070306024311.6FF1F1E4018@bag.python.org> Author: eric.smith Date: Tue Mar 6 03:43:07 2007 New Revision: 54142 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Fixed potentially unsafe pointer arithmetic. Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Tue Mar 6 03:43:07 2007 @@ -1197,9 +1197,9 @@ *pbuf = '0'; /* see if we're done mid-digit */ - pbuf--; - if (pbuf < start) + if (pbuf == start) goto DONE; + pbuf--; } } From python-checkins at python.org Tue Mar 6 04:02:42 2007 From: python-checkins at python.org (eric.smith) Date: Tue, 6 Mar 2007 04:02:42 +0100 (CET) Subject: [Python-checkins] r54143 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070306030242.740561E400C@bag.python.org> Author: eric.smith Date: Tue Mar 6 04:02:40 2007 New Revision: 54143 Modified: sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Added 'n' formatting, as I understand it. Added test cases, but they could use some work, such as testing different locales. Added notes to README.txt about these issues. Removed dummy formatter. Modified: sandbox/trunk/pep3101/README.txt ============================================================================== --- sandbox/trunk/pep3101/README.txt (original) +++ sandbox/trunk/pep3101/README.txt Tue Mar 6 04:02:40 2007 @@ -61,4 +61,8 @@ - Add capability to control exception handling to pep_differences and to code: 1) ability to dump exceptions into string, 2) ability to re-do lower exceptions or "pile-on" + - Refactor format_locale_number() and format_float() to avoid + massive code duplication. + - Test suite needs to test different locales for 'n' formatting. + Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Tue Mar 6 04:02:40 2007 @@ -1,6 +1,8 @@ import unittest from test import test_support +import locale + import pep3101 # Variables used for testing name mapper @@ -274,6 +276,14 @@ self.formatEqualsWithUnicode("(" + "1" * 100 + ")", "{0:()b}", -(2**100 - 1)) self.formatEqualsWithUnicode("(" + " " * 98 + "1" * 100 + ")", "{0:=()200b}", -(2**100 - 1)) + def test_number_specifier(self): + def test(value): + self.formatEqualsWithUnicode(locale.format("%f", value), "{0:n}", value) + + test(0) + test(1) + test(10**100) + def test_missing_type_specifier(self): # make sure floats use 'g', ints and longs 'd', and everything else 's' pass Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Tue Mar 6 04:02:40 2007 @@ -1003,34 +1003,6 @@ } -/* XXX delete this when all internal conversions are implemented */ -static int -format_DUMMY(PyObject *fieldobj, FmtState *fs) -{ - PyObject *myobj; - int ok; - - /* Test implementation, only at top level */ - CH_TYPE under = '_'; - - myobj = STROBJ_STR(fieldobj); - if (myobj == NULL) - return 0; - ok = output_data(fs, STROBJ_AS_PTR(myobj), - STROBJ_GET_SIZE(myobj)); - Py_DECREF(myobj); - if (!ok) - return 0; - if (fs->fieldspec.ptr != fs->fieldspec.end) { - if (!output_data(fs, &under, 1)) - return 0; - if (!output_data(fs, fs->fieldspec.ptr, - fs->fieldspec.end - fs->fieldspec.ptr)) - return 0; - } - return 1; -} - /************************************************************************/ /************************* Builtin formatters *************************/ /************************************************************************/ @@ -1616,11 +1588,85 @@ return 1; } +/* this code is really the same as format_exponent, except it calls + PyOS_snprintf() instead of PyOS_ascii_formatd(). it needs to be + refactored to avoid all of the duplicate code. */ static int format_locale_number(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - return format_DUMMY(fieldobj, fs); + /* first, do the conversion as 8-bit chars, using the platform's + snprintf. then, if needed, convert to unicode. */ + + /* fmt = '%.' + `prec` + `type` + '%%' + worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/ + char fmt[20]; + + double x; + CH_TYPE type = 'f'; + Py_ssize_t precision = format->precision; + CH_TYPE *buf; + int buflen; + int len; + char* trailing = ""; + + /* 'F' is the same as 'f', per the PEP */ + if (type == 'F') + type = 'f'; + + x = PyFloat_AsDouble(fieldobj); + if (x == -1.0 && PyErr_Occurred()) + return 0; + + if (precision < 0) + precision = 6; + if (type == 'f' && (fabs(x) / 1e25) >= 1e25) + type = 'g'; + + /* cast "type", because if we're in unicode we need to pass a + 8-bit char. this is safe, because we've restricted what "type" + can be */ + PyOS_snprintf(fmt, sizeof(fmt), "%%.%d%c%s", precision, (char)type, trailing); + + /* this is taken from unicodeobject.c, except we don't force a + limit here, we dynamically allocate instead */ + /* Worst case length calc to ensure no buffer overrun: + + 'g' formats: + fmt = %#.g + buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp + for any double rep.) + len = 1 + prec + 1 + 2 + 5 = 9 + prec + + 'f' formats: + buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50) + len = 1 + 50 + 1 + prec = 52 + prec + + If prec=0 the effective precision is 1 (the leading digit is + always given), therefore increase the length by one. + + */ + /* so, allocate the precision plus 54 chars (we add one additional + for the trailing percent). do this allocation as the native + type, because we're going to convert to unicode anyway */ + buflen = 54 + precision; + if (output_allocate(fs, buflen, &buf) == 0) + return 0; + PyOS_snprintf((char *)buf, buflen, fmt, x); + +#if C_UNICODE + len = strtounicode(buf, (char*)buf, -1); +#else + /* compute the length. I believe this is done because the return + value from snprintf above is unreliable */ + len = strlen(buf); +#endif + + /* shrink the buffer down to how many characters we actually + wrote. this is cheap, just pointer arithmetic */ + output_shrink(fs, buflen - len); + + return 1; } static int From python-checkins at python.org Tue Mar 6 04:27:49 2007 From: python-checkins at python.org (eric.smith) Date: Tue, 6 Mar 2007 04:27:49 +0100 (CET) Subject: [Python-checkins] r54144 - sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070306032749.B37811E400C@bag.python.org> Author: eric.smith Date: Tue Mar 6 04:27:46 2007 New Revision: 54144 Modified: sandbox/trunk/pep3101/README.txt sandbox/trunk/pep3101/unicodeformat.c Log: Refactored so that format_locale_number() and format_float() share the same code, except for the call in the middle that does the actual formatting. Modified: sandbox/trunk/pep3101/README.txt ============================================================================== --- sandbox/trunk/pep3101/README.txt (original) +++ sandbox/trunk/pep3101/README.txt Tue Mar 6 04:27:46 2007 @@ -61,8 +61,6 @@ - Add capability to control exception handling to pep_differences and to code: 1) ability to dump exceptions into string, 2) ability to re-do lower exceptions or "pile-on" - - Refactor format_locale_number() and format_float() to avoid - massive code duplication. - Test suite needs to test different locales for 'n' formatting. Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Tue Mar 6 04:27:46 2007 @@ -1504,48 +1504,55 @@ return 1; } +/* state that needs to be passed between _format_float_phase1() and + _format_float_phase2() */ +typedef struct { + /* fmt = '%.' + `prec` + `type` + '%%' + worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/ + char fmt[20]; + CH_TYPE *buf; + int buflen; + double x; +} FloatState; + +/* use type instead of format->type, so that it can be overridden by + format_locale_number() */ static int -format_float(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) +_format_float_phase1(FloatState *state, CH_TYPE type, PyObject *fieldobj, + FmtState *fs, const InternalFormatSpec *format) { /* first, do the conversion as 8-bit chars, using the platform's snprintf. then, if needed, convert to unicode. */ - /* fmt = '%.' + `prec` + `type` + '%%' - worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/ - char fmt[20]; - - double x; - CH_TYPE type = format->type; Py_ssize_t precision = format->precision; - CH_TYPE *buf; - int buflen; - int len; char* trailing = ""; /* 'F' is the same as 'f', per the PEP */ if (type == 'F') type = 'f'; - x = PyFloat_AsDouble(fieldobj); - if (x == -1.0 && PyErr_Occurred()) + state->x = PyFloat_AsDouble(fieldobj); + if (state->x == -1.0 && PyErr_Occurred()) { + printf("not a float\n"); return 0; + } if (type == '%') { type = 'f'; - x *= 100; + state->x *= 100; trailing = "%%"; } if (precision < 0) precision = 6; - if (type == 'f' && (fabs(x) / 1e25) >= 1e25) + if (type == 'f' && (fabs(state->x) / 1e25) >= 1e25) type = 'g'; /* cast "type", because if we're in unicode we need to pass a 8-bit char. this is safe, because we've restricted what "type" can be */ - PyOS_snprintf(fmt, sizeof(fmt), "%%.%d%c%s", precision, (char)type, trailing); + PyOS_snprintf(state->fmt, sizeof(state->fmt), "%%.%d%c%s", precision, + (char)type, trailing); /* this is taken from unicodeobject.c, except we don't force a limit here, we dynamically allocate instead */ @@ -1568,108 +1575,60 @@ /* so, allocate the precision plus 54 chars (we add one additional for the trailing percent). do this allocation as the native type, because we're going to convert to unicode anyway */ - buflen = 54 + precision; - if (output_allocate(fs, buflen, &buf) == 0) + state->buflen = 54 + precision; + if (output_allocate(fs, state->buflen, &state->buf) == 0) return 0; - PyOS_ascii_formatd((char *)buf, buflen, fmt, x); - -#if C_UNICODE - len = strtounicode(buf, (char*)buf, -1); -#else - /* compute the length. I believe this is done because the return - value from snprintf above is unreliable */ - len = strlen(buf); -#endif - - /* shrink the buffer down to how many characters we actually - wrote. this is cheap, just pointer arithmetic */ - output_shrink(fs, buflen - len); return 1; } -/* this code is really the same as format_exponent, except it calls - PyOS_snprintf() instead of PyOS_ascii_formatd(). it needs to be - refactored to avoid all of the duplicate code. */ + static int -format_locale_number(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) +_format_float_phase2(FloatState *state, FmtState *fs) { - /* first, do the conversion as 8-bit chars, using the platform's - snprintf. then, if needed, convert to unicode. */ - - /* fmt = '%.' + `prec` + `type` + '%%' - worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/ - char fmt[20]; - - double x; - CH_TYPE type = 'f'; - Py_ssize_t precision = format->precision; - CH_TYPE *buf; - int buflen; int len; - char* trailing = ""; - - /* 'F' is the same as 'f', per the PEP */ - if (type == 'F') - type = 'f'; - - x = PyFloat_AsDouble(fieldobj); - if (x == -1.0 && PyErr_Occurred()) - return 0; - - if (precision < 0) - precision = 6; - if (type == 'f' && (fabs(x) / 1e25) >= 1e25) - type = 'g'; - - /* cast "type", because if we're in unicode we need to pass a - 8-bit char. this is safe, because we've restricted what "type" - can be */ - PyOS_snprintf(fmt, sizeof(fmt), "%%.%d%c%s", precision, (char)type, trailing); - - /* this is taken from unicodeobject.c, except we don't force a - limit here, we dynamically allocate instead */ - /* Worst case length calc to ensure no buffer overrun: - - 'g' formats: - fmt = %#.g - buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp - for any double rep.) - len = 1 + prec + 1 + 2 + 5 = 9 + prec - - 'f' formats: - buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50) - len = 1 + 50 + 1 + prec = 52 + prec - - If prec=0 the effective precision is 1 (the leading digit is - always given), therefore increase the length by one. - - */ - /* so, allocate the precision plus 54 chars (we add one additional - for the trailing percent). do this allocation as the native - type, because we're going to convert to unicode anyway */ - buflen = 54 + precision; - if (output_allocate(fs, buflen, &buf) == 0) - return 0; - PyOS_snprintf((char *)buf, buflen, fmt, x); #if C_UNICODE - len = strtounicode(buf, (char*)buf, -1); + len = strtounicode(state->buf, (char*)state->buf, -1); #else /* compute the length. I believe this is done because the return value from snprintf above is unreliable */ - len = strlen(buf); + len = strlen(state->buf); #endif /* shrink the buffer down to how many characters we actually wrote. this is cheap, just pointer arithmetic */ - output_shrink(fs, buflen - len); + output_shrink(fs, state->buflen - len); return 1; } static int +format_float(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) +{ + FloatState state; + if (_format_float_phase1(&state, format->type, fieldobj, fs, format) == 0) + return 0; + PyOS_ascii_formatd((char *)state.buf, state.buflen, state.fmt, state.x); + return _format_float_phase2(&state, fs); +} + +/* this code is really the same as format_exponent, except it calls + PyOS_snprintf() instead of PyOS_ascii_formatd(). */ +static int +format_locale_number(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) +{ + FloatState state; + if (_format_float_phase1(&state, 'f', fieldobj, fs, format) == 0) { + return 0; + } + PyOS_snprintf((char *)state.buf, state.buflen, state.fmt, state.x); + return _format_float_phase2(&state, fs); +} + +static int format_repr(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { From python-checkins at python.org Tue Mar 6 04:58:52 2007 From: python-checkins at python.org (patrick.maupin) Date: Tue, 6 Mar 2007 04:58:52 +0100 (CET) Subject: [Python-checkins] r54145 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070306035852.682831E400C@bag.python.org> Author: patrick.maupin Date: Tue Mar 6 04:58:48 2007 New Revision: 54145 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Added some tests, squashed a recursion bug and fixed an error message Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Tue Mar 6 04:58:48 2007 @@ -300,12 +300,9 @@ self.formatRaises(ValueError, "}{", True) self.formatRaises(ValueError, "{0", True) self.formatRaises(ValueError, "{0.[]}", True) - # XXX: these raise the wrong exceptions - #self.formatRaises(ValueError, "{0[0}", True) - #self.formatRaises(ValueError, "{0[0:foo}", True) + self.formatRaises(ValueError, "{0[0}", [1]) + self.formatRaises(ValueError, "{0[0:foo}", [1]) self.formatRaises(ValueError, "{c]}", True) - # XXX: this should *not* raise - #self.formatRaises(ValueError, "{{1}}", True, 0) self.formatRaises(ValueError, "{{ {{{0}}", True) self.formatRaises(ValueError, "{0}}", True) @@ -387,6 +384,15 @@ self.formatRaises(ValueError, '{!syntax3}{') self.formatEquals('{', '{!syntax3}{ ') + def test_computed_lookups(self): + class Custom(object): + fred = 'Hi there' + self.formatEquals('e', '{0[{1}]}', 'abcdefg', 4) + self.formatEquals('e', '{foo[{bar}]}', foo='abcdefg', bar=4) + self.formatEquals(Custom.fred, '{0.{1}}', Custom, 'fred') + self.formatEquals(Custom.fred, '{x.{y}}', x=Custom, y='fred') + self.formatEquals('t', '{x.{y}[{0}]}', 3, x=Custom, y='fred') + def test_main(): test_support.run_unittest(FormatTest) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Tue Mar 6 04:58:48 2007 @@ -572,6 +572,7 @@ /* This little bit of mutual recursion allows nested dictionary lookups and computed attribute names */ + fs->fmtstr.ptr++; if (--(fs->max_recursion) < 0) return SetError(fs, "Maximum string recursion limit exceeded"); result = get_field_object(fs); @@ -1968,7 +1969,7 @@ at_end = ptr >= end; switch (syntaxmode) { case 0: - if ((c == '}') && (!at_end) && (c != *ptr)) + if ((c == '}') && (at_end || (c != *ptr))) return (int)SetError(fs, "Single } encountered"); case 1: if (at_end) From python-checkins at python.org Tue Mar 6 05:04:01 2007 From: python-checkins at python.org (eric.smith) Date: Tue, 6 Mar 2007 05:04:01 +0100 (CET) Subject: [Python-checkins] r54146 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070306040401.7F7471E400C@bag.python.org> Author: eric.smith Date: Tue Mar 6 05:03:49 2007 New Revision: 54146 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Refactored float formatting, again. This time it's simpler by using a callback, instead of the two-phase version I used last time. Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Tue Mar 6 05:03:49 2007 @@ -66,7 +66,6 @@ #define PySet_Discard PyDict_DelItem #define PySet_New PyDict_Copy #define PySet_GET_SIZE PyDict_Size -#define PyOS_ascii_formatd PyOS_snprintf #endif @@ -1505,54 +1504,65 @@ return 1; } -/* state that needs to be passed between _format_float_phase1() and - _format_float_phase2() */ -typedef struct { +/* the callback function to call to do the actual float formatting. + it matches the definition of PyOS_ascii_formatd */ +typedef char* +(*DoubleSnprintfFunction)(char *buffer, size_t buf_len, + const char *format, double d); + +/* just a wrapper to make PyOS_snprintf look like DoubleSnprintfFunction */ +static char* +snprintf_double(char *buffer, size_t buf_len, const char *format, double d) +{ + PyOS_snprintf(buffer, buf_len, format, d); + return NULL; +} + +/* use type instead of format->type, so that it can be overridden by + format_locale_number() */ +static int +_format_float(CH_TYPE type, PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format, + DoubleSnprintfFunction snprintf) +{ /* fmt = '%.' + `prec` + `type` + '%%' worst case length = 2 + 10 (len of INT_MAX) + 1 + 2 = 15 (use 20)*/ char fmt[20]; CH_TYPE *buf; int buflen; double x; -} FloatState; + int len; + Py_ssize_t precision = format->precision; + char* trailing = ""; -/* use type instead of format->type, so that it can be overridden by - format_locale_number() */ -static int -_format_float_phase1(FloatState *state, CH_TYPE type, PyObject *fieldobj, - FmtState *fs, const InternalFormatSpec *format) -{ /* first, do the conversion as 8-bit chars, using the platform's snprintf. then, if needed, convert to unicode. */ - Py_ssize_t precision = format->precision; - char* trailing = ""; - /* 'F' is the same as 'f', per the PEP */ if (type == 'F') type = 'f'; - state->x = PyFloat_AsDouble(fieldobj); - if (state->x == -1.0 && PyErr_Occurred()) { + x = PyFloat_AsDouble(fieldobj); + if (x == -1.0 && PyErr_Occurred()) { printf("not a float\n"); return 0; } if (type == '%') { type = 'f'; - state->x *= 100; + x *= 100; trailing = "%%"; } if (precision < 0) precision = 6; - if (type == 'f' && (fabs(state->x) / 1e25) >= 1e25) + if (type == 'f' && (fabs(x) / 1e25) >= 1e25) type = 'g'; /* cast "type", because if we're in unicode we need to pass a 8-bit char. this is safe, because we've restricted what "type" can be */ - PyOS_snprintf(state->fmt, sizeof(state->fmt), "%%.%d%c%s", precision, + PyOS_snprintf(fmt, sizeof(fmt), "%%.%d%c%s", precision, (char)type, trailing); /* this is taken from unicodeobject.c, except we don't force a @@ -1576,30 +1586,24 @@ /* so, allocate the precision plus 54 chars (we add one additional for the trailing percent). do this allocation as the native type, because we're going to convert to unicode anyway */ - state->buflen = 54 + precision; - if (output_allocate(fs, state->buflen, &state->buf) == 0) + buflen = 54 + precision; + if (output_allocate(fs, buflen, &buf) == 0) return 0; - return 1; -} - - -static int -_format_float_phase2(FloatState *state, FmtState *fs) -{ - int len; + /* call the passed in function to do the actual formatting */ + snprintf((char*)buf, buflen, fmt, x); #if C_UNICODE - len = strtounicode(state->buf, (char*)state->buf, -1); + len = strtounicode(buf, (char*)buf, -1); #else /* compute the length. I believe this is done because the return value from snprintf above is unreliable */ - len = strlen(state->buf); + len = strlen(buf); #endif /* shrink the buffer down to how many characters we actually wrote. this is cheap, just pointer arithmetic */ - output_shrink(fs, state->buflen - len); + output_shrink(fs, buflen - len); return 1; } @@ -1608,11 +1612,13 @@ format_float(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - FloatState state; - if (_format_float_phase1(&state, format->type, fieldobj, fs, format) == 0) - return 0; - PyOS_ascii_formatd((char *)state.buf, state.buflen, state.fmt, state.x); - return _format_float_phase2(&state, fs); + return _format_float(format->type, fieldobj, fs, format, +#if PYTHON_API_VERSION < 1013 + snprintf_double +#else + PyOS_ascii_formatd +#endif + ); } /* this code is really the same as format_exponent, except it calls @@ -1621,12 +1627,7 @@ format_locale_number(PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format) { - FloatState state; - if (_format_float_phase1(&state, 'f', fieldobj, fs, format) == 0) { - return 0; - } - PyOS_snprintf((char *)state.buf, state.buflen, state.fmt, state.x); - return _format_float_phase2(&state, fs); + return _format_float('f', fieldobj, fs, format, snprintf_double); } static int From python-checkins at python.org Tue Mar 6 06:04:39 2007 From: python-checkins at python.org (patrick.maupin) Date: Tue, 6 Mar 2007 06:04:39 +0100 (CET) Subject: [Python-checkins] r54147 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070306050439.CB6AF1E400C@bag.python.org> Author: patrick.maupin Date: Tue Mar 6 06:04:37 2007 New Revision: 54147 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Broke output_allocate into two functions Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Tue Mar 6 06:04:37 2007 @@ -424,6 +424,30 @@ } /* + output_extend reallocates the output string buffer. + It returns a status: 0 for a failed reallocation, + 1 for success. +*/ + +static int +output_extend(FmtState *fs, Py_ssize_t count) +{ + CH_TYPE *startptr; + Py_ssize_t curlen, maxlen; + startptr = STROBJ_AS_PTR(fs->outstr.obj); + curlen = fs->outstr.ptr - startptr; + maxlen = curlen + count + fs->size_increment; + if (STROBJ_RESIZE(&fs->outstr.obj, maxlen) < 0) + return 0; + startptr = STROBJ_AS_PTR(fs->outstr.obj); + fs->outstr.ptr = startptr + curlen; + fs->outstr.end = startptr + maxlen; + if (fs->size_increment < MAX_SIZE_INCREMENT) + fs->size_increment *= SIZE_MULTIPLIER; + return 1; +} + +/* output_allocate reserves space in our output string buffer In some cases, it has to reallocate the string. @@ -437,21 +461,9 @@ static int output_allocate(FmtState *fs, Py_ssize_t count, CH_TYPE **ptr) { - Py_ssize_t room = fs->outstr.end - fs->outstr.ptr; - if (count > room) { - CH_TYPE *startptr; - Py_ssize_t curlen, maxlen; - startptr = STROBJ_AS_PTR(fs->outstr.obj); - curlen = fs->outstr.ptr - startptr; - maxlen = curlen + count + fs->size_increment; - if (STROBJ_RESIZE(&fs->outstr.obj, maxlen) < 0) - return 0; - startptr = STROBJ_AS_PTR(fs->outstr.obj); - fs->outstr.ptr = startptr + curlen; - fs->outstr.end = startptr + maxlen; - if (fs->size_increment < MAX_SIZE_INCREMENT) - fs->size_increment *= SIZE_MULTIPLIER; - } + if ((count > fs->outstr.end - fs->outstr.ptr) && + !output_extend(fs, count)) + return 0; *ptr = fs->outstr.ptr; fs->outstr.ptr += count; return 1; @@ -469,20 +481,11 @@ static int output_data(FmtState *fs, const CH_TYPE *s, Py_ssize_t count) { - CH_TYPE *dst; - - /* there is some duplicate code here with output_allocate, - which is here to avoid a function call if there's already - enough allocated space */ - Py_ssize_t room = fs->outstr.end - fs->outstr.ptr; - if (count > room) { - if (output_allocate(fs, count, &dst) == 0) - return 0; - } else { - dst = fs->outstr.ptr; - fs->outstr.ptr += count; - } - memcpy(dst, s, count * sizeof(CH_TYPE)); + if ((count > fs->outstr.end - fs->outstr.ptr) && + !output_extend(fs, count)) + return 0; + memcpy(fs->outstr.ptr, s, count * sizeof(CH_TYPE)); + fs->outstr.ptr += count; return 1; } From buildbot at python.org Tue Mar 6 06:11:47 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 05:11:47 +0000 Subject: [Python-checkins] buildbot warnings in MIPS Debian 2.5 Message-ID: <20070306051147.909351E400C@bag.python.org> The Buildbot has detected a new failure of MIPS Debian 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/MIPS%2520Debian%25202.5/builds/148 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/httplib.py", line 856, in endheaders self._send_output() File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/httplib.py", line 728, in _send_output self.send(msg) File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/httplib.py", line 695, in send self.connect() File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/httplib.py", line 1131, in connect ssl = socket.ssl(sock, self.key_file, self.cert_file) File "/home/pybot/buildarea/2.5.klose-debian-mips/build/Lib/socket.py", line 74, in ssl return _realssl(sock, keyfile, certfile) IOError: [Errno socket error] (8, 'EOF occurred in violation of protocol') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 10:30:32 2007 From: python-checkins at python.org (eric.smith) Date: Tue, 6 Mar 2007 10:30:32 +0100 (CET) Subject: [Python-checkins] r54148 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070306093032.4E7111E400C@bag.python.org> Author: eric.smith Date: Tue Mar 6 10:30:21 2007 New Revision: 54148 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Removed unused FORMATBUFLEN. Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Tue Mar 6 10:30:21 2007 @@ -77,23 +77,12 @@ + 1 + 1 = 24 */ #define MAXLEN_INT_STRING 64 +#define ABS(x) ((x) < 0 ? -(x) : (x)) + /************************************************************************/ /*********** Global data structures and forward declarations *********/ /************************************************************************/ -/* FORMATBUFLEN is taken from stringobject.c, it should probably be - factored out */ -/* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) - - FORMATBUFLEN is the length of the buffer in which the floats, ints, & - chars are formatted. XXX This is a magic number. Each formatting - routine does bounds checking to ensure no overflow, but a better - solution may be to malloc a buffer of appropriate size for each - format. For now, the current solution is sufficient. -*/ -#define FORMATBUFLEN (size_t)120 - -#define ABS(x) ((x) < 0 ? -(x) : (x)) #ifdef __cplusplus extern "C" { From python-checkins at python.org Tue Mar 6 10:33:05 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 10:33:05 +0100 (CET) Subject: [Python-checkins] r54149 - python/trunk/Doc/api/newtypes.tex Message-ID: <20070306093305.D294C1E400C@bag.python.org> Author: georg.brandl Date: Tue Mar 6 10:33:01 2007 New Revision: 54149 Modified: python/trunk/Doc/api/newtypes.tex Log: Nit: a struct field is set to GenericAlloc, not GenericAlloc(). Modified: python/trunk/Doc/api/newtypes.tex ============================================================================== --- python/trunk/Doc/api/newtypes.tex (original) +++ python/trunk/Doc/api/newtypes.tex Tue Mar 6 10:33:01 2007 @@ -1316,7 +1316,7 @@ This field is inherited by static subtypes, but not by dynamic subtypes (subtypes created by a class statement); in the latter, - this field is always set to \cfunction{PyType_GenericAlloc()}, to + this field is always set to \cfunction{PyType_GenericAlloc}, to force a standard heap allocation strategy. That is also the recommended value for statically defined types. \end{cmemberdesc} From python-checkins at python.org Tue Mar 6 11:02:53 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 11:02:53 +0100 (CET) Subject: [Python-checkins] r54150 - in python/trunk: Doc/ext/newtypes.tex Doc/ext/shoddy.c Misc/NEWS Message-ID: <20070306100253.057651E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 11:02:47 2007 New Revision: 54150 Added: python/trunk/Doc/ext/shoddy.c Modified: python/trunk/Doc/ext/newtypes.tex python/trunk/Misc/NEWS Log: Patch #1671450: add a section about subclassing builtin types to the "extending and embedding" tutorial. Modified: python/trunk/Doc/ext/newtypes.tex ============================================================================== --- python/trunk/Doc/ext/newtypes.tex (original) +++ python/trunk/Doc/ext/newtypes.tex Tue Mar 6 11:02:47 2007 @@ -489,7 +489,6 @@ garbage collection, there are calls that can be made to ``untrack'' the object from garbage collection, however, these calls are advanced and not covered here.} -\item \end{itemize} @@ -930,6 +929,102 @@ collection. Most extensions will use the versions automatically provided. +\subsection{Subclassing other types} + +It is possible to create new extension types that are derived from existing +types. It is easiest to inherit from the built in types, since an extension +can easily use the \class{PyTypeObject} it needs. It can be difficult to +share these \class{PyTypeObject} structures between extension modules. + +In this example we will create a \class{Shoddy} type that inherits from +the builtin \class{list} type. The new type will be completely compatible +with regular lists, but will have an additional \method{increment()} method +that increases an internal counter. + +\begin{verbatim} +>>> import shoddy +>>> s = shoddy.Shoddy(range(3)) +>>> s.extend(s) +>>> print len(s) +6 +>>> print s.increment() +1 +>>> print s.increment() +2 +\end{verbatim} + +\verbatiminput{shoddy.c} + +As you can see, the source code closely resembles the \class{Noddy} examples in previous +sections. We will break down the main differences between them. + +\begin{verbatim} +typedef struct { + PyListObject list; + int state; +} Shoddy; +\end{verbatim} + +The primary difference for derived type objects is that the base type's +object structure must be the first value. The base type will already +include the \cfunction{PyObject_HEAD} at the beginning of its structure. + +When a Python object is a \class{Shoddy} instance, its \var{PyObject*} pointer +can be safely cast to both \var{PyListObject*} and \var{Shoddy*}. + +\begin{verbatim} +static int +Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) +{ + if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} +\end{verbatim} + +In the \member{__init__} method for our type, we can see how to call through +to the \member{__init__} method of the base type. + +This pattern is important when writing a type with custom \member{new} and +\member{dealloc} methods. The \member{new} method should not actually create the +memory for the object with \member{tp_alloc}, that will be handled by +the base class when calling its \member{tp_new}. + +When filling out the \cfunction{PyTypeObject} for the \class{Shoddy} type, +you see a slot for \cfunction{tp_base}. Due to cross platform compiler +issues, you can't fill that field directly with the \cfunction{PyList_Type}; +it can be done later in the module's \cfunction{init} function. + +\begin{verbatim} +PyMODINIT_FUNC +initshoddy(void) +{ + PyObject *m; + + ShoddyType.tp_base = &PyList_Type; + if (PyType_Ready(&ShoddyType) < 0) + return; + + m = Py_InitModule3("shoddy", NULL, "Shoddy module"); + if (m == NULL) + return; + + Py_INCREF(&ShoddyType); + PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); +} +\end{verbatim} + +Before calling \cfunction{PyType_Ready}, the type structure must have the +\member{tp_base} slot filled in. When we are deriving a new type, it is +not necessary to fill out the \member{tp_alloc} slot with +\cfunction{PyType_GenericNew} -- the allocate function from the base type +will be inherited. + +After that, calling \cfunction{PyType_Ready} and adding the type object +to the module is the same as with the basic \class{Noddy} examples. + + \section{Type Methods \label{dnt-type-methods}} Added: python/trunk/Doc/ext/shoddy.c ============================================================================== --- (empty file) +++ python/trunk/Doc/ext/shoddy.c Tue Mar 6 11:02:47 2007 @@ -0,0 +1,91 @@ +#include + +typedef struct { + PyListObject list; + int state; +} Shoddy; + + +static PyObject * +Shoddy_increment(Shoddy *self, PyObject *unused) +{ + self->state++; + return PyInt_FromLong(self->state); +} + + +static PyMethodDef Shoddy_methods[] = { + {"increment", (PyCFunction)Shoddy_increment, METH_NOARGS, + PyDoc_STR("increment state counter")}, + {NULL, NULL}, +}; + +static int +Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) +{ + if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} + + +static PyTypeObject ShoddyType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "shoddy.Shoddy", /* tp_name */ + sizeof(Shoddy), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* 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 | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Shoddy_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Shoddy_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +PyMODINIT_FUNC +initshoddy(void) +{ + PyObject *m; + + ShoddyType.tp_base = &PyList_Type; + if (PyType_Ready(&ShoddyType) < 0) + return; + + m = Py_InitModule3("shoddy", NULL, "Shoddy module"); + if (m == NULL) + return; + + Py_INCREF(&ShoddyType); + PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); +} Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 11:02:47 2007 @@ -502,6 +502,9 @@ Documentation ------------- +- Patch #1671450: add a section about subclassing builtin types to the + "extending and embedding" tutorial. + - Bug #1629125: fix wrong data type (int -> Py_ssize_t) in PyDict_Next docs. From python-checkins at python.org Tue Mar 6 11:03:03 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 11:03:03 +0100 (CET) Subject: [Python-checkins] r54151 - in python/branches/release25-maint: Doc/ext/newtypes.tex Doc/ext/shoddy.c Misc/NEWS Message-ID: <20070306100303.16B9A1E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 11:02:59 2007 New Revision: 54151 Added: python/branches/release25-maint/Doc/ext/shoddy.c Modified: python/branches/release25-maint/Doc/ext/newtypes.tex python/branches/release25-maint/Misc/NEWS Log: Patch #1671450: add a section about subclassing builtin types to the "extending and embedding" tutorial. (backport from rev. 54150) Modified: python/branches/release25-maint/Doc/ext/newtypes.tex ============================================================================== --- python/branches/release25-maint/Doc/ext/newtypes.tex (original) +++ python/branches/release25-maint/Doc/ext/newtypes.tex Tue Mar 6 11:02:59 2007 @@ -489,7 +489,6 @@ garbage collection, there are calls that can be made to ``untrack'' the object from garbage collection, however, these calls are advanced and not covered here.} -\item \end{itemize} @@ -930,6 +929,102 @@ collection. Most extensions will use the versions automatically provided. +\subsection{Subclassing other types} + +It is possible to create new extension types that are derived from existing +types. It is easiest to inherit from the built in types, since an extension +can easily use the \class{PyTypeObject} it needs. It can be difficult to +share these \class{PyTypeObject} structures between extension modules. + +In this example we will create a \class{Shoddy} type that inherits from +the builtin \class{list} type. The new type will be completely compatible +with regular lists, but will have an additional \method{increment()} method +that increases an internal counter. + +\begin{verbatim} +>>> import shoddy +>>> s = shoddy.Shoddy(range(3)) +>>> s.extend(s) +>>> print len(s) +6 +>>> print s.increment() +1 +>>> print s.increment() +2 +\end{verbatim} + +\verbatiminput{shoddy.c} + +As you can see, the source code closely resembles the \class{Noddy} examples in previous +sections. We will break down the main differences between them. + +\begin{verbatim} +typedef struct { + PyListObject list; + int state; +} Shoddy; +\end{verbatim} + +The primary difference for derived type objects is that the base type's +object structure must be the first value. The base type will already +include the \cfunction{PyObject_HEAD} at the beginning of its structure. + +When a Python object is a \class{Shoddy} instance, its \var{PyObject*} pointer +can be safely cast to both \var{PyListObject*} and \var{Shoddy*}. + +\begin{verbatim} +static int +Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) +{ + if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} +\end{verbatim} + +In the \member{__init__} method for our type, we can see how to call through +to the \member{__init__} method of the base type. + +This pattern is important when writing a type with custom \member{new} and +\member{dealloc} methods. The \member{new} method should not actually create the +memory for the object with \member{tp_alloc}, that will be handled by +the base class when calling its \member{tp_new}. + +When filling out the \cfunction{PyTypeObject} for the \class{Shoddy} type, +you see a slot for \cfunction{tp_base}. Due to cross platform compiler +issues, you can't fill that field directly with the \cfunction{PyList_Type}; +it can be done later in the module's \cfunction{init} function. + +\begin{verbatim} +PyMODINIT_FUNC +initshoddy(void) +{ + PyObject *m; + + ShoddyType.tp_base = &PyList_Type; + if (PyType_Ready(&ShoddyType) < 0) + return; + + m = Py_InitModule3("shoddy", NULL, "Shoddy module"); + if (m == NULL) + return; + + Py_INCREF(&ShoddyType); + PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); +} +\end{verbatim} + +Before calling \cfunction{PyType_Ready}, the type structure must have the +\member{tp_base} slot filled in. When we are deriving a new type, it is +not necessary to fill out the \member{tp_alloc} slot with +\cfunction{PyType_GenericNew} -- the allocate function from the base type +will be inherited. + +After that, calling \cfunction{PyType_Ready} and adding the type object +to the module is the same as with the basic \class{Noddy} examples. + + \section{Type Methods \label{dnt-type-methods}} Added: python/branches/release25-maint/Doc/ext/shoddy.c ============================================================================== --- (empty file) +++ python/branches/release25-maint/Doc/ext/shoddy.c Tue Mar 6 11:02:59 2007 @@ -0,0 +1,91 @@ +#include + +typedef struct { + PyListObject list; + int state; +} Shoddy; + + +static PyObject * +Shoddy_increment(Shoddy *self, PyObject *unused) +{ + self->state++; + return PyInt_FromLong(self->state); +} + + +static PyMethodDef Shoddy_methods[] = { + {"increment", (PyCFunction)Shoddy_increment, METH_NOARGS, + PyDoc_STR("increment state counter")}, + {NULL, NULL}, +}; + +static int +Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds) +{ + if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0) + return -1; + self->state = 0; + return 0; +} + + +static PyTypeObject ShoddyType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "shoddy.Shoddy", /* tp_name */ + sizeof(Shoddy), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* 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 | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Shoddy_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Shoddy_init, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +PyMODINIT_FUNC +initshoddy(void) +{ + PyObject *m; + + ShoddyType.tp_base = &PyList_Type; + if (PyType_Ready(&ShoddyType) < 0) + return; + + m = Py_InitModule3("shoddy", NULL, "Shoddy module"); + if (m == NULL) + return; + + Py_INCREF(&ShoddyType); + PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType); +} Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Tue Mar 6 11:02:59 2007 @@ -457,6 +457,9 @@ Documentation ------------- +- Patch #1671450: add a section about subclassing builtin types to the + "extending and embedding" tutorial. + - Bug #1629125: fix wrong data type (int -> Py_ssize_t) in PyDict_Next docs. From nnorwitz at gmail.com Tue Mar 6 11:33:55 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Tue, 6 Mar 2007 05:33:55 -0500 Subject: [Python-checkins] Python Regression Test Failures all (1) Message-ID: <20070306103355.GA19215@python.psfb.org> test_grammar test_opcodes test_operations test_builtin test_exceptions test_types test_MimeWriter test_StringIO test___all__ test___future__ test__locale test_aepack test_aepack skipped -- No module named aepack test_al test_al skipped -- No module named al test_anydbm test_applesingle test_applesingle skipped -- No module named macostools test_array test_ast test_asynchat test_atexit test_audioop test_augassign test_base64 test_bastion test_bigaddrspace test_bigmem test_binascii test_binhex test_binop test_bisect test_bool test_bsddb test_bsddb185 test_bsddb185 skipped -- No module named bsddb185 test_bsddb3 test_bufio test_bz2 test_cProfile test_calendar test_call test_capi test_cd test_cd skipped -- No module named cd test_cfgparser test_cgi test_charmapcodec test_cl test_cl skipped -- No module named cl test_class test_cmath test_cmd_line test_code test_codeccallbacks test_codecencodings_cn test_codecencodings_hk test_codecencodings_jp test_codecencodings_kr test_codecencodings_tw test_codecmaps_cn test_codecmaps_hk test_codecmaps_jp test_codecmaps_kr test_codecmaps_tw test_codecs test_codeop test_coding test_coercion test_collections test_colorsys test_commands test_compare test_compile test_compiler test_complex test_complex_args test_contains test_contextlib test_cookie test_cookielib test_copy test_copy_reg test_cpickle test_crypt test_csv test_ctypes test_datetime test_dbm test_decimal test_decorators test_defaultdict test_deque test_descr test_descrtut test_dict test_difflib test_dircache test_dis test_distutils test_dl test_doctest test_doctest2 test_dumbdbm test_dummy_thread test_dummy_threading test_email test_email_codecs test_email_renamed test_enumerate test_eof test_errno test_exception_variations test_extcall test_fcntl test_file test_filecmp test_fileinput test_float test_fnmatch test_fork1 test_format test_fpformat test_frozen test_funcattrs test_functools test_future test_gc test_gdbm test_generators test_genericpath test_genexps test_getargs test_getargs2 test_getopt test_gettext test_gl test_gl skipped -- No module named gl test_glob test_global test_grp test_gzip test_hash test_hashlib test_heapq test_hexoct test_hmac test_hotshot test_htmllib test_htmlparser test_httplib test_imageop test_imaplib test_imgfile test_imgfile skipped -- No module named imgfile test_imp test_import test_importhooks test_index test_inspect test_ioctl test_ioctl skipped -- Unable to open /dev/tty test_isinstance test_iter test_iterlen test_itertools test_largefile test_list test_locale test_logging test_long test_long_future test_longexp test_macfs test_macfs skipped -- No module named macfs test_macostools test_macostools skipped -- No module named macostools test_macpath test_mailbox test_marshal test_math test_md5 test_mhlib test_mimetools test_mimetypes test_minidom test_mmap test_module test_modulefinder test_multibytecodec test_multibytecodec_support test_multifile test_mutants test_netrc test_new test_nis test_normalization test_ntpath test_old_mailbox test_openpty test_operator test_optparse test_os test_parser test_peepholer test_pep247 test_pep263 test_pep277 test_pep277 skipped -- test works only on NT+ test_pep292 test_pep352 test_pickle test_pickletools test_pkg test_pkgimport test_platform test_plistlib test_plistlib skipped -- No module named plistlib test_poll test_popen [7321 refs] [7321 refs] [7321 refs] test_popen2 test_posix test_posixpath test_pow test_pprint test_profile test_profilehooks test_pty test_pwd test_pyclbr test_pyexpat test_queue test_quopri [7696 refs] [7696 refs] test_random test_re test_repr test_resource test_rfc822 test_rgbimg test_richcmp test_robotparser test_runpy test_sax test_scope test_scriptpackages test_scriptpackages skipped -- No module named aetools test_select test_set test_sets test_sgmllib test_sha test_shelve test_shlex test_shutil test_signal test_site test_slice test_socket test_socket_ssl test test_socket_ssl crashed -- : [Errno socket error] (110, 'Connection timed out') test_socketserver test_softspace test_sort test_sqlite test_startfile test_startfile skipped -- cannot import name startfile test_str test_strftime test_string test_stringprep test_strop test_strptime test_struct test_structmembers test_structseq test_subprocess [7316 refs] [7317 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7317 refs] [8865 refs] [7532 refs] [7317 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] . [7316 refs] [7316 refs] this bit of output is from a test of stdout in a different process ... [7316 refs] [7316 refs] [7532 refs] test_sunaudiodev test_sunaudiodev skipped -- No module named sunaudiodev test_sundry test_symtable test_syntax test_sys [7316 refs] [7316 refs] test_tarfile test_tcl test_tcl skipped -- No module named _tkinter test_tempfile [7320 refs] test_textwrap test_thread test_threaded_import test_threadedtempfile test_threading test_threading_local test_threadsignals test_time test_timeout test_tokenize test_trace test_traceback test_transformer test_tuple test_ucn test_unary test_unicode test_unicode_file test_unicode_file skipped -- No Unicode filesystem semantics on this platform. test_unicodedata test_unittest test_univnewlines test_unpack test_urllib test_urllib2 test_urllib2net test_urllibnet test_urlparse test_userdict test_userlist test_userstring test_uu test_uuid WARNING: uuid.getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. WARNING: uuid._ifconfig_getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. WARNING: uuid._unixdll_getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. test_wait3 test_wait4 test_warnings test_wave test_weakref test_whichdb test_winreg test_winreg skipped -- No module named _winreg test_winsound test_winsound skipped -- No module named winsound test_with test_wsgiref test_xdrlib test_xml_etree test_xml_etree_c test_xmllib test_xmlrpc test_xpickle test_xrange test_zipfile test_zipfile64 test_zipfile64 skipped -- test requires loads of disk-space bytes and a long time to run test_zipimport test_zlib 299 tests OK. 1 test failed: test_socket_ssl 21 tests skipped: test_aepack test_al test_applesingle test_bsddb185 test_cd test_cl test_gl test_imgfile test_ioctl test_macfs test_macostools test_pep277 test_plistlib test_scriptpackages test_startfile test_sunaudiodev test_tcl test_unicode_file test_winreg test_winsound test_zipfile64 1 skip unexpected on linux2: test_ioctl warning: DBTxn aborted in destructor. No prior commit() or abort(). [463197 refs] From python-checkins at python.org Tue Mar 6 11:41:26 2007 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 6 Mar 2007 11:41:26 +0100 (CET) Subject: [Python-checkins] r54152 - in python/trunk: Doc/lib/libzipfile.tex Lib/test/test_zipfile.py Lib/zipfile.py Misc/NEWS Message-ID: <20070306104126.1E3B61E400E@bag.python.org> Author: martin.v.loewis Date: Tue Mar 6 11:41:24 2007 New Revision: 54152 Modified: python/trunk/Doc/lib/libzipfile.tex python/trunk/Lib/test/test_zipfile.py python/trunk/Lib/zipfile.py python/trunk/Misc/NEWS Log: Patch #1121142: Implement ZipFile.open. Modified: python/trunk/Doc/lib/libzipfile.tex ============================================================================== --- python/trunk/Doc/lib/libzipfile.tex (original) +++ python/trunk/Doc/lib/libzipfile.tex Tue Mar 6 11:41:24 2007 @@ -141,6 +141,32 @@ Return a list of archive members by name. \end{methoddesc} +\begin{methoddesc}{open}{name\optional{, mode\optional{, pwd}}} + Extract a member from the archive as a file-like object (ZipExtFile). + \var{name} is the name of the file in the archive. The \var{mode} + parameter, if included, must be one of the following: \code{'r'} (the + default), \code{'U'}, or \code{'rU'}. Choosing \code{'U'} or + \code{'rU'} will enable universal newline support in the read-only + object. \var{pwd} is the password used for encrypted files. + \begin{notice} + The file-like object is read-only and provides the following methods: + \method{read()}, \method{readline()}, \method{readlines()}, + \method{__iter__()}, \method{next()}. + \end{notice} + \begin{notice} + If the ZipFile was created by passing in a file-like object as the + first argument to the constructor, then the object returned by + \method{open()} shares the ZipFile's file pointer. Under these + circumstances, the object returned by \method{open()} should not + be used after any additional operations are performed on the + ZipFile object. If the ZipFile was created by passing in a string + (the filename) as the first argument to the constructor, then + \method{open()} will create a new file object that will be held + by the ZipExtFile, allowing it to operate independently of the + ZipFile. + \end{notice} +\end{methoddesc} + \begin{methoddesc}{printdir}{} Print a table of contents for the archive to \code{sys.stdout}. \end{methoddesc} Modified: python/trunk/Lib/test/test_zipfile.py ============================================================================== --- python/trunk/Lib/test/test_zipfile.py (original) +++ python/trunk/Lib/test/test_zipfile.py Tue Mar 6 11:41:24 2007 @@ -4,26 +4,29 @@ except ImportError: zlib = None -import zipfile, os, unittest, sys, shutil +import zipfile, os, unittest, sys, shutil, struct from StringIO import StringIO from tempfile import TemporaryFile +from random import randint, random from test.test_support import TESTFN, run_unittest TESTFN2 = TESTFN + "2" +FIXEDTEST_SIZE = 10 class TestsWithSourceFile(unittest.TestCase): def setUp(self): - line_gen = ("Test of zipfile line %d." % i for i in range(0, 1000)) - self.data = '\n'.join(line_gen) + self.line_gen = ("Zipfile test line %d. random float: %f" % (i, random()) + for i in xrange(FIXEDTEST_SIZE)) + self.data = '\n'.join(self.line_gen) + '\n' # Make a source file with some lines fp = open(TESTFN, "wb") fp.write(self.data) fp.close() - def zipTest(self, f, compression): + def makeTestArchive(self, f, compression): # Create the ZIP archive zipfp = zipfile.ZipFile(f, "w", compression) zipfp.write(TESTFN, "another"+os.extsep+"name") @@ -31,6 +34,9 @@ zipfp.writestr("strfile", self.data) zipfp.close() + def zipTest(self, f, compression): + self.makeTestArchive(f, compression) + # Read the ZIP archive zipfp = zipfile.ZipFile(f, "r", compression) self.assertEqual(zipfp.read(TESTFN), self.data) @@ -85,22 +91,144 @@ # Check that testzip doesn't raise an exception zipfp.testzip() + zipfp.close() + def testStored(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipTest(f, zipfile.ZIP_STORED) + def zipOpenTest(self, f, compression): + self.makeTestArchive(f, compression) + + # Read the ZIP archive + zipfp = zipfile.ZipFile(f, "r", compression) + zipdata1 = [] + zipopen1 = zipfp.open(TESTFN) + while 1: + read_data = zipopen1.read(256) + if not read_data: + break + zipdata1.append(read_data) + + zipdata2 = [] + zipopen2 = zipfp.open("another"+os.extsep+"name") + while 1: + read_data = zipopen2.read(256) + if not read_data: + break + zipdata2.append(read_data) + + self.assertEqual(''.join(zipdata1), self.data) + self.assertEqual(''.join(zipdata2), self.data) zipfp.close() + + def testOpenStored(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipOpenTest(f, zipfile.ZIP_STORED) + def zipRandomOpenTest(self, f, compression): + self.makeTestArchive(f, compression) + # Read the ZIP archive + zipfp = zipfile.ZipFile(f, "r", compression) + zipdata1 = [] + zipopen1 = zipfp.open(TESTFN) + while 1: + read_data = zipopen1.read(randint(1, 1024)) + if not read_data: + break + zipdata1.append(read_data) + self.assertEqual(''.join(zipdata1), self.data) + zipfp.close() + + def testRandomOpenStored(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipRandomOpenTest(f, zipfile.ZIP_STORED) + + def zipReadlineTest(self, f, compression): + self.makeTestArchive(f, compression) - def testStored(self): + # Read the ZIP archive + zipfp = zipfile.ZipFile(f, "r") + zipopen = zipfp.open(TESTFN) + for line in self.line_gen: + linedata = zipopen.readline() + self.assertEqual(linedata, line + '\n') + + zipfp.close() + + def zipReadlinesTest(self, f, compression): + self.makeTestArchive(f, compression) + + # Read the ZIP archive + zipfp = zipfile.ZipFile(f, "r") + ziplines = zipfp.open(TESTFN).readlines() + for line, zipline in zip(self.line_gen, ziplines): + self.assertEqual(zipline, line + '\n') + + zipfp.close() + + def zipIterlinesTest(self, f, compression): + self.makeTestArchive(f, compression) + + # Read the ZIP archive + zipfp = zipfile.ZipFile(f, "r") + for line, zipline in zip(self.line_gen, zipfp.open(TESTFN)): + self.assertEqual(zipline, line + '\n') + + zipfp.close() + + def testReadlineStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): - self.zipTest(f, zipfile.ZIP_STORED) + self.zipReadlineTest(f, zipfile.ZIP_STORED) + + def testReadlinesStored(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipReadlinesTest(f, zipfile.ZIP_STORED) + + def testIterlinesStored(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipIterlinesTest(f, zipfile.ZIP_STORED) if zlib: def testDeflated(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipTest(f, zipfile.ZIP_DEFLATED) + def testOpenDeflated(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipOpenTest(f, zipfile.ZIP_DEFLATED) + + def testRandomOpenDeflated(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipRandomOpenTest(f, zipfile.ZIP_DEFLATED) + + def testReadlineDeflated(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipReadlineTest(f, zipfile.ZIP_DEFLATED) + + def testReadlinesDeflated(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipReadlinesTest(f, zipfile.ZIP_DEFLATED) + + def testIterlinesDeflated(self): + for f in (TESTFN2, TemporaryFile(), StringIO()): + self.zipIterlinesTest(f, zipfile.ZIP_DEFLATED) + + def testLowCompression(self): + # Checks for cases where compressed data is larger than original + # Create the ZIP archive + zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_DEFLATED) + zipfp.writestr("strfile", '12') + zipfp.close() + + # Get an open object for strfile + zipfp = zipfile.ZipFile(TESTFN2, "r", zipfile.ZIP_DEFLATED) + openobj = zipfp.open("strfile") + self.assertEqual(openobj.read(1), '1') + self.assertEqual(openobj.read(1), '2') + def testAbsoluteArcnames(self): zipfp = zipfile.ZipFile(TESTFN2, "w", zipfile.ZIP_STORED) zipfp.write(TESTFN, "/absolute") @@ -110,7 +238,6 @@ self.assertEqual(zipfp.namelist(), ["absolute"]) zipfp.close() - def tearDown(self): os.remove(TESTFN) os.remove(TESTFN2) @@ -123,7 +250,7 @@ self._limit = zipfile.ZIP64_LIMIT zipfile.ZIP64_LIMIT = 5 - line_gen = ("Test of zipfile line %d." % i for i in range(0, 1000)) + line_gen = ("Test of zipfile line %d." % i for i in range(0, FIXEDTEST_SIZE)) self.data = '\n'.join(line_gen) # Make a source file with some lines @@ -344,6 +471,26 @@ except zipfile.BadZipfile: os.unlink(TESTFN) + def testIsZipErroneousFile(self): + # This test checks that the is_zipfile function correctly identifies + # a file that is not a zip file + fp = open(TESTFN, "w") + fp.write("this is not a legal zip file\n") + fp.close() + chk = zipfile.is_zipfile(TESTFN) + os.unlink(TESTFN) + self.assert_(chk is False) + + def testIsZipValidFile(self): + # This test checks that the is_zipfile function correctly identifies + # a file that is a zip file + zipf = zipfile.ZipFile(TESTFN, mode="w") + zipf.writestr("foo.txt", "O, for a Muse of Fire!") + zipf.close() + chk = zipfile.is_zipfile(TESTFN) + os.unlink(TESTFN) + self.assert_(chk is True) + def testNonExistentFileRaisesIOError(self): # make sure we don't raise an AttributeError when a partially-constructed # ZipFile instance is finalized; this tests for regression on SF tracker @@ -371,7 +518,6 @@ # and report that the first file in the archive was corrupt. self.assertRaises(RuntimeError, zipf.testzip) - class DecryptionTests(unittest.TestCase): # This test checks that ZIP decryption works. Since the library does not # support encryption at the moment, we use a pre-generated encrypted @@ -411,9 +557,255 @@ self.zip.setpassword("python") self.assertEquals(self.zip.read("test.txt"), self.plain) + +class TestsWithRandomBinaryFiles(unittest.TestCase): + def setUp(self): + datacount = randint(16, 64)*1024 + randint(1, 1024) + self.data = ''.join((struct.pack('= 0: + nllen = len(sep) + return nl, nllen + + return nl, nllen + + def readline(self, size = -1): + """Read a line with approx. size. If size is negative, + read a whole line. + """ + if size < 0: + size = sys.maxint + elif size == 0: + return '' + + # check for a newline already in buffer + nl, nllen = self._checkfornewline() + + if nl >= 0: + # the next line was already in the buffer + nl = min(nl, size) + else: + # no line break in buffer - try to read more + size -= len(self.linebuffer) + while nl < 0 and size > 0: + buf = self.read(min(size, 100)) + if not buf: + break + self.linebuffer += buf + size -= len(buf) + + # check for a newline in buffer + nl, nllen = self._checkfornewline() + + # we either ran out of bytes in the file, or + # met the specified size limit without finding a newline, + # so return current buffer + if nl < 0: + s = self.linebuffer + self.linebuffer = '' + return s + + buf = self.linebuffer[:nl] + self.lastdiscard = self.linebuffer[nl:nl + nllen] + self.linebuffer = self.linebuffer[nl + nllen:] + + # line is always returned with \n as newline char (except possibly + # for a final incomplete line in the file, which is handled above). + return buf + "\n" + + def readlines(self, sizehint = -1): + """Return a list with all (following) lines. The sizehint parameter + is ignored in this implementation. + """ + result = [] + while True: + line = self.readline() + if not line: break + result.append(line) + return result + + def read(self, size = None): + # act like file() obj and return empty string if size is 0 + if size == 0: + return '' + + # determine read size + bytesToRead = self.compress_size - self.bytes_read + + # adjust read size for encrypted files since the first 12 bytes + # are for the encryption/password information + if self.decrypter is not None: + bytesToRead -= 12 + + if size is not None and size >= 0: + if self.compress_type == ZIP_STORED: + lr = len(self.readbuffer) + bytesToRead = min(bytesToRead, size - lr) + elif self.compress_type == ZIP_DEFLATED: + if len(self.readbuffer) > size: + # the user has requested fewer bytes than we've already + # pulled through the decompressor; don't read any more + bytesToRead = 0 + else: + # user will use up the buffer, so read some more + lr = len(self.rawbuffer) + bytesToRead = min(bytesToRead, self.compreadsize - lr) + + # avoid reading past end of file contents + if bytesToRead + self.bytes_read > self.compress_size: + bytesToRead = self.compress_size - self.bytes_read + + # try to read from file (if necessary) + if bytesToRead > 0: + bytes = self.fileobj.read(bytesToRead) + self.bytes_read += len(bytes) + self.rawbuffer += bytes + + # handle contents of raw buffer + if self.rawbuffer: + newdata = self.rawbuffer + self.rawbuffer = '' + + # decrypt new data if we were given an object to handle that + if newdata and self.decrypter is not None: + newdata = ''.join(map(self.decrypter, newdata)) + + # decompress newly read data if necessary + if newdata and self.compress_type == ZIP_DEFLATED: + newdata = self.dc.decompress(newdata) + self.rawbuffer = self.dc.unconsumed_tail + if self.eof and len(self.rawbuffer) == 0: + # we're out of raw bytes (both from the file and + # the local buffer); flush just to make sure the + # decompressor is done + newdata += self.dc.flush() + # prevent decompressor from being used again + self.dc = None + + self.readbuffer += newdata + + + # return what the user asked for + if size is None or len(self.readbuffer) <= size: + bytes = self.readbuffer + self.readbuffer = '' + else: + bytes = self.readbuffer[:size] + self.readbuffer = self.readbuffer[size:] + + return bytes + + class ZipFile: """ Class with methods to open, read, write, close, list zip files. @@ -534,73 +728,75 @@ def read(self, name, pwd=None): """Return file bytes (as a string) for name.""" - if self.mode not in ("r", "a"): - raise RuntimeError, 'read() requires mode "r" or "a"' + return self.open(name, "r", pwd).read() + + def open(self, name, mode="r", pwd=None): + """Return file-like object for 'name'.""" + if mode not in ("r", "U", "rU"): + raise RuntimeError, 'open() requires mode "r", "U", or "rU"' if not self.fp: raise RuntimeError, \ "Attempt to read ZIP archive that was already closed" + + # Only open a new file for instances where we were not + # given a file object in the constructor + if self._filePassed: + zef_file = self.fp + else: + zef_file = open(self.filename, 'rb') + + # Get info object for name zinfo = self.getinfo(name) - is_encrypted = zinfo.flag_bits & 0x1 - if is_encrypted: - if not pwd: - pwd = self.pwd - if not pwd: - raise RuntimeError, "File %s is encrypted, " \ - "password required for extraction" % name - filepos = self.fp.tell() - self.fp.seek(zinfo.header_offset, 0) + filepos = zef_file.tell() + + zef_file.seek(zinfo.header_offset, 0) # Skip the file header: - fheader = self.fp.read(30) + fheader = zef_file.read(30) if fheader[0:4] != stringFileHeader: raise BadZipfile, "Bad magic number for file header" fheader = struct.unpack(structFileHeader, fheader) - fname = self.fp.read(fheader[_FH_FILENAME_LENGTH]) + fname = zef_file.read(fheader[_FH_FILENAME_LENGTH]) if fheader[_FH_EXTRA_FIELD_LENGTH]: - self.fp.read(fheader[_FH_EXTRA_FIELD_LENGTH]) + zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH]) if fname != zinfo.orig_filename: raise BadZipfile, \ 'File name in directory "%s" and header "%s" differ.' % ( zinfo.orig_filename, fname) - bytes = self.fp.read(zinfo.compress_size) - # Go with decryption + # check for encrypted flag & handle password + is_encrypted = zinfo.flag_bits & 0x1 + zd = None if is_encrypted: + if not pwd: + pwd = self.pwd + if not pwd: + raise RuntimeError, "File %s is encrypted, " \ + "password required for extraction" % name + zd = _ZipDecrypter(pwd) # The first 12 bytes in the cypher stream is an encryption header # used to strengthen the algorithm. The first 11 bytes are # completely random, while the 12th contains the MSB of the CRC, # and is used to check the correctness of the password. + bytes = zef_file.read(12) h = map(zd, bytes[0:12]) if ord(h[11]) != ((zinfo.CRC>>24)&255): raise RuntimeError, "Bad password for file %s" % name - bytes = "".join(map(zd, bytes[12:])) - # Go with decompression - self.fp.seek(filepos, 0) - if zinfo.compress_type == ZIP_STORED: - pass - elif zinfo.compress_type == ZIP_DEFLATED: - if not zlib: - raise RuntimeError, \ - "De-compression requires the (missing) zlib module" - # zlib compress/decompress code by Jeremy Hylton of CNRI - dc = zlib.decompressobj(-15) - bytes = dc.decompress(bytes) - # need to feed in unused pad byte so that zlib won't choke - ex = dc.decompress('Z') + dc.flush() - if ex: - bytes = bytes + ex - else: - raise BadZipfile, \ - "Unsupported compression method %d for file %s" % \ - (zinfo.compress_type, name) - crc = binascii.crc32(bytes) - if crc != zinfo.CRC: - raise BadZipfile, "Bad CRC-32 for file %s" % name - return bytes + + # build and return a ZipExtFile + if zd is None: + zef = ZipExtFile(zef_file, zinfo) + else: + zef = ZipExtFile(zef_file, zinfo, zd) + + # set universal newlines on ZipExtFile if necessary + if "U" in mode: + zef.set_univ_newlines(True) + return zef def _writecheck(self, zinfo): """Check for errors before writing a file to the archive.""" Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 11:41:24 2007 @@ -139,6 +139,8 @@ Library ------- +- Patch #1121142: Implement ZipFile.open. + - Taught setup.py how to locate Berkeley DB on Macs using MacPorts. - Added heapq.merge() for merging sorted input streams. From python-checkins at python.org Tue Mar 6 12:23:23 2007 From: python-checkins at python.org (eric.smith) Date: Tue, 6 Mar 2007 12:23:23 +0100 (CET) Subject: [Python-checkins] r54153 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070306112323.7CCBB1E400D@bag.python.org> Author: eric.smith Date: Tue Mar 6 12:23:22 2007 New Revision: 54153 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: At Patrick Maupin's suggestion, improved the logic for looking up default internal formatter if not type specifier is present. Added test cases for same. Removed bogus printf left over from debugging. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Tue Mar 6 12:23:22 2007 @@ -52,18 +52,7 @@ self.assertEquals(val, unicode(result.upper())) def formatRaises(self, exc, text, *args, **kwargs): - exc = exc or Exception #StringFormat.FormatError - text = str(text) - #prevState = StringFormat.strict_format_errors - #StringFormat.strict_format_errors = True - try: - self.assertRaises(exc, - lambda: pep3101.format( - text, *args, **kwargs)) - finally: - pass - #StringFormat.strict_format_errors = prevState - + self.assertRaises(exc, pep3101.format, text, *args, **kwargs) def test_basic(self): # directly from the pep intro @@ -286,7 +275,17 @@ def test_missing_type_specifier(self): # make sure floats use 'g', ints and longs 'd', and everything else 's' - pass + + self.formatEqualsWithUnicode("3.5", "{0}", 3.5) + self.formatEqualsWithUnicode("5e+99", "{0}", 0.5e100) + self.formatEqualsWithUnicode("5e-101", "{0}", 0.5e-100) + self.formatEqualsWithUnicode("0", "{0}", 0) + self.formatEqualsWithUnicode("1", "{0}", 1) + self.formatEqualsWithUnicode("-1", "{0}", -1) + self.formatEqualsWithUnicode("(1)", "{0:()}", -1) + self.formatEqualsWithUnicode("1" + "0" * 100, "{0}", 10**100) + self.formatEqualsWithUnicode("hello, world", "{0}", "hello, world") + self.formatEqualsWithUnicode(" hello, world", "{0:>20}", "hello, world") def test_custom_format(self): class Custom(object): @@ -306,6 +305,12 @@ self.formatRaises(ValueError, "{{ {{{0}}", True) self.formatRaises(ValueError, "{0}}", True) + def test_invalid_type_specifier(self): + self.formatRaises(ValueError, "{0::}", 0) + self.formatRaises(ValueError, "{0:&}", 0) + self.formatRaises(ValueError, "{0:k}", 0) + self.formatRaises(ValueError, "{0:4<10.20K}", 0) + def test_name_mapper(self): mydict = dict(foo=1, bar=2) dict2 = mydict, dict(foobar=3) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Tue Mar 6 12:23:22 2007 @@ -1511,7 +1511,7 @@ } /* use type instead of format->type, so that it can be overridden by - format_locale_number() */ + format_number() */ static int _format_float(CH_TYPE type, PyObject *fieldobj, FmtState *fs, const InternalFormatSpec *format, @@ -1535,10 +1535,8 @@ type = 'f'; x = PyFloat_AsDouble(fieldobj); - if (x == -1.0 && PyErr_Occurred()) { - printf("not a float\n"); + if (x == -1.0 && PyErr_Occurred()) return 0; - } if (type == '%') { type = 'f'; @@ -1616,8 +1614,8 @@ /* this code is really the same as format_exponent, except it calls PyOS_snprintf() instead of PyOS_ascii_formatd(). */ static int -format_locale_number(PyObject *fieldobj, FmtState *fs, - const InternalFormatSpec *format) +format_number(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) { return _format_float('f', fieldobj, fs, format, snprintf_double); } @@ -1662,32 +1660,52 @@ return ok; } -/* returns a pointer to our conversion function, or NULL if invalid */ +static int +format_bad_type_specifier(PyObject *fieldobj, FmtState *fs, + const InternalFormatSpec *format) +{ + SetError(fs, "Invalid conversion character"); + return 0; +} + +/* returns a pointer to our conversion function. also sets + format->type based on the type of fieldobj, if format->type was not + specified. if format->type is unknown, returns a pointer to the + psueod-conversion function format_bad_type_specifier() */ Py_LOCAL_INLINE(FormatFunction) -format_function(CH_TYPE c) +format_function(PyObject *fieldobj, InternalFormatSpec *format) { - switch (c) { - case 'b': return format_binary; /* base-2 */ - case 'c': return format_char; /* as character */ - case 'n': return format_locale_number; /* number in locale-specific + while (1) + switch (format->type) { + case 'b': return format_binary; /* base-2 */ + case 'c': return format_char; /* as character */ + case 'n': return format_number; /* number in locale-specific format */ - case 'd': /* decimal integer */ - case 'o': /* octal */ - case 'x': /* base 16 */ - case 'X': return format_integer; /* base 16 uppercase */ - case 'r': return format_repr; /* in repr() format */ - case 's': return format_string; /* convert using str() */ - case 'e': /* exponential notation */ - case 'E': /* exponential notation + case 'd': /* decimal integer */ + case 'o': /* octal */ + case 'x': /* base 16 */ + case 'X': return format_integer; /* base 16 uppercase */ + case 'r': return format_repr; /* in repr() format */ + case 's': return format_string; /* convert using str() */ + case 'e': /* exponential notation */ + case 'E': /* exponential notation with uppercase 'E' */ - case 'f': /* fixed-point */ - case 'F': /* fixed-point with uppercase */ - case 'g': /* general number notation */ - case 'G': /* general number notation + case 'f': /* fixed-point */ + case 'F': /* fixed-point with uppercase */ + case 'g': /* general number notation */ + case 'G': /* general number notation with uppercase 'E' */ - case '%': return format_float; /* as percentage */ - default: - return NULL; + case '%': return format_float; /* as percentage */ + case '\0': + /* if no type character was specified, look up the default + type character, based on the type of our object, then + loop around and execute the switch statement again */ + format->type = (PyInt_Check(fieldobj) || + PyLong_Check(fieldobj)) ? 'd' + : (PyFloat_Check(fieldobj)) ?'g' : 's'; + continue; + default: + return format_bad_type_specifier; } } @@ -1697,33 +1715,15 @@ static int internal_render(FmtState *fs, PyObject *fieldobj) { InternalFormatSpec format; - FormatFunction formatter; if (!parse_internal_render_format_spec(fs, &format)) { return 0; } - /* if no type character was specified, look up the default - type character, based on the type of our object */ - if (format.type == '\0') { - if (PyInt_Check(fieldobj) || PyLong_Check(fieldobj)) { - format.type = 'd'; - } else if (PyFloat_Check(fieldobj)) { - format.type = 'g'; - } else { - format.type = 's'; - } - } - - /* find the formatter function */ - formatter = format_function(format.type); - if (formatter == NULL) { - SetError(fs, "Invalid conversion character"); - return 0; - } - - /* do the formatting, writing into the output string */ - return formatter(fieldobj, fs, &format); + /* do the formatting, writing into the output string. if there's + * an error in format.type, this still works by calling + * format_bad_type_specifier() to set an error */ + return format_function(fieldobj, &format)(fieldobj, fs, &format); } static PyObject * From python-checkins at python.org Tue Mar 6 12:51:17 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 12:51:17 +0100 (CET) Subject: [Python-checkins] r54154 - python/trunk/Lib/test/test_slice.py Message-ID: <20070306115117.ECFC81E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 12:51:14 2007 New Revision: 54154 Modified: python/trunk/Lib/test/test_slice.py Log: A test case for the fix in #1674228. Modified: python/trunk/Lib/test/test_slice.py ============================================================================== --- python/trunk/Lib/test/test_slice.py (original) +++ python/trunk/Lib/test/test_slice.py Tue Mar 6 12:51:14 2007 @@ -92,6 +92,17 @@ self.assertRaises(OverflowError, slice(None).indices, 1L<<100) + def test_setslice_without_getslice(self): + tmp = [] + class X(object): + def __setslice__(self, i, j, k): + tmp.append((i, j, k)) + + x = X() + x[1:2] = 42 + self.assertEquals(tmp, [(1, 2, 42)]) + + def test_main(): test_support.run_unittest(SliceTest) From python-checkins at python.org Tue Mar 6 12:51:29 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 12:51:29 +0100 (CET) Subject: [Python-checkins] r54155 - python/branches/release25-maint/Lib/test/test_slice.py Message-ID: <20070306115129.814E41E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 12:51:27 2007 New Revision: 54155 Modified: python/branches/release25-maint/Lib/test/test_slice.py Log: A test case for the fix in #1674228. (backport from rev. 54154) Modified: python/branches/release25-maint/Lib/test/test_slice.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_slice.py (original) +++ python/branches/release25-maint/Lib/test/test_slice.py Tue Mar 6 12:51:27 2007 @@ -92,6 +92,17 @@ self.assertRaises(OverflowError, slice(None).indices, 1L<<100) + def test_setslice_without_getslice(self): + tmp = [] + class X(object): + def __setslice__(self, i, j, k): + tmp.append((i, j, k)) + + x = X() + x[1:2] = 42 + self.assertEquals(tmp, [(1, 2, 42)]) + + def test_main(): test_support.run_unittest(SliceTest) From python-checkins at python.org Tue Mar 6 12:52:26 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 12:52:26 +0100 (CET) Subject: [Python-checkins] r54156 - python/trunk/Lib/idlelib/MultiCall.py Message-ID: <20070306115226.6C09E1E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 12:52:24 2007 New Revision: 54156 Modified: python/trunk/Lib/idlelib/MultiCall.py Log: Patch #1672481: fix bug in idlelib.MultiCall. Modified: python/trunk/Lib/idlelib/MultiCall.py ============================================================================== --- python/trunk/Lib/idlelib/MultiCall.py (original) +++ python/trunk/Lib/idlelib/MultiCall.py Tue Mar 6 12:52:24 2007 @@ -349,6 +349,8 @@ triplets.append(triplet) def event_delete(self, virtual, *sequences): + if virtual not in self.__eventinfo: + return func, triplets = self.__eventinfo[virtual] for seq in sequences: triplet = _parse_sequence(seq) From python-checkins at python.org Tue Mar 6 12:52:34 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 12:52:34 +0100 (CET) Subject: [Python-checkins] r54157 - python/branches/release25-maint/Lib/idlelib/MultiCall.py Message-ID: <20070306115234.31F541E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 12:52:33 2007 New Revision: 54157 Modified: python/branches/release25-maint/Lib/idlelib/MultiCall.py Log: Patch #1672481: fix bug in idlelib.MultiCall. (backport from rev. 54156) Modified: python/branches/release25-maint/Lib/idlelib/MultiCall.py ============================================================================== --- python/branches/release25-maint/Lib/idlelib/MultiCall.py (original) +++ python/branches/release25-maint/Lib/idlelib/MultiCall.py Tue Mar 6 12:52:33 2007 @@ -349,6 +349,8 @@ triplets.append(triplet) def event_delete(self, virtual, *sequences): + if virtual not in self.__eventinfo: + return func, triplets = self.__eventinfo[virtual] for seq in sequences: triplet = _parse_sequence(seq) From python-checkins at python.org Tue Mar 6 13:16:54 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 13:16:54 +0100 (CET) Subject: [Python-checkins] r54158 - in python/branches/release25-maint: Misc/NEWS Python/pythonrun.c Message-ID: <20070306121654.36D691E400F@bag.python.org> Author: georg.brandl Date: Tue Mar 6 13:16:52 2007 New Revision: 54158 Modified: python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Python/pythonrun.c Log: Bug #1674503: close the file opened by execfile() in an error condition. (backport) Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Tue Mar 6 13:16:52 2007 @@ -12,6 +12,8 @@ Core and builtins ----------------- +- Bug #1674503: close the file opened by execfile() in an error condition. + - Patch #1674228: when assigning a slice (old-style), check for the sq_ass_slice instead of the sq_slice slot. Modified: python/branches/release25-maint/Python/pythonrun.c ============================================================================== --- python/branches/release25-maint/Python/pythonrun.c (original) +++ python/branches/release25-maint/Python/pythonrun.c Tue Mar 6 13:16:52 2007 @@ -1244,12 +1244,12 @@ mod = PyParser_ASTFromFile(fp, filename, start, 0, 0, flags, NULL, arena); + if (closeit) + fclose(fp); if (mod == NULL) { PyArena_Free(arena); return NULL; } - if (closeit) - fclose(fp); ret = run_mod(mod, filename, globals, locals, flags, arena); PyArena_Free(arena); return ret; From python-checkins at python.org Tue Mar 6 13:17:51 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 13:17:51 +0100 (CET) Subject: [Python-checkins] r54159 - in python/trunk: Misc/NEWS Python/pythonrun.c Message-ID: <20070306121751.4F5701E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 13:17:50 2007 New Revision: 54159 Modified: python/trunk/Misc/NEWS python/trunk/Python/pythonrun.c Log: Bug #1674503: close the file opened by execfile() in an error condition. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 13:17:50 2007 @@ -12,6 +12,8 @@ Core and builtins ----------------- +- Bug #1674503: close the file opened by execfile() in an error condition. + - Patch #1674228: when assigning a slice (old-style), check for the sq_ass_slice instead of the sq_slice slot. Modified: python/trunk/Python/pythonrun.c ============================================================================== --- python/trunk/Python/pythonrun.c (original) +++ python/trunk/Python/pythonrun.c Tue Mar 6 13:17:50 2007 @@ -1251,12 +1251,12 @@ mod = PyParser_ASTFromFile(fp, filename, start, 0, 0, flags, NULL, arena); + if (closeit) + fclose(fp); if (mod == NULL) { PyArena_Free(arena); return NULL; } - if (closeit) - fclose(fp); ret = run_mod(mod, filename, globals, locals, flags, arena); PyArena_Free(arena); return ret; From buildbot at python.org Tue Mar 6 13:31:23 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 12:31:23 +0000 Subject: [Python-checkins] buildbot warnings in PPC64 Debian trunk Message-ID: <20070306123123.884991E400D@bag.python.org> The Buildbot has detected a new failure of PPC64 Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/PPC64%2520Debian%2520trunk/builds/117 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 13:50:00 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 12:50:00 +0000 Subject: [Python-checkins] buildbot warnings in S-390 Debian trunk Message-ID: <20070306125000.EFA631E400D@bag.python.org> The Buildbot has detected a new failure of S-390 Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/S-390%2520Debian%2520trunk/builds/717 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 13:55:02 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 12:55:02 +0000 Subject: [Python-checkins] buildbot warnings in x86 mvlgcc trunk Message-ID: <20070306125502.7041D1E400E@bag.python.org> The Buildbot has detected a new failure of x86 mvlgcc trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520mvlgcc%2520trunk/builds/292 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 14:15:46 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 13:15:46 +0000 Subject: [Python-checkins] buildbot warnings in x86 gentoo 2.5 Message-ID: <20070306131546.8C8381E4018@bag.python.org> The Buildbot has detected a new failure of x86 gentoo 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%25202.5/builds/255 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/httplib.py", line 856, in endheaders self._send_output() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/httplib.py", line 728, in _send_output self.send(msg) File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/httplib.py", line 695, in send self.connect() File "/home/buildslave/python-trunk/2.5.norwitz-x86/build/Lib/httplib.py", line 1130, in connect sock.connect((self.host, self.port)) File "", line 1, in connect IOError: [Errno socket error] (110, 'Connection timed out') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 14:32:52 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 14:32:52 +0100 (CET) Subject: [Python-checkins] r54160 - python/trunk/Modules/_collectionsmodule.c Message-ID: <20070306133252.BDDEB1E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 14:32:52 2007 New Revision: 54160 Modified: python/trunk/Modules/_collectionsmodule.c Log: Fix another reincarnation of bug #1576657 in defaultdict. Modified: python/trunk/Modules/_collectionsmodule.c ============================================================================== --- python/trunk/Modules/_collectionsmodule.c (original) +++ python/trunk/Modules/_collectionsmodule.c Tue Mar 6 14:32:52 2007 @@ -1075,7 +1075,7 @@ PyDoc_STRVAR(defdict_missing_doc, "__missing__(key) # Called by __getitem__ for missing key; pseudo-code:\n\ - if self.default_factory is None: raise KeyError(key)\n\ + if self.default_factory is None: raise KeyError((key,))\n\ self[key] = value = self.default_factory()\n\ return value\n\ "); @@ -1087,7 +1087,11 @@ PyObject *value; if (factory == NULL || factory == Py_None) { /* XXX Call dict.__missing__(key) */ - PyErr_SetObject(PyExc_KeyError, key); + PyObject *tup; + tup = PyTuple_Pack(1, key); + if (!tup) return NULL; + PyErr_SetObject(PyExc_KeyError, tup); + Py_DECREF(tup); return NULL; } value = PyEval_CallObject(factory, NULL); From python-checkins at python.org Tue Mar 6 14:33:07 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 14:33:07 +0100 (CET) Subject: [Python-checkins] r54161 - python/branches/release25-maint/Modules/collectionsmodule.c Message-ID: <20070306133307.6C12A1E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 14:33:07 2007 New Revision: 54161 Modified: python/branches/release25-maint/Modules/collectionsmodule.c Log: Fix another reincarnation of bug #1576657 in defaultdict. (backport from rev. 54160) Modified: python/branches/release25-maint/Modules/collectionsmodule.c ============================================================================== --- python/branches/release25-maint/Modules/collectionsmodule.c (original) +++ python/branches/release25-maint/Modules/collectionsmodule.c Tue Mar 6 14:33:07 2007 @@ -1075,7 +1075,7 @@ PyDoc_STRVAR(defdict_missing_doc, "__missing__(key) # Called by __getitem__ for missing key; pseudo-code:\n\ - if self.default_factory is None: raise KeyError(key)\n\ + if self.default_factory is None: raise KeyError((key,))\n\ self[key] = value = self.default_factory()\n\ return value\n\ "); @@ -1087,7 +1087,11 @@ PyObject *value; if (factory == NULL || factory == Py_None) { /* XXX Call dict.__missing__(key) */ - PyErr_SetObject(PyExc_KeyError, key); + PyObject *tup; + tup = PyTuple_Pack(1, key); + if (!tup) return NULL; + PyErr_SetObject(PyExc_KeyError, tup); + Py_DECREF(tup); return NULL; } value = PyEval_CallObject(factory, NULL); From python-checkins at python.org Tue Mar 6 14:35:02 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 14:35:02 +0100 (CET) Subject: [Python-checkins] r54162 - python/trunk/Lib/test/test_defaultdict.py Message-ID: <20070306133502.6DD951E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 14:35:00 2007 New Revision: 54162 Modified: python/trunk/Lib/test/test_defaultdict.py Log: A test case for the defaultdict KeyError bug. Modified: python/trunk/Lib/test/test_defaultdict.py ============================================================================== --- python/trunk/Lib/test/test_defaultdict.py (original) +++ python/trunk/Lib/test/test_defaultdict.py Tue Mar 6 14:35:00 2007 @@ -132,6 +132,15 @@ self.assertEqual(d2.default_factory, list) self.assertEqual(d2, d1) + def test_keyerror_without_factory(self): + d1 = defaultdict() + try: + d1[(1,)] + except KeyError, err: + self.assertEqual(err.message, (1,)) + else: + self.fail("expected KeyError") + def test_main(): test_support.run_unittest(TestDefaultDict) From python-checkins at python.org Tue Mar 6 14:35:09 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 14:35:09 +0100 (CET) Subject: [Python-checkins] r54163 - python/branches/release25-maint/Lib/test/test_defaultdict.py Message-ID: <20070306133509.F3E151E4014@bag.python.org> Author: georg.brandl Date: Tue Mar 6 14:35:08 2007 New Revision: 54163 Modified: python/branches/release25-maint/Lib/test/test_defaultdict.py Log: A test case for the defaultdict KeyError bug. (backport from rev. 54162) Modified: python/branches/release25-maint/Lib/test/test_defaultdict.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_defaultdict.py (original) +++ python/branches/release25-maint/Lib/test/test_defaultdict.py Tue Mar 6 14:35:08 2007 @@ -132,6 +132,15 @@ self.assertEqual(d2.default_factory, list) self.assertEqual(d2, d1) + def test_keyerror_without_factory(self): + d1 = defaultdict() + try: + d1[(1,)] + except KeyError, err: + self.assertEqual(err.message, (1,)) + else: + self.fail("expected KeyError") + def test_main(): test_support.run_unittest(TestDefaultDict) From python-checkins at python.org Tue Mar 6 14:37:50 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 14:37:50 +0100 (CET) Subject: [Python-checkins] r54164 - in python/trunk: Doc/lib/libdoctest.tex Lib/doctest.py Misc/NEWS Message-ID: <20070306133750.C40061E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 14:37:45 2007 New Revision: 54164 Modified: python/trunk/Doc/lib/libdoctest.tex python/trunk/Lib/doctest.py python/trunk/Misc/NEWS Log: Patch #1663234: you can now run doctest on test files and modules using "python -m doctest [-v] filename ...". Modified: python/trunk/Doc/lib/libdoctest.tex ============================================================================== --- python/trunk/Doc/lib/libdoctest.tex (original) +++ python/trunk/Doc/lib/libdoctest.tex Tue Mar 6 14:37:45 2007 @@ -201,6 +201,19 @@ \code{sys.argv} is not examined by \function{testmod()} (so passing \programopt{-v} or not has no effect). +Since Python 2.6, there is also a command line shortcut for running +\function{testmod()}. You can instruct the Python interpreter to run +the doctest module directly from the standard library and pass the module +name(s) on the command line: + +\begin{verbatim} +python -m doctest -v example.py +\end{verbatim} + +This will import \file{example.py} as a standalone module and run +\function{testmod()} on it. Note that this may not work correctly if the +file is part of a package and imports other submodules from that package. + For more information on \function{testmod()}, see section~\ref{doctest-basic-api}. @@ -267,6 +280,18 @@ set with the \programopt{-v} command-line switch or with the optional keyword argument \var{verbose}. +Since Python 2.6, there is also a command line shortcut for running +\function{testfile()}. You can instruct the Python interpreter to run +the doctest module directly from the standard library and pass the file +name(s) on the command line: + +\begin{verbatim} +python -m doctest -v example.txt +\end{verbatim} + +Because the file name does not end with \file{.py}, \module{doctest} infers +that it must be run with \function{testfile()}, not \function{testmod()}. + For more information on \function{testfile()}, see section~\ref{doctest-basic-api}. Modified: python/trunk/Lib/doctest.py ============================================================================== --- python/trunk/Lib/doctest.py (original) +++ python/trunk/Lib/doctest.py Tue Mar 6 14:37:45 2007 @@ -2630,8 +2630,23 @@ } def _test(): - r = unittest.TextTestRunner() - r.run(DocTestSuite()) + testfiles = [arg for arg in sys.argv[1:] if arg and arg[0] != '-'] + if len(testfiles) > 0: + for filename in testfiles: + if filename.endswith(".py"): + # This is a module -- insert its dir into sys.path and try to + # import it. If it is part of a package, that possibly won't work + # because of package imports. + dirname, filename = os.path.split(filename) + sys.path.insert(0, dirname) + m = __import__(filename[:-3]) + del sys.path[0] + testmod(m) + else: + testfile(filename, module_relative=False) + else: + r = unittest.TextTestRunner() + r.run(DocTestSuite()) if __name__ == "__main__": _test() Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 14:37:45 2007 @@ -141,6 +141,9 @@ Library ------- +- Patch #1663234: you can now run doctest on test files and modules + using "python -m doctest [-v] filename ...". + - Patch #1121142: Implement ZipFile.open. - Taught setup.py how to locate Berkeley DB on Macs using MacPorts. From buildbot at python.org Tue Mar 6 15:29:36 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 14:29:36 +0000 Subject: [Python-checkins] buildbot warnings in x86 gentoo trunk Message-ID: <20070306142936.D41871E400E@bag.python.org> The Buildbot has detected a new failure of x86 gentoo trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%2520trunk/builds/1969 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: Traceback (most recent call last): File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/test/test_thread.py", line 281, in readerThread rec = dbutils.DeadlockWrap(c.next, max_retries=10) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/dbutils.py", line 62, in DeadlockWrap return function(*_args, **_kwargs) DBLockDeadlockError: (-30996, 'DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock') Traceback (most recent call last): File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/test/test_thread.py", line 281, in readerThread rec = dbutils.DeadlockWrap(c.next, max_retries=10) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/dbutils.py", line 62, in DeadlockWrap return function(*_args, **_kwargs) DBLockDeadlockError: (-30996, 'DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock') Traceback (most recent call last): File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/test/test_thread.py", line 281, in readerThread rec = dbutils.DeadlockWrap(c.next, max_retries=10) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/dbutils.py", line 62, in DeadlockWrap return function(*_args, **_kwargs) DBLockDeadlockError: (-30996, 'DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock') Traceback (most recent call last): File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/test/test_thread.py", line 281, in readerThread rec = dbutils.DeadlockWrap(c.next, max_retries=10) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/dbutils.py", line 62, in DeadlockWrap return function(*_args, **_kwargs) DBLockDeadlockError: (-30996, 'DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock') Traceback (most recent call last): File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/test/test_thread.py", line 281, in readerThread rec = dbutils.DeadlockWrap(c.next, max_retries=10) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/bsddb/dbutils.py", line 62, in DeadlockWrap return function(*_args, **_kwargs) DBLockDeadlockError: (-30996, 'DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock') 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 864, in endheaders self._send_output() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 736, in _send_output self.send(msg) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 695, in send self.connect() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 1152, in connect sock.connect((self.host, self.port)) File "", line 1, in connect IOError: [Errno socket error] (110, 'Connection timed out') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 15:33:34 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 14:33:34 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable trunk Message-ID: <20070306143334.674C11E400D@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%2520trunk/builds/120 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 15:43:01 2007 From: python-checkins at python.org (martin.v.loewis) Date: Tue, 6 Mar 2007 15:43:01 +0100 (CET) Subject: [Python-checkins] r54165 - in python/trunk: Doc/lib/libhtmlparser.tex Lib/HTMLParser.py Lib/test/test_htmlparser.py Misc/NEWS Message-ID: <20070306144301.A47BA1E400E@bag.python.org> Author: martin.v.loewis Date: Tue Mar 6 15:43:00 2007 New Revision: 54165 Modified: python/trunk/Doc/lib/libhtmlparser.tex python/trunk/Lib/HTMLParser.py python/trunk/Lib/test/test_htmlparser.py python/trunk/Misc/NEWS Log: Patch #912410: Replace HTML entity references for attribute values in HTMLParser. Modified: python/trunk/Doc/lib/libhtmlparser.tex ============================================================================== --- python/trunk/Doc/lib/libhtmlparser.tex (original) +++ python/trunk/Doc/lib/libhtmlparser.tex Tue Mar 6 15:43:00 2007 @@ -75,14 +75,18 @@ be overridden by a derived class; the base class implementation does nothing. -The \var{tag} argument is the name of the tag converted to -lower case. The \var{attrs} argument is a list of \code{(\var{name}, -\var{value})} pairs containing the attributes found inside the tag's -\code{<>} brackets. The \var{name} will be translated to lower case -and double quotes and backslashes in the \var{value} have been -interpreted. For instance, for the tag \code{}, this method would be called as +The \var{tag} argument is the name of the tag converted to lower case. +The \var{attrs} argument is a list of \code{(\var{name}, \var{value})} +pairs containing the attributes found inside the tag's \code{<>} +brackets. The \var{name} will be translated to lower case, and quotes +in the \var{value} have been removed, and character and entity +references have been replaced. For instance, for the tag \code{}, this method would be called as \samp{handle_starttag('a', [('href', 'http://www.cwi.nl/')])}. + +\versionchanged[All entity references from htmlentitydefs are now +replaced in the attribute values]{2.6} + \end{methoddesc} \begin{methoddesc}{handle_startendtag}{tag, attrs} Modified: python/trunk/Lib/HTMLParser.py ============================================================================== --- python/trunk/Lib/HTMLParser.py (original) +++ python/trunk/Lib/HTMLParser.py Tue Mar 6 15:43:00 2007 @@ -358,12 +358,30 @@ self.error("unknown declaration: %r" % (data,)) # Internal -- helper to remove special character quoting + entitydefs = None def unescape(self, s): if '&' not in s: return s - s = s.replace("<", "<") - s = s.replace(">", ">") - s = s.replace("'", "'") - s = s.replace(""", '"') - s = s.replace("&", "&") # Must be last - return s + def replaceEntities(s): + s = s.groups()[0] + if s[0] == "#": + s = s[1:] + if s[0] in ['x','X']: + c = int(s[1:], 16) + else: + c = int(s) + return unichr(c) + else: + # Cannot use name2codepoint directly, because HTMLParser supports apos, + # which is not part of HTML 4 + import htmlentitydefs + if HTMLParser.entitydefs is None: + entitydefs = HTMLParser.entitydefs = {'apos':u"'"} + for k, v in htmlentitydefs.name2codepoint.iteritems(): + entitydefs[k] = unichr(v) + try: + return self.entitydefs[s] + except KeyError: + return '&'+s+';' + + return re.sub(r"&(#?[xX]?(?:[0-9a-fA-F]+|\w{1,8}));", replaceEntities, s) Modified: python/trunk/Lib/test/test_htmlparser.py ============================================================================== --- python/trunk/Lib/test/test_htmlparser.py (original) +++ python/trunk/Lib/test/test_htmlparser.py Tue Mar 6 15:43:00 2007 @@ -309,6 +309,11 @@ ("endtag", "script"), ]) + def test_entityrefs_in_attributes(self): + self._run_check("", [ + ("starttag", "html", [("foo", u"\u20AC&aa&unsupported;")]) + ]) + def test_main(): test_support.run_unittest(HTMLParserTestCase) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 15:43:00 2007 @@ -141,6 +141,9 @@ Library ------- +- Patch #912410: Replace HTML entity references for attribute values + in HTMLParser. + - Patch #1663234: you can now run doctest on test files and modules using "python -m doctest [-v] filename ...". From python-checkins at python.org Tue Mar 6 16:41:43 2007 From: python-checkins at python.org (skip.montanaro) Date: Tue, 6 Mar 2007 16:41:43 +0100 (CET) Subject: [Python-checkins] r54166 - in python/trunk: Misc/NEWS setup.py Message-ID: <20070306154143.1B7091E4015@bag.python.org> Author: skip.montanaro Date: Tue Mar 6 16:41:38 2007 New Revision: 54166 Modified: python/trunk/Misc/NEWS python/trunk/setup.py Log: patch 1673619 - identify extension modules which cannot be built Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 16:41:38 2007 @@ -141,6 +141,9 @@ Library ------- +- Patch #1673619: setup.py identifies extension modules it doesn't know how + to build and those it knows how to build but that fail to build. + - Patch #912410: Replace HTML entity references for attribute values in HTMLParser. Modified: python/trunk/setup.py ============================================================================== --- python/trunk/setup.py (original) +++ python/trunk/setup.py Tue Mar 6 16:41:38 2007 @@ -91,10 +91,14 @@ class PyBuildExt(build_ext): + def __init__(self, dist): + build_ext.__init__(self, dist) + self.failed = [] + def build_extensions(self): # Detect which modules should be compiled - self.detect_modules() + missing = self.detect_modules() # Remove modules that are present on the disabled list self.extensions = [ext for ext in self.extensions @@ -178,6 +182,31 @@ build_ext.build_extensions(self) + longest = max([len(e.name) for e in self.extensions]) + if self.failed: + longest = max(longest, max([len(name) for name in self.failed])) + + def print_three_column(lst): + lst.sort(cmp=str.lower) + # guarantee zip() doesn't drop anything + while len(lst) % 3: + lst.append("") + for e, f, g in zip(lst[::3], lst[1::3], lst[2::3]): + print "%-*s %-*s %-*s" % (longest, e, longest, f, + longest, g) + print + + if missing: + print + print "Failed to find the necessary bits to build these modules:" + print_three_column(missing) + + if self.failed: + failed = self.failed[:] + print + print "Failed to build these modules:" + print_three_column(failed) + def build_extension(self, ext): if ext.name == '_ctypes': @@ -189,6 +218,7 @@ except (CCompilerError, DistutilsError), why: self.announce('WARNING: building of extension "%s" failed: %s' % (ext.name, sys.exc_info()[1])) + self.failed.append(ext.name) return # Workaround for Mac OS X: The Carbon-based modules cannot be # reliably imported into a command-line Python @@ -209,6 +239,7 @@ try: imp.load_dynamic(ext.name, ext_filename) except ImportError, why: + self.failed.append(ext.name) self.announce('*** WARNING: renaming "%s" since importing it' ' failed: %s' % (ext.name, why), level=3) assert not self.inplace @@ -234,6 +265,7 @@ self.announce('*** WARNING: importing extension "%s" ' 'failed with %s: %s' % (ext.name, exc_type, why), level=3) + self.failed.append(ext.name) def get_platform(self): # Get value of sys.platform @@ -299,6 +331,7 @@ ] inc_dirs = self.compiler.include_dirs + ['/usr/include'] exts = [] + missing = [] config_h = sysconfig.get_config_h_filename() config_h_vars = sysconfig.parse_config_h(open(config_h)) @@ -387,6 +420,8 @@ # static Unicode character database if have_unicode: exts.append( Extension('unicodedata', ['unicodedata.c']) ) + else: + missing.append('unicodedata') # access to ISO C locale support data = open('pyconfig.h').read() m = re.search(r"#s*define\s+WITH_LIBINTL\s+1\s*", data) @@ -419,6 +454,11 @@ if (config_h_vars.get('HAVE_GETSPNAM', False) or config_h_vars.get('HAVE_GETSPENT', False)): exts.append( Extension('spwd', ['spwdmodule.c']) ) + else: + missing.append('spwd') + else: + missing.extend(['pwd', 'grp', 'spwd']) + # select(2); not on ancient System V exts.append( Extension('select', ['selectmodule.c']) ) @@ -435,11 +475,15 @@ # Memory-mapped files (also works on Win32). if platform not in ['atheos', 'mac']: exts.append( Extension('mmap', ['mmapmodule.c']) ) + else: + missing.append('mmap') # Lance Ellinghaus's syslog module if platform not in ['mac']: # syslog daemon interface exts.append( Extension('syslog', ['syslogmodule.c']) ) + else: + missing.append('syslog') # George Neville-Neil's timing module: # Deprecated in PEP 4 http://www.python.org/peps/pep-0004.html @@ -466,6 +510,8 @@ exts.append( Extension('imageop', ['imageop.c']) ) # Read SGI RGB image files (but coded portably) exts.append( Extension('rgbimg', ['rgbimgmodule.c']) ) + else: + missing.extend(['imageop', 'rgbimg']) # readline do_readline = self.compiler.find_library_file(lib_dirs, 'readline') @@ -503,6 +549,9 @@ library_dirs=['/usr/lib/termcap'], extra_link_args=readline_extra_link_args, libraries=readline_libs) ) + else: + missing.append('readline') + if platform not in ['mac']: # crypt module. @@ -511,6 +560,8 @@ else: libs = [] exts.append( Extension('crypt', ['cryptmodule.c'], libraries=libs) ) + else: + missing.append('crypt') # CSV files exts.append( Extension('_csv', ['_csv.c']) ) @@ -543,6 +594,8 @@ library_dirs = ssl_libs, libraries = ['ssl', 'crypto'], depends = ['socketmodule.h']), ) + else: + missing.append('_ssl') # find out which version of OpenSSL we have openssl_ver = 0 @@ -576,6 +629,7 @@ include_dirs = ssl_incs, library_dirs = ssl_libs, libraries = ['ssl', 'crypto']) ) + missing.extend(['_sha', '_md5']) else: # The _sha module implements the SHA1 hash algorithm. exts.append( Extension('_sha', ['shamodule.c']) ) @@ -585,12 +639,14 @@ exts.append( Extension('_md5', sources = ['md5module.c', 'md5.c'], depends = ['md5.h']) ) + missing.append('_hashlib') 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']) ) - + else: + missing.extend(['_sha256', '_sha512']) # Modules that provide persistent dictionary-like semantics. You will # probably want to arrange for at least one of them to be available on @@ -743,6 +799,7 @@ db_incs = None dblibs = [] dblib_dir = None + missing.append('_bsddb') # The sqlite interface sqlite_setup_debug = False # verbose debug prints from this script? @@ -835,6 +892,8 @@ runtime_library_dirs=sqlite_libdir, extra_link_args=sqlite_extra_link_args, libraries=["sqlite3",])) + else: + missing.append('_sqlite3') # Look for Berkeley db 1.85. Note that it is built as a different # module name so it can be included even when later versions are @@ -857,6 +916,10 @@ libraries=libraries)) else: exts.append(Extension('bsddb185', ['bsddbmodule.c'])) + else: + missing.append('bsddb185') + else: + missing.append('bsddb185') # The standard Unix dbm module: if platform not in ['cygwin']: @@ -882,11 +945,15 @@ define_macros=[('HAVE_BERKDB_H',None), ('DB_DBM_HSEARCH',None)], libraries=dblibs)) + else: + missing.append('dbm') # Anthony Baxter's gdbm module. GNU dbm(3) will require -lgdbm: if (self.compiler.find_library_file(lib_dirs, 'gdbm')): exts.append( Extension('gdbm', ['gdbmmodule.c'], libraries = ['gdbm'] ) ) + else: + missing.append('gdbm') # Unix-only modules if platform not in ['mac', 'win32']: @@ -895,6 +962,8 @@ # Jeremy Hylton's rlimit interface if platform not in ['atheos']: exts.append( Extension('resource', ['resource.c']) ) + else: + missing.append('resource') # Sun yellow pages. Some systems have the functions in libc. if platform not in ['cygwin', 'atheos']: @@ -904,6 +973,10 @@ libs = [] exts.append( Extension('nis', ['nismodule.c'], libraries = libs) ) + else: + missing.append('nis') + else: + missing.extend(['nis', 'resource', 'termios']) # Curses support, requiring the System V version of curses, often # provided by the ncurses library. @@ -932,13 +1005,16 @@ exts.append( Extension('_curses', ['_cursesmodule.c'], libraries = curses_libs) ) + else: + missing.append('_curses') # If the curses module is enabled, check for the panel module if (module_enabled(exts, '_curses') and self.compiler.find_library_file(lib_dirs, panel_library)): exts.append( Extension('_curses_panel', ['_curses_panel.c'], libraries = [panel_library] + curses_libs) ) - + else: + missing.append('_curses_panel') # Andrew Kuchling's zlib module. Note that some versions of zlib # 1.1.3 have security problems. See CERT Advisory CA-2002-07: @@ -974,6 +1050,12 @@ exts.append( Extension('zlib', ['zlibmodule.c'], libraries = ['z'], extra_link_args = zlib_extra_link_args)) + else: + missing.append('zlib') + else: + missing.append('zlib') + else: + missing.append('zlib') # Gustavo Niemeyer's bz2 module. if (self.compiler.find_library_file(lib_dirs, 'bz2')): @@ -984,6 +1066,8 @@ exts.append( Extension('bz2', ['bz2module.c'], libraries = ['bz2'], extra_link_args = bz2_extra_link_args) ) + else: + missing.append('bz2') # Interface to the Expat XML parser # @@ -1021,14 +1105,20 @@ include_dirs = [expatinc], sources = ['_elementtree.c'], )) + else: + missing.append('_elementtree') # Hye-Shik Chang's CJKCodecs modules. if have_unicode: exts.append(Extension('_multibytecodec', ['cjkcodecs/multibytecodec.c'])) for loc in ('kr', 'jp', 'cn', 'tw', 'hk', 'iso2022'): - exts.append(Extension('_codecs_' + loc, + exts.append(Extension('_codecs_%s' % loc, ['cjkcodecs/_codecs_%s.c' % loc])) + else: + missing.append('_multibytecodec') + for loc in ('kr', 'jp', 'cn', 'tw', 'hk', 'iso2022'): + missing.append('_codecs_%s' % loc) # Dynamic loading module if sys.maxint == 0x7fffffff: @@ -1036,6 +1126,10 @@ dl_inc = find_file('dlfcn.h', [], inc_dirs) if (dl_inc is not None) and (platform not in ['atheos']): exts.append( Extension('dl', ['dlmodule.c']) ) + else: + missing.append('dl') + else: + missing.append('dl') # Thomas Heller's _ctypes module self.detect_ctypes(inc_dirs, lib_dirs) @@ -1044,14 +1138,20 @@ if platform == 'linux2': # Linux-specific modules exts.append( Extension('linuxaudiodev', ['linuxaudiodev.c']) ) + else: + missing.append('linuxaudiodev') if platform in ('linux2', 'freebsd4', 'freebsd5', 'freebsd6', 'freebsd7'): exts.append( Extension('ossaudiodev', ['ossaudiodev.c']) ) + else: + missing.append('ossaudiodev') if platform == 'sunos5': # SunOS specific modules exts.append( Extension('sunaudiodev', ['sunaudiodev.c']) ) + else: + missing.append('sunaudiodev') if platform == 'darwin' and ("--disable-toolbox-glue" not in sysconfig.get_config_var("CONFIG_ARGS")): @@ -1140,6 +1240,11 @@ # Call the method for detecting whether _tkinter can be compiled self.detect_tkinter(inc_dirs, lib_dirs) + if '_tkinter' not in [e.name for e in self.extensions]: + missing.append('_tkinter') + + return missing + def detect_tkinter_darwin(self, inc_dirs, lib_dirs): # The _tkinter module, using frameworks. Since frameworks are quite # different the UNIX search logic is not sharable. From buildbot at python.org Tue Mar 6 16:47:46 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 15:47:46 +0000 Subject: [Python-checkins] buildbot failure in ppc Debian unstable trunk Message-ID: <20070306154747.132021E400D@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%2520trunk/builds/122 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 16:48:34 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 15:48:34 +0000 Subject: [Python-checkins] buildbot failure in x86 gentoo trunk Message-ID: <20070306154834.6CD1B1E400D@bag.python.org> The Buildbot has detected a new failure of x86 gentoo trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%2520trunk/builds/1971 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 16:48:42 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 15:48:42 +0000 Subject: [Python-checkins] buildbot failure in x86 mvlgcc trunk Message-ID: <20070306154842.7D5281E400E@bag.python.org> The Buildbot has detected a new failure of x86 mvlgcc trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520mvlgcc%2520trunk/builds/295 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 16:49:01 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 15:49:01 +0000 Subject: [Python-checkins] buildbot failure in PPC64 Debian trunk Message-ID: <20070306154901.DDDCB1E400F@bag.python.org> The Buildbot has detected a new failure of PPC64 Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/PPC64%2520Debian%2520trunk/builds/121 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 16:50:05 2007 From: python-checkins at python.org (guido.van.rossum) Date: Tue, 6 Mar 2007 16:50:05 +0100 (CET) Subject: [Python-checkins] r54167 - in python/trunk: Lib/test/test_datetime.py Misc/NEWS Modules/datetimemodule.c Message-ID: <20070306155005.33C821E4012@bag.python.org> Author: guido.van.rossum Date: Tue Mar 6 16:50:01 2007 New Revision: 54167 Modified: python/trunk/Lib/test/test_datetime.py python/trunk/Misc/NEWS python/trunk/Modules/datetimemodule.c Log: Patch #1646728: datetime.fromtimestamp fails with negative fractional times. With unittest. Somebody please backport to 2.5. Modified: python/trunk/Lib/test/test_datetime.py ============================================================================== --- python/trunk/Lib/test/test_datetime.py (original) +++ python/trunk/Lib/test/test_datetime.py Tue Mar 6 16:50:01 2007 @@ -1425,6 +1425,15 @@ self.assertRaises(ValueError, self.theclass.utcfromtimestamp, insane) + def test_negative_float_fromtimestamp(self): + # The result is tz-dependent; at least test that this doesn't + # fail (like it did before bug 1646728 was fixed). + self.theclass.fromtimestamp(-1.05) + + def test_negative_float_utcfromtimestamp(self): + d = self.theclass.utcfromtimestamp(-1.05) + self.assertEquals(d, self.theclass(1969, 12, 31, 23, 59, 58, 950000)) + def test_utcnow(self): import time Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 16:50:01 2007 @@ -404,6 +404,9 @@ Extension Modules ----------------- +- Patch #1646728: datetime.fromtimestamp fails with negative + fractional times. With unittest. + - Patch #1490190: posixmodule now includes os.chflags() and os.lchflags() functions on platforms where the underlying system calls are available. Modified: python/trunk/Modules/datetimemodule.c ============================================================================== --- python/trunk/Modules/datetimemodule.c (original) +++ python/trunk/Modules/datetimemodule.c Tue Mar 6 16:50:01 2007 @@ -3683,6 +3683,12 @@ return NULL; fraction = timestamp - (double)timet; us = (int)round_to_long(fraction * 1e6); + if (us < 0) { + /* Truncation towards zero is not what we wanted + for negative numbers (Python's mod semantics) */ + timet -= 1; + us += 1000000; + } /* If timestamp is less than one microsecond smaller than a * full second, round up. Otherwise, ValueErrors are raised * for some floats. */ From buildbot at python.org Tue Mar 6 16:53:33 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 15:53:33 +0000 Subject: [Python-checkins] buildbot failure in alpha Tru64 5.1 trunk Message-ID: <20070306155333.55E8B1E400D@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%2520trunk/builds/1458 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 17:24:13 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 16:24:13 +0000 Subject: [Python-checkins] buildbot failure in S-390 Debian trunk Message-ID: <20070306162413.C86791E400E@bag.python.org> The Buildbot has detected a new failure of S-390 Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/S-390%2520Debian%2520trunk/builds/720 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: guido.van.rossum,martin.v.loewis,skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 17:24:13 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 16:24:13 +0000 Subject: [Python-checkins] buildbot failure in ia64 Ubuntu trunk trunk Message-ID: <20070306162413.C642C1E400D@bag.python.org> The Buildbot has detected a new failure of ia64 Ubuntu trunk trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ia64%2520Ubuntu%2520trunk%2520trunk/builds/429 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: guido.van.rossum,skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 17:25:37 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 16:25:37 +0000 Subject: [Python-checkins] buildbot failure in sparc solaris10 gcc trunk Message-ID: <20070306162537.7FDAB1E4011@bag.python.org> The Buildbot has detected a new failure of sparc solaris10 gcc trunk. Full details are available at: http://www.python.org/dev/buildbot/all/sparc%2520solaris10%2520gcc%2520trunk/builds/1811 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: guido.van.rossum,skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 17:45:13 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 16:45:13 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070306164513.D8E691E4017@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/242 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: guido.van.rossum,skip.montanaro Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_datetime ====================================================================== ERROR: test_negative_float_fromtimestamp (test.test_datetime.TestDateTime) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_datetime.py", line 1431, in test_negative_float_fromtimestamp self.theclass.fromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function ====================================================================== ERROR: test_negative_float_utcfromtimestamp (test.test_datetime.TestDateTime) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_datetime.py", line 1434, in test_negative_float_utcfromtimestamp d = self.theclass.utcfromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function ====================================================================== ERROR: test_negative_float_fromtimestamp (test.test_datetime.TestDateTimeTZ) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_datetime.py", line 1431, in test_negative_float_fromtimestamp self.theclass.fromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function ====================================================================== ERROR: test_negative_float_utcfromtimestamp (test.test_datetime.TestDateTimeTZ) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_datetime.py", line 1434, in test_negative_float_utcfromtimestamp d = self.theclass.utcfromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 17:49:31 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 16:49:31 +0000 Subject: [Python-checkins] buildbot failure in g4 osx.4 trunk Message-ID: <20070306164932.015191E400D@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%2520trunk/builds/1792 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: guido.van.rossum,skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 18:43:50 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 17:43:50 +0000 Subject: [Python-checkins] buildbot failure in hppa Ubuntu dapper trunk Message-ID: <20070306174350.AFDCE1E400D@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/83 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl,guido.van.rossum,martin.v.loewis,skip.montanaro BUILD FAILED: failed compile sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 18:46:24 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 18:46:24 +0100 (CET) Subject: [Python-checkins] r54168 - in python/branches/release25-maint: Lib/test/test_datetime.py Misc/NEWS Modules/datetimemodule.c Message-ID: <20070306174624.B099F1E4016@bag.python.org> Author: georg.brandl Date: Tue Mar 6 18:46:17 2007 New Revision: 54168 Modified: python/branches/release25-maint/Lib/test/test_datetime.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Modules/datetimemodule.c Log: Patch #1646728: datetime.fromtimestamp fails with negative fractional times. With unittest. (backport from rev. 54167 by Guido) Modified: python/branches/release25-maint/Lib/test/test_datetime.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_datetime.py (original) +++ python/branches/release25-maint/Lib/test/test_datetime.py Tue Mar 6 18:46:17 2007 @@ -1425,6 +1425,15 @@ self.assertRaises(ValueError, self.theclass.utcfromtimestamp, insane) + def test_negative_float_fromtimestamp(self): + # The result is tz-dependent; at least test that this doesn't + # fail (like it did before bug 1646728 was fixed). + self.theclass.fromtimestamp(-1.05) + + def test_negative_float_utcfromtimestamp(self): + d = self.theclass.utcfromtimestamp(-1.05) + self.assertEquals(d, self.theclass(1969, 12, 31, 23, 59, 58, 950000)) + def test_utcnow(self): import time Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Tue Mar 6 18:46:17 2007 @@ -118,6 +118,9 @@ Extension Modules ----------------- +- Patch #1646728: datetime.fromtimestamp fails with negative + fractional times. With unittest. + - Patch #1494140: Add documentation for the new struct.Struct object. - Patch #1657276: Make NETLINK_DNRTMSG conditional. Modified: python/branches/release25-maint/Modules/datetimemodule.c ============================================================================== --- python/branches/release25-maint/Modules/datetimemodule.c (original) +++ python/branches/release25-maint/Modules/datetimemodule.c Tue Mar 6 18:46:17 2007 @@ -3686,6 +3686,12 @@ return NULL; fraction = timestamp - (double)timet; us = (int)round_to_long(fraction * 1e6); + if (us < 0) { + /* Truncation towards zero is not what we wanted + for negative numbers (Python's mod semantics) */ + timet -= 1; + us += 1000000; + } /* If timestamp is less than one microsecond smaller than a * full second, round up. Otherwise, ValueErrors are raised * for some floats. */ From python-checkins at python.org Tue Mar 6 18:49:15 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 18:49:15 +0100 (CET) Subject: [Python-checkins] r54169 - python/trunk/setup.py Message-ID: <20070306174915.0D0C61E4010@bag.python.org> Author: georg.brandl Date: Tue Mar 6 18:49:14 2007 New Revision: 54169 Modified: python/trunk/setup.py Log: Fix cmp vs. key argument for list.sort. Modified: python/trunk/setup.py ============================================================================== --- python/trunk/setup.py (original) +++ python/trunk/setup.py Tue Mar 6 18:49:14 2007 @@ -187,7 +187,7 @@ longest = max(longest, max([len(name) for name in self.failed])) def print_three_column(lst): - lst.sort(cmp=str.lower) + lst.sort(key=str.lower) # guarantee zip() doesn't drop anything while len(lst) % 3: lst.append("") From python-checkins at python.org Tue Mar 6 19:21:33 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 19:21:33 +0100 (CET) Subject: [Python-checkins] r54170 - python/trunk/Lib/doctest.py Message-ID: <20070306182133.B9FF11E4017@bag.python.org> Author: georg.brandl Date: Tue Mar 6 19:21:32 2007 New Revision: 54170 Modified: python/trunk/Lib/doctest.py Log: Small nit, found by Neal. Modified: python/trunk/Lib/doctest.py ============================================================================== --- python/trunk/Lib/doctest.py (original) +++ python/trunk/Lib/doctest.py Tue Mar 6 19:21:32 2007 @@ -2631,10 +2631,10 @@ def _test(): testfiles = [arg for arg in sys.argv[1:] if arg and arg[0] != '-'] - if len(testfiles) > 0: + if testfiles: for filename in testfiles: if filename.endswith(".py"): - # This is a module -- insert its dir into sys.path and try to + # It is a module -- insert its dir into sys.path and try to # import it. If it is part of a package, that possibly won't work # because of package imports. dirname, filename = os.path.split(filename) From python-checkins at python.org Tue Mar 6 19:30:02 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 19:30:02 +0100 (CET) Subject: [Python-checkins] r54171 - python/trunk/Doc/ref/ref3.tex Message-ID: <20070306183002.BFCDA1E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 19:29:58 2007 New Revision: 54171 Modified: python/trunk/Doc/ref/ref3.tex Log: Patch #1602128: clarify that richcmp methods can return NotImplemented and should return True or False otherwise. Modified: python/trunk/Doc/ref/ref3.tex ============================================================================== --- python/trunk/Doc/ref/ref3.tex (original) +++ python/trunk/Doc/ref/ref3.tex Tue Mar 6 19:29:58 2007 @@ -1282,10 +1282,14 @@ \code{\var{x}.__ne__(\var{y})}, \code{\var{x}>\var{y}} calls \code{\var{x}.__gt__(\var{y})}, and \code{\var{x}>=\var{y}} calls \code{\var{x}.__ge__(\var{y})}. -These methods can return any value, but if the comparison operator is -used in a Boolean context, the return value should be interpretable as -a Boolean value, else a \exception{TypeError} will be raised. -By convention, \code{False} is used for false and \code{True} for true. + +A rich comparison method may return the singleton \code{NotImplemented} if it +does not implement the operation for a given pair of arguments. +By convention, \code{False} and \code{True} are returned for a successful +comparison. However, these methods can return any value, so if the +comparison operator is used in a Boolean context (e.g., in the condition +of an \code{if} statement), Python will call \function{bool()} on the +value to determine if the result is true or false. There are no implied relationships among the comparison operators. The truth of \code{\var{x}==\var{y}} does not imply that \code{\var{x}!=\var{y}} @@ -1299,9 +1303,7 @@ \method{__ge__()} are each other's reflection, and \method{__eq__()} and \method{__ne__()} are their own reflection. -Arguments to rich comparison methods are never coerced. A rich -comparison method may return \code{NotImplemented} if it does not -implement the operation for a given pair of arguments. +Arguments to rich comparison methods are never coerced. \end{methoddesc} \begin{methoddesc}[object]{__cmp__}{self, other} From python-checkins at python.org Tue Mar 6 19:30:15 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 19:30:15 +0100 (CET) Subject: [Python-checkins] r54172 - python/branches/release25-maint/Doc/ref/ref3.tex Message-ID: <20070306183015.7538A1E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 19:30:12 2007 New Revision: 54172 Modified: python/branches/release25-maint/Doc/ref/ref3.tex Log: Patch #1602128: clarify that richcmp methods can return NotImplemented and should return True or False otherwise. (backport from rev. 54171) Modified: python/branches/release25-maint/Doc/ref/ref3.tex ============================================================================== --- python/branches/release25-maint/Doc/ref/ref3.tex (original) +++ python/branches/release25-maint/Doc/ref/ref3.tex Tue Mar 6 19:30:12 2007 @@ -1282,10 +1282,14 @@ \code{\var{x}.__ne__(\var{y})}, \code{\var{x}>\var{y}} calls \code{\var{x}.__gt__(\var{y})}, and \code{\var{x}>=\var{y}} calls \code{\var{x}.__ge__(\var{y})}. -These methods can return any value, but if the comparison operator is -used in a Boolean context, the return value should be interpretable as -a Boolean value, else a \exception{TypeError} will be raised. -By convention, \code{False} is used for false and \code{True} for true. + +A rich comparison method may return the singleton \code{NotImplemented} if it +does not implement the operation for a given pair of arguments. +By convention, \code{False} and \code{True} are returned for a successful +comparison. However, these methods can return any value, so if the +comparison operator is used in a Boolean context (e.g., in the condition +of an \code{if} statement), Python will call \function{bool()} on the +value to determine if the result is true or false. There are no implied relationships among the comparison operators. The truth of \code{\var{x}==\var{y}} does not imply that \code{\var{x}!=\var{y}} @@ -1299,9 +1303,7 @@ \method{__ge__()} are each other's reflection, and \method{__eq__()} and \method{__ne__()} are their own reflection. -Arguments to rich comparison methods are never coerced. A rich -comparison method may return \code{NotImplemented} if it does not -implement the operation for a given pair of arguments. +Arguments to rich comparison methods are never coerced. \end{methoddesc} \begin{methoddesc}[object]{__cmp__}{self, other} From python-checkins at python.org Tue Mar 6 19:41:22 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 19:41:22 +0100 (CET) Subject: [Python-checkins] r54173 - in python/trunk: Lib/test/test_builtin.py Misc/NEWS Objects/longobject.c Message-ID: <20070306184122.28C411E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 19:41:12 2007 New Revision: 54173 Modified: python/trunk/Lib/test/test_builtin.py python/trunk/Misc/NEWS python/trunk/Objects/longobject.c Log: Patch #1638879: don't accept strings with embedded NUL bytes in long(). Modified: python/trunk/Lib/test/test_builtin.py ============================================================================== --- python/trunk/Lib/test/test_builtin.py (original) +++ python/trunk/Lib/test/test_builtin.py Tue Mar 6 19:41:12 2007 @@ -1017,6 +1017,11 @@ self.assertRaises(ValueError, long, '53', 40) self.assertRaises(TypeError, long, 1, 12) + # SF patch #1638879: embedded NULs were not detected with + # explicit base + self.assertRaises(ValueError, long, '123\0', 10) + self.assertRaises(ValueError, long, '123\x00 245', 20) + self.assertEqual(long('100000000000000000000000000000000', 2), 4294967296) self.assertEqual(long('102002022201221111211', 3), 4294967296) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 19:41:12 2007 @@ -12,6 +12,8 @@ Core and builtins ----------------- +- Patch #1638879: don't accept strings with embedded NUL bytes in long(). + - Bug #1674503: close the file opened by execfile() in an error condition. - Patch #1674228: when assigning a slice (old-style), check for the Modified: python/trunk/Objects/longobject.c ============================================================================== --- python/trunk/Objects/longobject.c (original) +++ python/trunk/Objects/longobject.c Tue Mar 6 19:41:12 2007 @@ -3287,8 +3287,25 @@ return PyLong_FromLong(0L); if (base == -909) return PyNumber_Long(x); - else if (PyString_Check(x)) + else if (PyString_Check(x)) { + /* Since PyLong_FromString doesn't have a length parameter, + * check here for possible NULs in the string. */ + char *string = PyString_AS_STRING(x); + if (strlen(string) != PyString_Size(x)) { + /* create a repr() of the input string, + * just like PyLong_FromString does. */ + PyObject *srepr; + srepr = PyObject_Repr(x); + if (srepr == NULL) + return NULL; + PyErr_Format(PyExc_ValueError, + "invalid literal for long() with base %d: %s", + base, PyString_AS_STRING(srepr)); + Py_DECREF(srepr); + return NULL; + } return PyLong_FromString(PyString_AS_STRING(x), NULL, base); + } #ifdef Py_USING_UNICODE else if (PyUnicode_Check(x)) return PyLong_FromUnicode(PyUnicode_AS_UNICODE(x), From python-checkins at python.org Tue Mar 6 19:44:45 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 19:44:45 +0100 (CET) Subject: [Python-checkins] r54174 - in python/branches/release25-maint: Lib/test/test_builtin.py Misc/NEWS Objects/longobject.c Message-ID: <20070306184445.E57241E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 19:44:35 2007 New Revision: 54174 Modified: python/branches/release25-maint/Lib/test/test_builtin.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Objects/longobject.c Log: Patch #1638879: don't accept strings with embedded NUL bytes in long(). (backport from rev. 54173) Modified: python/branches/release25-maint/Lib/test/test_builtin.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_builtin.py (original) +++ python/branches/release25-maint/Lib/test/test_builtin.py Tue Mar 6 19:44:35 2007 @@ -1017,6 +1017,11 @@ self.assertRaises(ValueError, long, '53', 40) self.assertRaises(TypeError, long, 1, 12) + # SF patch #1638879: embedded NULs were not detected with + # explicit base + self.assertRaises(ValueError, long, '123\0', 10) + self.assertRaises(ValueError, long, '123\x00 245', 20) + self.assertEqual(long('100000000000000000000000000000000', 2), 4294967296) self.assertEqual(long('102002022201221111211', 3), 4294967296) Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Tue Mar 6 19:44:35 2007 @@ -12,6 +12,8 @@ Core and builtins ----------------- +- Patch #1638879: don't accept strings with embedded NUL bytes in long(). + - Bug #1674503: close the file opened by execfile() in an error condition. - Patch #1674228: when assigning a slice (old-style), check for the Modified: python/branches/release25-maint/Objects/longobject.c ============================================================================== --- python/branches/release25-maint/Objects/longobject.c (original) +++ python/branches/release25-maint/Objects/longobject.c Tue Mar 6 19:44:35 2007 @@ -3287,8 +3287,25 @@ return PyLong_FromLong(0L); if (base == -909) return PyNumber_Long(x); - else if (PyString_Check(x)) + else if (PyString_Check(x)) { + /* Since PyLong_FromString doesn't have a length parameter, + * check here for possible NULs in the string. */ + char *string = PyString_AS_STRING(x); + if (strlen(string) != PyString_Size(x)) { + /* create a repr() of the input string, + * just like PyLong_FromString does. */ + PyObject *srepr; + srepr = PyObject_Repr(x); + if (srepr == NULL) + return NULL; + PyErr_Format(PyExc_ValueError, + "invalid literal for long() with base %d: %s", + base, PyString_AS_STRING(srepr)); + Py_DECREF(srepr); + return NULL; + } return PyLong_FromString(PyString_AS_STRING(x), NULL, base); + } #ifdef Py_USING_UNICODE else if (PyUnicode_Check(x)) return PyLong_FromUnicode(PyUnicode_AS_UNICODE(x), From python-checkins at python.org Tue Mar 6 19:47:36 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 19:47:36 +0100 (CET) Subject: [Python-checkins] r54175 - python/trunk/README Message-ID: <20070306184736.E071B1E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 19:47:31 2007 New Revision: 54175 Modified: python/trunk/README Log: Patch #1673121: update README wrt. OSX default shell. Modified: python/trunk/README ============================================================================== --- python/trunk/README (original) +++ python/trunk/README Tue Mar 6 19:47:31 2007 @@ -570,9 +570,9 @@ MacOSX: The tests will crash on both 10.1 and 10.2 with SEGV in test_re and test_sre due to the small default stack size. If you set the stack size to 2048 before doing a "make test" the - failure can be avoided. If you're using the tcsh (the default - on OSX), or csh shells use "limit stacksize 2048" and for the - bash shell, use "ulimit -s 2048". + failure can be avoided. If you're using the tcsh or csh shells, + use "limit stacksize 2048" and for the bash shell (the default + as of OSX 10.3), use "ulimit -s 2048". On naked Darwin you may want to add the configure option "--disable-toolbox-glue" to disable the glue code for the Carbon From python-checkins at python.org Tue Mar 6 19:47:42 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 19:47:42 +0100 (CET) Subject: [Python-checkins] r54176 - python/branches/release25-maint/README Message-ID: <20070306184742.0C8CB1E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 19:47:40 2007 New Revision: 54176 Modified: python/branches/release25-maint/README Log: Patch #1673121: update README wrt. OSX default shell. (backport from rev. 54175) Modified: python/branches/release25-maint/README ============================================================================== --- python/branches/release25-maint/README (original) +++ python/branches/release25-maint/README Tue Mar 6 19:47:40 2007 @@ -583,9 +583,9 @@ MacOSX: The tests will crash on both 10.1 and 10.2 with SEGV in test_re and test_sre due to the small default stack size. If you set the stack size to 2048 before doing a "make test" the - failure can be avoided. If you're using the tcsh (the default - on OSX), or csh shells use "limit stacksize 2048" and for the - bash shell, use "ulimit -s 2048". + failure can be avoided. If you're using the tcsh or csh shells, + use "limit stacksize 2048" and for the bash shell (the default + as of OSX 10.3), use "ulimit -s 2048". On naked Darwin you may want to add the configure option "--disable-toolbox-glue" to disable the glue code for the Carbon From buildbot at python.org Tue Mar 6 19:55:41 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 18:55:41 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 trunk Message-ID: <20070306185541.6A0201E4024@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%2520trunk/builds/1460 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 20:00:02 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 20:00:02 +0100 (CET) Subject: [Python-checkins] r54177 - in python/trunk: Lib/test/test_operator.py Misc/NEWS Modules/operator.c Message-ID: <20070306190002.D971D1E400D@bag.python.org> Author: georg.brandl Date: Tue Mar 6 19:59:11 2007 New Revision: 54177 Modified: python/trunk/Lib/test/test_operator.py python/trunk/Misc/NEWS python/trunk/Modules/operator.c Log: Patch #1654417: make operator.{get,set,del}slice use the full range of Py_ssize_t. Modified: python/trunk/Lib/test/test_operator.py ============================================================================== --- python/trunk/Lib/test/test_operator.py (original) +++ python/trunk/Lib/test/test_operator.py Tue Mar 6 19:59:11 2007 @@ -143,6 +143,8 @@ self.failUnlessRaises(TypeError, operator.delslice, a, None, None) self.failUnless(operator.delslice(a, 2, 8) is None) self.assert_(a == [0, 1, 8, 9]) + operator.delslice(a, 0, test_support.MAX_Py_ssize_t) + self.assert_(a == []) def test_div(self): self.failUnlessRaises(TypeError, operator.div, 5) @@ -170,6 +172,8 @@ self.failUnlessRaises(TypeError, operator.getslice) self.failUnlessRaises(TypeError, operator.getslice, a, None, None) self.failUnless(operator.getslice(a, 4, 6) == [4, 5]) + b = operator.getslice(a, 0, test_support.MAX_Py_ssize_t) + self.assert_(b == a) def test_indexOf(self): self.failUnlessRaises(TypeError, operator.indexOf) @@ -318,6 +322,8 @@ self.failUnlessRaises(TypeError, operator.setslice, a, None, None, None) self.failUnless(operator.setslice(a, 1, 3, [2, 1]) is None) self.assert_(a == [0, 2, 1, 3]) + operator.setslice(a, 0, test_support.MAX_Py_ssize_t, []) + self.assert_(a == []) def test_sub(self): self.failUnlessRaises(TypeError, operator.sub) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 19:59:11 2007 @@ -406,6 +406,9 @@ Extension Modules ----------------- +- Patch #1654417: make operator.{get,set,del}slice use the full range + of Py_ssize_t. + - Patch #1646728: datetime.fromtimestamp fails with negative fractional times. With unittest. Modified: python/trunk/Modules/operator.c ============================================================================== --- python/trunk/Modules/operator.c (original) +++ python/trunk/Modules/operator.c Tue Mar 6 19:59:11 2007 @@ -168,43 +168,41 @@ op_getslice(PyObject *s, PyObject *a) { PyObject *a1; - int a2,a3; + Py_ssize_t a2, a3; - if (!PyArg_ParseTuple(a,"Oii:getslice",&a1,&a2,&a3)) + if (!PyArg_ParseTuple(a, "Onn:getslice", &a1, &a2, &a3)) return NULL; - return PySequence_GetSlice(a1,a2,a3); + return PySequence_GetSlice(a1, a2, a3); } static PyObject* op_setslice(PyObject *s, PyObject *a) { PyObject *a1, *a4; - int a2,a3; + Py_ssize_t a2, a3; - if (!PyArg_ParseTuple(a,"OiiO:setslice",&a1,&a2,&a3,&a4)) + if (!PyArg_ParseTuple(a, "OnnO:setslice", &a1, &a2, &a3, &a4)) return NULL; - if (-1 == PySequence_SetSlice(a1,a2,a3,a4)) + if (-1 == PySequence_SetSlice(a1, a2, a3, a4)) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject* op_delslice(PyObject *s, PyObject *a) { PyObject *a1; - int a2,a3; + Py_ssize_t a2, a3; - if(! PyArg_ParseTuple(a,"Oii:delslice",&a1,&a2,&a3)) + if (!PyArg_ParseTuple(a, "Onn:delslice", &a1, &a2, &a3)) return NULL; - if (-1 == PySequence_DelSlice(a1,a2,a3)) + if (-1 == PySequence_DelSlice(a1, a2, a3)) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #undef spam1 From python-checkins at python.org Tue Mar 6 20:00:10 2007 From: python-checkins at python.org (georg.brandl) Date: Tue, 6 Mar 2007 20:00:10 +0100 (CET) Subject: [Python-checkins] r54178 - in python/branches/release25-maint: Lib/test/test_operator.py Misc/NEWS Modules/operator.c Message-ID: <20070306190010.EA5061E4018@bag.python.org> Author: georg.brandl Date: Tue Mar 6 20:00:09 2007 New Revision: 54178 Modified: python/branches/release25-maint/Lib/test/test_operator.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Modules/operator.c Log: Patch #1654417: make operator.{get,set,del}slice use the full range of Py_ssize_t. (backport from rev. 54177) Modified: python/branches/release25-maint/Lib/test/test_operator.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_operator.py (original) +++ python/branches/release25-maint/Lib/test/test_operator.py Tue Mar 6 20:00:09 2007 @@ -143,6 +143,8 @@ self.failUnlessRaises(TypeError, operator.delslice, a, None, None) self.failUnless(operator.delslice(a, 2, 8) is None) self.assert_(a == [0, 1, 8, 9]) + operator.delslice(a, 0, test_support.MAX_Py_ssize_t) + self.assert_(a == []) def test_div(self): self.failUnlessRaises(TypeError, operator.div, 5) @@ -170,6 +172,8 @@ self.failUnlessRaises(TypeError, operator.getslice) self.failUnlessRaises(TypeError, operator.getslice, a, None, None) self.failUnless(operator.getslice(a, 4, 6) == [4, 5]) + b = operator.getslice(a, 0, test_support.MAX_Py_ssize_t) + self.assert_(b == a) def test_indexOf(self): self.failUnlessRaises(TypeError, operator.indexOf) @@ -318,6 +322,8 @@ self.failUnlessRaises(TypeError, operator.setslice, a, None, None, None) self.failUnless(operator.setslice(a, 1, 3, [2, 1]) is None) self.assert_(a == [0, 2, 1, 3]) + operator.setslice(a, 0, test_support.MAX_Py_ssize_t, []) + self.assert_(a == []) def test_sub(self): self.failUnlessRaises(TypeError, operator.sub) Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Tue Mar 6 20:00:09 2007 @@ -120,6 +120,9 @@ Extension Modules ----------------- +- Patch #1654417: make operator.{get,set,del}slice use the full range + of Py_ssize_t. + - Patch #1646728: datetime.fromtimestamp fails with negative fractional times. With unittest. Modified: python/branches/release25-maint/Modules/operator.c ============================================================================== --- python/branches/release25-maint/Modules/operator.c (original) +++ python/branches/release25-maint/Modules/operator.c Tue Mar 6 20:00:09 2007 @@ -168,43 +168,41 @@ op_getslice(PyObject *s, PyObject *a) { PyObject *a1; - int a2,a3; + Py_ssize_t a2, a3; - if (!PyArg_ParseTuple(a,"Oii:getslice",&a1,&a2,&a3)) + if (!PyArg_ParseTuple(a, "Onn:getslice", &a1, &a2, &a3)) return NULL; - return PySequence_GetSlice(a1,a2,a3); + return PySequence_GetSlice(a1, a2, a3); } static PyObject* op_setslice(PyObject *s, PyObject *a) { PyObject *a1, *a4; - int a2,a3; + Py_ssize_t a2, a3; - if (!PyArg_ParseTuple(a,"OiiO:setslice",&a1,&a2,&a3,&a4)) + if (!PyArg_ParseTuple(a, "OnnO:setslice", &a1, &a2, &a3, &a4)) return NULL; - if (-1 == PySequence_SetSlice(a1,a2,a3,a4)) + if (-1 == PySequence_SetSlice(a1, a2, a3, a4)) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject* op_delslice(PyObject *s, PyObject *a) { PyObject *a1; - int a2,a3; + Py_ssize_t a2, a3; - if(! PyArg_ParseTuple(a,"Oii:delslice",&a1,&a2,&a3)) + if (!PyArg_ParseTuple(a, "Onn:delslice", &a1, &a2, &a3)) return NULL; - if (-1 == PySequence_DelSlice(a1,a2,a3)) + if (-1 == PySequence_DelSlice(a1, a2, a3)) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #undef spam1 From buildbot at python.org Tue Mar 6 20:05:20 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 19:05:20 +0000 Subject: [Python-checkins] buildbot warnings in x86 gentoo trunk Message-ID: <20070306190523.175AE1E400D@bag.python.org> The Buildbot has detected a new failure of x86 gentoo trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%2520trunk/builds/1975 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings failed slave lost sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 20:08:32 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 19:08:32 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP 2.5 Message-ID: <20070306190832.EE7121E4018@bag.python.org> The Buildbot has detected a new failure of x86 XP 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%25202.5/builds/142 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_datetime ====================================================================== ERROR: test_negative_float_fromtimestamp (test.test_datetime.TestDateTime) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\2.5.mcintyre-windows\build\lib\test\test_datetime.py", line 1431, in test_negative_float_fromtimestamp self.theclass.fromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function ====================================================================== ERROR: test_negative_float_utcfromtimestamp (test.test_datetime.TestDateTime) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\2.5.mcintyre-windows\build\lib\test\test_datetime.py", line 1434, in test_negative_float_utcfromtimestamp d = self.theclass.utcfromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function ====================================================================== ERROR: test_negative_float_fromtimestamp (test.test_datetime.TestDateTimeTZ) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\2.5.mcintyre-windows\build\lib\test\test_datetime.py", line 1431, in test_negative_float_fromtimestamp self.theclass.fromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function ====================================================================== ERROR: test_negative_float_utcfromtimestamp (test.test_datetime.TestDateTimeTZ) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\2.5.mcintyre-windows\build\lib\test\test_datetime.py", line 1434, in test_negative_float_utcfromtimestamp d = self.theclass.utcfromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function sincerely, -The Buildbot From buildbot at python.org Tue Mar 6 20:52:04 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 19:52:04 +0000 Subject: [Python-checkins] buildbot warnings in x86 mvlgcc trunk Message-ID: <20070306195204.2AE421E4014@bag.python.org> The Buildbot has detected a new failure of x86 mvlgcc trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520mvlgcc%2520trunk/builds/300 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 21:39:00 2007 From: python-checkins at python.org (walter.doerwald) Date: Tue, 6 Mar 2007 21:39:00 +0100 (CET) Subject: [Python-checkins] r54180 - in python/trunk: Lib/test/test_curses.py Modules/_cursesmodule.c Message-ID: <20070306203900.2880E1E4015@bag.python.org> Author: walter.doerwald Date: Tue Mar 6 21:38:57 2007 New Revision: 54180 Modified: python/trunk/Lib/test/test_curses.py python/trunk/Modules/_cursesmodule.c Log: Patch for bug #1633621: if curses.resizeterm() or curses.resize_term() is called, update _curses.LINES, _curses.COLS, curses.LINES and curses.COLS. Modified: python/trunk/Lib/test/test_curses.py ============================================================================== --- python/trunk/Lib/test/test_curses.py (original) +++ python/trunk/Lib/test/test_curses.py Tue Mar 6 21:38:57 2007 @@ -241,12 +241,21 @@ except curses.panel.error: pass +def test_resize_term(stdscr): + if hasattr(curses, 'resizeterm'): + lines, cols = curses.LINES, curses.COLS + curses.resizeterm(lines - 1, cols + 1) + + if curses.LINES != lines - 1 or curses.COLS != cols + 1: + raise RuntimeError, "Expected resizeterm to update LINES and COLS" + def main(stdscr): curses.savetty() try: module_funcs(stdscr) window_funcs(stdscr) test_userptr_without_set(stdscr) + test_resize_term(stdscr) finally: curses.resetty() Modified: python/trunk/Modules/_cursesmodule.c ============================================================================== --- python/trunk/Modules/_cursesmodule.c (original) +++ python/trunk/Modules/_cursesmodule.c Tue Mar 6 21:38:57 2007 @@ -2196,19 +2196,72 @@ } } +/* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES + * and _curses.COLS */ +static int +update_lines_cols(void) +{ + PyObject *o; + PyObject *m = PyImport_ImportModule("curses"); + + if (!m) + return 0; + + o = PyInt_FromLong(LINES); + if (!o) { + Py_DECREF(m); + return 0; + } + if (PyObject_SetAttrString(m, "LINES", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + if (PyDict_SetItemString(ModDict, "LINES", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + Py_DECREF(o); + o = PyInt_FromLong(COLS); + if (!o) { + Py_DECREF(m); + return 0; + } + if (PyObject_SetAttrString(m, "COLS", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + if (PyDict_SetItemString(ModDict, "COLS", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + Py_DECREF(o); + Py_DECREF(m); + return 1; +} + #ifdef HAVE_CURSES_RESIZETERM static PyObject * PyCurses_ResizeTerm(PyObject *self, PyObject *args) { int lines; int columns; + PyObject *result; PyCursesInitialised if (!PyArg_ParseTuple(args,"ii:resizeterm", &lines, &columns)) return NULL; - return PyCursesCheckERR(resizeterm(lines, columns), "resizeterm"); + result = PyCursesCheckERR(resizeterm(lines, columns), "resizeterm"); + if (!result) + return NULL; + if (!update_lines_cols()) + return NULL; + return result; } #endif @@ -2220,12 +2273,19 @@ int lines; int columns; + PyObject *result; + PyCursesInitialised if (!PyArg_ParseTuple(args,"ii:resize_term", &lines, &columns)) return NULL; - return PyCursesCheckERR(resize_term(lines, columns), "resize_term"); + result = PyCursesCheckERR(resize_term(lines, columns), "resize_term"); + if (!result) + return NULL; + if (!update_lines_cols()) + return NULL; + return result; } #endif /* HAVE_CURSES_RESIZE_TERM */ From python-checkins at python.org Tue Mar 6 21:46:32 2007 From: python-checkins at python.org (walter.doerwald) Date: Tue, 6 Mar 2007 21:46:32 +0100 (CET) Subject: [Python-checkins] r54181 - in python/branches/release25-maint: Lib/test/test_curses.py Modules/_cursesmodule.c Message-ID: <20070306204632.5C6231E400D@bag.python.org> Author: walter.doerwald Date: Tue Mar 6 21:46:26 2007 New Revision: 54181 Modified: python/branches/release25-maint/Lib/test/test_curses.py python/branches/release25-maint/Modules/_cursesmodule.c Log: Backport checkin: Patch for bug #1633621: if curses.resizeterm() or curses.resize_term() is called, update _curses.LINES, _curses.COLS, curses.LINES and curses.COLS. Modified: python/branches/release25-maint/Lib/test/test_curses.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_curses.py (original) +++ python/branches/release25-maint/Lib/test/test_curses.py Tue Mar 6 21:46:26 2007 @@ -241,12 +241,21 @@ except curses.panel.error: pass +def test_resize_term(stdscr): + if hasattr(curses, 'resizeterm'): + lines, cols = curses.LINES, curses.COLS + curses.resizeterm(lines - 1, cols + 1) + + if curses.LINES != lines - 1 or curses.COLS != cols + 1: + raise RuntimeError, "Expected resizeterm to update LINES and COLS" + def main(stdscr): curses.savetty() try: module_funcs(stdscr) window_funcs(stdscr) test_userptr_without_set(stdscr) + test_resize_term(stdscr) finally: curses.resetty() Modified: python/branches/release25-maint/Modules/_cursesmodule.c ============================================================================== --- python/branches/release25-maint/Modules/_cursesmodule.c (original) +++ python/branches/release25-maint/Modules/_cursesmodule.c Tue Mar 6 21:46:26 2007 @@ -2196,19 +2196,72 @@ } } +/* Internal helper used for updating curses.LINES, curses.COLS, _curses.LINES + * and _curses.COLS */ +static int +update_lines_cols(void) +{ + PyObject *o; + PyObject *m = PyImport_ImportModule("curses"); + + if (!m) + return 0; + + o = PyInt_FromLong(LINES); + if (!o) { + Py_DECREF(m); + return 0; + } + if (PyObject_SetAttrString(m, "LINES", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + if (PyDict_SetItemString(ModDict, "LINES", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + Py_DECREF(o); + o = PyInt_FromLong(COLS); + if (!o) { + Py_DECREF(m); + return 0; + } + if (PyObject_SetAttrString(m, "COLS", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + if (PyDict_SetItemString(ModDict, "COLS", o)) { + Py_DECREF(m); + Py_DECREF(o); + return 0; + } + Py_DECREF(o); + Py_DECREF(m); + return 1; +} + #ifdef HAVE_CURSES_RESIZETERM static PyObject * PyCurses_ResizeTerm(PyObject *self, PyObject *args) { int lines; int columns; + PyObject *result; PyCursesInitialised if (!PyArg_ParseTuple(args,"ii:resizeterm", &lines, &columns)) return NULL; - return PyCursesCheckERR(resizeterm(lines, columns), "resizeterm"); + result = PyCursesCheckERR(resizeterm(lines, columns), "resizeterm"); + if (!result) + return NULL; + if (!update_lines_cols()) + return NULL; + return result; } #endif @@ -2220,12 +2273,19 @@ int lines; int columns; + PyObject *result; + PyCursesInitialised if (!PyArg_ParseTuple(args,"ii:resize_term", &lines, &columns)) return NULL; - return PyCursesCheckERR(resize_term(lines, columns), "resize_term"); + result = PyCursesCheckERR(resize_term(lines, columns), "resize_term"); + if (!result) + return NULL; + if (!update_lines_cols()) + return NULL; + return result; } #endif /* HAVE_CURSES_RESIZE_TERM */ From buildbot at python.org Tue Mar 6 21:54:14 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 20:54:14 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 trunk Message-ID: <20070306205414.EE75C1E4019@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%2520trunk/builds/1462 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: walter.doerwald Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 22:15:24 2007 From: python-checkins at python.org (walter.doerwald) Date: Tue, 6 Mar 2007 22:15:24 +0100 (CET) Subject: [Python-checkins] r54182 - python/trunk/Misc/NEWS Message-ID: <20070306211524.92B8C1E400E@bag.python.org> Author: walter.doerwald Date: Tue Mar 6 22:15:24 2007 New Revision: 54182 Modified: python/trunk/Misc/NEWS Log: Document change to curses. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 6 22:15:24 2007 @@ -484,6 +484,8 @@ - Added support for linking the bsddb module against BerkeleyDB 4.5.x. +- Bug #1633621: if curses.resizeterm() or curses.resize_term() is called, + update _curses.LINES, _curses.COLS, curses.LINES and curses.COLS. Tests ----- From python-checkins at python.org Tue Mar 6 22:16:32 2007 From: python-checkins at python.org (walter.doerwald) Date: Tue, 6 Mar 2007 22:16:32 +0100 (CET) Subject: [Python-checkins] r54183 - python/branches/release25-maint/Misc/NEWS Message-ID: <20070306211632.EDFEE1E400D@bag.python.org> Author: walter.doerwald Date: Tue Mar 6 22:16:32 2007 New Revision: 54183 Modified: python/branches/release25-maint/Misc/NEWS Log: Document curses changes. Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Tue Mar 6 22:16:32 2007 @@ -191,6 +191,9 @@ - Bug #1552726: fix polling at the interpreter prompt when certain versions of the readline library are in use. +- Bug #1633621: if curses.resizeterm() or curses.resize_term() is called, + update _curses.LINES, _curses.COLS, curses.LINES and curses.COLS. + Library ------- From buildbot at python.org Tue Mar 6 22:20:18 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 21:20:18 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070306212018.950351E400D@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/246 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: walter.doerwald Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_datetime ====================================================================== ERROR: test_negative_float_fromtimestamp (test.test_datetime.TestDateTime) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_datetime.py", line 1431, in test_negative_float_fromtimestamp self.theclass.fromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function ====================================================================== ERROR: test_negative_float_utcfromtimestamp (test.test_datetime.TestDateTime) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_datetime.py", line 1434, in test_negative_float_utcfromtimestamp d = self.theclass.utcfromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function ====================================================================== ERROR: test_negative_float_fromtimestamp (test.test_datetime.TestDateTimeTZ) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_datetime.py", line 1431, in test_negative_float_fromtimestamp self.theclass.fromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function ====================================================================== ERROR: test_negative_float_utcfromtimestamp (test.test_datetime.TestDateTimeTZ) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_datetime.py", line 1434, in test_negative_float_utcfromtimestamp d = self.theclass.utcfromtimestamp(-1.05) ValueError: timestamp out of range for platform localtime()/gmtime() function sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 23:31:21 2007 From: python-checkins at python.org (brett.cannon) Date: Tue, 6 Mar 2007 23:31:21 +0100 (CET) Subject: [Python-checkins] r54184 - sandbox/trunk/pep0 Message-ID: <20070306223121.8617B1E400D@bag.python.org> Author: brett.cannon Date: Tue Mar 6 23:31:18 2007 New Revision: 54184 Added: sandbox/trunk/pep0/ Log: Place in the sandbox to develop a script to auto-generate PEP 0 (PEP index). From buildbot at python.org Tue Mar 6 23:43:07 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 06 Mar 2007 22:43:07 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 Message-ID: <20070306224307.6796F1E400F@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/43 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: walter.doerwald Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Tue Mar 6 23:43:19 2007 From: python-checkins at python.org (brett.cannon) Date: Tue, 6 Mar 2007 23:43:19 +0100 (CET) Subject: [Python-checkins] r54185 - sandbox/trunk/pep0/TODO sandbox/trunk/pep0/pep0.py sandbox/trunk/pep0/test_pep0.py Message-ID: <20070306224319.9866F1E400E@bag.python.org> Author: brett.cannon Date: Tue Mar 6 23:43:15 2007 New Revision: 54185 Added: sandbox/trunk/pep0/TODO (contents, props changed) sandbox/trunk/pep0/pep0.py (contents, props changed) sandbox/trunk/pep0/test_pep0.py (contents, props changed) Log: Initial checkin. No where near complete, but can at least parse metadata headers of PEPs. Added: sandbox/trunk/pep0/TODO ============================================================================== --- (empty file) +++ sandbox/trunk/pep0/TODO Tue Mar 6 23:43:15 2007 @@ -0,0 +1,25 @@ +In script: +* Read PEPs as UTF-8, not ASCII. +* Output static text for PEP 0. + + Store Owners list in a data structure. + - Support nicknames for PEP listing (e.g., "Guido van Rossum" -> + "GvR"). + - Care about making sure that email addresses are up-to-date between + PEPs and PEP 0? + - Worth keeping emails in both PEP 0 and individual PEPs, or just make + PEP 0 master and leave out of PEPs so that single place can be + maintained and considered up-to-date? + + Store Key in data structure for easy mapping? + - Would allow for easy validation that metadata is correct in PEPs. +* Output PEP 0 with numerical PEP index. +* Output PEP 0 with special sections. + +For PEPs: +* Define (and enforce) consistency in Author field. +* Empty PEPs are not in any way identified within the PEPs themselves. + + Get ride of section and just consider rejected? + - No longer accept empty PEPs, right? +* Meta-PEPs are not noted as such within the PEPs. + + Add a "Meta" option for "Type"? +* Fix inconsistent usage of Status field. + + Some PEPs just say "Standard"; missing "Track". Added: sandbox/trunk/pep0/pep0.py ============================================================================== --- (empty file) +++ sandbox/trunk/pep0/pep0.py Tue Mar 6 23:43:15 2007 @@ -0,0 +1,125 @@ +"""Auto-generate PEP 0 (PEP index). """ +from __future__ import with_statement +import os + +def consume_headers(directory='.'): + """Pull out metadata for every PEP in the specified directory and return + them in a list sorted by PEP name.""" + peps = [] + for file_name in os.listdir(directory): + if file_name.startswith('pep-') and file_name.endswith('.txt'): + peps.append(consume_pep(os.path.join(directory, file_name))) + peps.sort(key=lambda pep: pep['PEP']) + return peps + +def consume_pep(path): + """Consume the specified file as a PEP to get its metadata.""" + pep_info = {} + with open(path, 'rU') as pep_file: + try: + for line in pep_file: + if line == '\n': + break + elif line[1].isspace(): + type_ = parse_metadata(pep_info, line, type_) + else: + type_ = parse_metadata(pep_info, line) + except Exception: + print "In", pep_file + raise + return pep_info + +def parse_metadata(pep_info, line, previous_type=None): + """Parse the given line for PEP metadata, adding on to existing metadata if + previous_type is specified, returning the last type of metadata handled.""" + if previous_type: + type_ = previous_type + data = line + else: + type_, data = line.split(':', 1) + type_ = type_.strip() + data = data.strip() + handler = handlers.get(type_, handle_generic) + result = handler(data) + if previous_type: + previous_data = pep_info[type_] + if not isinstance(previous_data, list): + previous_data = [previous_data] + pep_info[type_] = previous_data + previous_data.extend(result) + else: + pep_info[type_] = result + return type_ + +def handle_generic(data): + """Default handler for PEP metadata.""" + return data + +def handle_pep_num(data): + """Return the integer for the PEP number.""" + return int(data) + +def handle_author(data): + """Return a list of author names.""" + if '<' in data: + author, email = data.split('<', 1) + elif '(' in data: + email, author = data.split('(', 1) + author = author[:author.index(')')] + else: + author = data + return [author_name.strip() for author_name in author.split(',') if + author_name] + +def handle_csv(data): + """Handle the Post-History.""" + return [value.strip() for value in data.split(',') if value] + +handlers = {'Author': handle_author, + 'PEP': handle_pep_num, + 'Post-History': handle_csv, + } + +def sort_peps(peps): + """Sort PEPs into meta, informational, accepted, open, finished, empty, + and essentially dead.""" + meta = [] + info = [] + accepted = [] + open_ = [] + finished = [] + empty = [] + dead = [] + for pep in peps: + # XXX not all meta PEPs are process PEPs. + if pep['Type'] == 'Process': + meta.append(pep) + elif pep['Type'] == 'Informational': + info.append(pep) + elif pep['Status'] == 'Accepted': + accepted.append(pep) + elif pep['Status'] == 'Draft': + open_.append(pep) + elif pep['Status'] == 'Final': + finished.append(pep) + # XXX empty + elif pep['Status'] in ('Rejected', 'Withdrawn', 'Deferred', + 'Incomplete'): + dead.append(pep) + return meta, info, accepted, open_, finished, empty, dead + +if __name__ == '__main__': + from sys import argv + + if not argv[1:]: + directory = '.' + else: + directory = argv[1] + peps = consume_headers(directory) + + status = set() + type_ = set() + for pep in peps: + status.add(pep['Status']) + type_.add(pep['Type']) + meta, info, accepted, open_, done, empty, dead = sort_peps(peps) Added: sandbox/trunk/pep0/test_pep0.py ============================================================================== --- (empty file) +++ sandbox/trunk/pep0/test_pep0.py Tue Mar 6 23:43:15 2007 @@ -0,0 +1,187 @@ +from __future__ import with_statement +import unittest +from test import test_support +import pep0 +from contextlib import contextmanager +import os + +class HandlerTests(unittest.TestCase): + + def test_handle_generic(self): + # Identity function. + for data in ('spam', 'spam,', '', 'spam, monty'): + self.failUnlessEqual(pep0.handle_generic(data), data) + + def test_pep_num(self): + # String -> int. + num = 42 + string_rep = str(num) + self.failUnlessEqual(pep0.handle_pep_num(string_rep), num) + + def test_handle_csv(self): + # Split on commas. + data = ['a', 'b', 'c'] + string_rep = ','.join(data) + self.failUnlessEqual(pep0.handle_csv(string_rep), data) + string_rep = ', '.join(data) + self.failUnlessEqual(pep0.handle_csv(string_rep), data) + string_rep = ', '.join(data) + ',' + got = pep0.handle_csv(string_rep) + self.failUnlessEqual(got, data, + '%r != %r (using %r)' % + (got, data, string_rep)) + + def test_handle_author(self): + # Handle the various ways authors can be specified: + # Name , + # email (name), + # Name. + author = "Guido van Rossum" + str_rep = "%s " % author + self.failUnlessEqual(pep0.handle_author(str_rep), [author]) + str_rep += ',' + self.failUnlessEqual(pep0.handle_author(str_rep), [author]) + str_rep = "email (%s)" % author + self.failUnlessEqual(pep0.handle_author(str_rep), [author]) + str_rep += ',' + self.failUnlessEqual(pep0.handle_author(str_rep), [author]) + str_rep = author + self.failUnlessEqual(pep0.handle_author(str_rep), [author]) + str_rep += ',' + self.failUnlessEqual(pep0.handle_author(str_rep), [author]) + authors = ["Guido van Rossum", "Brett Cannon"] + str_rep = ', '.join(authors) + self.failUnlessEqual(pep0.handle_author(str_rep), authors) + + +class ParseMetaDataTests(unittest.TestCase): + + def test_parse_known_formats(self): + # Handle specific metadata format types. + assert "PEP" in pep0.handlers + line = "PEP: 42" + info = {} + handled = pep0.parse_metadata(info, line) + self.failUnlessEqual(handled, "PEP") + self.failUnless("PEP" in info) + self.failUnlessEqual(info['PEP'], 42) + + def test_parse_unknown_formats(self): + # If a format is not known then it should just be returned with + # whitespace stripped. + info = {} + type_ = "Spam" + data = "Monty Python" + line = "%s: %s" % (type_, data) + handled = pep0.parse_metadata(info, line) + self.failUnlessEqual(handled, type_) + self.failUnless(type_ in info) + self.failUnlessEqual(info[type_], data) + + def test_multiline_formats(self): + # Deal with formats that can span multiple lines (e.g., authors and + # Post-History). + type_ = 'Prev' + info = {type_ : [1]} + data = 'A' + handled = pep0.parse_metadata(info, data, type_) + self.failUnlessEqual(handled, type_) + self.failUnlessEqual(len(info[type_]), 2) + self.failUnlessEqual(info[type_][1], data) + + + at contextmanager +def test_file(path): + try: + open_file = open(path, 'w') + yield open_file + finally: + open_file.close() + if os.path.exists(path): + os.unlink(path) + + +class ConsumePepTests(unittest.TestCase): + + def test_single_line(self): + # Test a PEP that only has a single line of metadata. + type_ = 'Spam' + data = 'Monty' + with test_file(test_support.TESTFN) as pep_file: + pep_file.write('%s: %s\n' % (type_, data)) + pep_file.write('\n') + pep_file.write('The PEP.') + pep_file.close() + metadata = pep0.consume_pep(test_support.TESTFN) + self.failUnless(type_ in metadata) + self.failUnlessEqual(metadata[type_], data) + + def test_multi_line_authors(self): + # Make sure that metadata that takes multiple lines works when it + # is expected (e.g., Author and Post-History). + authors = ['A', 'B'] + output = 'Author: ' + authors[0] + '\n' + output += ' ' + authors[1] + '\n' + with test_file(test_support.TESTFN) as pep_file: + pep_file.write(output) + pep_file.write('\n') + pep_file.write('The PEP.') + pep_file.close() + metadata = pep0.consume_pep(test_support.TESTFN) + self.failUnless('Author' in metadata) + self.failUnlessEqual(metadata['Author'], authors) + + def test_multi_line_post_history(self): + # Post-History entries on multiple lines is fine. + dates = ['04-Jul-1776', '23-Oct-2007', '01-Jan-2001'] + output = 'Post-History: ' + ', '.join(dates[:2]) + '\n' + output += ' ' + dates[2] + '\n' + with test_file(test_support.TESTFN) as pep_file: + pep_file.write(output) + pep_file.write('\n') + pep_file.write('The PEP.') + pep_file.close() + metadata = pep0.consume_pep(test_support.TESTFN) + self.failUnless('Post-History' in metadata) + self.failUnlessEqual(metadata['Post-History'], dates) + + def test_utf8(self): + # Need to handle text as UTF-8. + # XXX + pass + + +class PepSortTests(unittest.TestCase): + + def test_meta(self): + pass + + def test_info(self): + pass + + def test_accepted(self): + pass + + def test_open(self): + pass + + def test_finished(self): + pass + + def test_empty(self): + pass + + def test_dead(self): + pass + + +def test_main(): + test_support.run_unittest( + HandlerTests, + ParseMetaDataTests, + ConsumePepTests, + ) + + +if __name__ == '__main__': + test_main() From python-checkins at python.org Wed Mar 7 00:01:35 2007 From: python-checkins at python.org (barry.warsaw) Date: Wed, 7 Mar 2007 00:01:35 +0100 (CET) Subject: [Python-checkins] r54186 - peps/trunk/pep-0000.txt peps/trunk/pep-0364.txt Message-ID: <20070306230135.571711E400D@bag.python.org> Author: barry.warsaw Date: Wed Mar 7 00:01:20 2007 New Revision: 54186 Added: peps/trunk/pep-0364.txt Modified: peps/trunk/pep-0000.txt Log: PEP 364, Transitioning to the Py3K Standard Library Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Wed Mar 7 00:01:20 2007 @@ -109,6 +109,7 @@ S 355 Path - Object oriented filesystem paths Lindqvist S 358 The "bytes" Object Schemenauer, GvR S 362 Function Signature Object Cannon, Seo + S 364 Transitioning to the Py3K Standard Library Warsaw S 754 IEEE 754 Floating Point Special Values Warnes S 3101 Advanced String Formatting Talin S 3108 Standard Library Reorganization Cannon @@ -440,6 +441,7 @@ I 361 Python 2.6 Release Schedule Norwitz, et al S 362 Function Signature Object Cannon, Seo SR 363 Syntax For Dynamic Attribute Access North + S 364 Transitioning to the Py3K Standard Library Warsaw SR 666 Reject Foolish Indentation Creighton S 754 IEEE 754 Floating Point Special Values Warnes P 3000 Python 3000 GvR Added: peps/trunk/pep-0364.txt ============================================================================== --- (empty file) +++ peps/trunk/pep-0364.txt Wed Mar 7 00:01:20 2007 @@ -0,0 +1,269 @@ +PEP: 364 +Title: Transitioning to the Py3K Standard Library +Version: $Revision$ +Last-Modified: $Date$ +Author: Barry A. Warsaw +Status: Active +Type: Standards Track +Content-Type: text/x-rst +Created: 01-Mar-2007 +Python-Version: 2.6 +Post-History: + + +Abstract +======== + +PEP 3108 describes the reorganization of the Python standard library +for the Python 3.0 release [1]_. This PEP describes a +mechanism for transitioning from the Python 2.x standard library to +the Python 3.0 standard library. This transition will allow and +encourage Python programmers to use the new Python 3.0 library names +starting with Python 2.6, while maintaining the old names for backward +compatibility. In this way, a Python programmer will be able to write +forward compatible code without sacrificing interoperability with +existing Python programs. + + +Rationale +========= + +PEP 3108 presents a rationale for Python standard library (stdlib) +reorganization. The reader is encouraged to consult that PEP for +details about why and how the library will be reorganized. Should +PEP 3108 be accepted in part or in whole, then it is advantageous to +allow Python programmers to begin the transition to the new stdlib +module names in Python 2.x, so that they can write forward compatible +code starting with Python 2.6. + +Note that PEP 3108 proposes to remove some "silly old stuff", +i.e. modules that are no longer useful or necessary. The PEP you are +reading does not address this because there are no forward +compatibility issues for modules that are to be removed, except to +stop using such modules. + +This PEP concerns only the mechanism by which mappings from old stdlib +names to new stdlib names are maintained. Please consult PEP 3108 for +all specific module renaming proposals. Specifically see the section +titled ``Modules to Rename`` for guidelines on the old name to new +name mappings. The few examples in this PEP are given for +illustrative purposes only and should not be used for specific +renaming recommendations. + + +Supported Renamings +=================== + +There are at least 4 use cases explicitly supported by this PEP: + +- Simple top-level package name renamings, such as ``StringIO`` to + ``stringio``; + +- Sub-package renamings where the package name may or may not be + renamed, such as ``email.MIMEText`` to ``email.mime.text``; + +- Extension module renaming, such as ``cStringIO`` to ``cstringio``; + +- Third party renaming of any of the above. + +Two use cases supported by this PEP include renaming simple top-level +modules, such as ``StringIO``, as well as modules within packages, +such as ``email.MIMEText``. + +In the former case, PEP 3108 currently recommends ``StringIO`` be +renamed to ``stringio``, following PEP 8 recommendations [2]_. + +In the latter case, the email 4.0 package distributed with Python 2.5 +already renamed ``email.MIMEText`` to ``email.mime.text``, although it +did so in a one-off, uniquely hackish way inside the email package. +The mechanism described in this PEP is general enough to handle all +module renamings, obviating the need for the Python 2.5 hack (except +for backward compatibility with earlier Python versions). + +An additional use case is to support the renaming of C extension +modules. As long as the new name for the C module is importable, it +can be remapped to the new name. E.g. ``cStringIO`` renamed to +``cstringio``. + +Third party package renaming is also supported, via several public +interfaces accessible by any Python module. + +Remappings are not performed recursively. + + +.mv files +========= + +Remapping files are called ``.mv`` files; the suffix was chosen to be +evocative of the Unix mv(1) command. An ``.mv`` file is a simple +line-oriented text file. All blank lines and lines that start with a +# are ignored. All other lines must contain two whitespace separated +fields. The first field is the old module name, and the second field +is the new module name. Both module names must be specified using +their full dotted-path names. Here is an example ``.mv`` file from +Python 2.6:: + + # Map the various string i/o libraries to their new names + StringIO stringio + cStringIO cstringio + +``.mv`` files can appear anywhere in the file system, and there is a +programmatic interface provided to parse them, and register the +remappings inside them. By default, when Python starts up, all the +``.mv`` files in the ``oldlib`` package are read, and their remappings +are automatically registered. This is where all the module remappings +should be specified for top-level Python 2.x standard library modules. + + +Implementation Specification +============================ + +This section provides the full specification for how module renamings +in Python 2.x are implemented. The central mechanism relies on +various import hooks as described in PEP 302 [3]_. Specifically +``sys.path_importer_cache``, ``sys.path``, and ``sys.meta_path`` are +all employed to provide the necessary functionality. + +When Python's import machinery is initialized, the oldlib package is +imported. Inside oldlib there is a class called ``OldStdlibLoader``. +This class implements the PEP 302 interface and is automatically +instantiated, with zero arguments. The constructor reads all the +``.mv`` files from the oldlib package directory, automatically +registering all the remappings found in those ``.mv`` files. This is +how the Python 2.x standard library is remapped. + +The OldStdlibLoader class should not be instantiated by other Python +modules. Instead, you can access the global OldStdlibLoader instance +via the ``sys.stdlib_remapper`` instance. Use this instance if you want +programmatic access to the remapping machinery. + +One important implementation detail: as needed by the PEP 302 API, a +magic string is added to sys.path, and module __path__ attributes in +order to hook in our remapping loader. This magic string is currently +```` and some changes were necessary to Python's site.py file +in order to treat all sys.path entries starting with ``<`` as +special. Specifically, no attempt is made to make them absolute file +names (since they aren't file names at all). + +In order for the remapping import hooks to work, the module or package +must be physically located under its new name. This is because the +import hooks catch only modules that are not already imported, and +cannot be imported by Python's built-in import rules. Thus, if a +module has been moved, say from Lib/StringIO.py to Lib/stringio.py, +and the former's ``.pyc`` file has been removed, then without the +remapper, this would fail:: + + import StringIO + +Instead, with the remapper, this failing import will be caught, the +old name will be looked up in the registered remappings, and in this +case, the new name ``stringio`` will be found. The remapper then +attempts to import the new name, and if that succeeds, it binds the +resulting module into sys.modules, under both the old and new names. +Thus, the above import will result in entries in sys.modules for +'StringIO' and 'stringio', and both will point to the exact same +module object. + +Note that no way to disable the remapping machinery is proposed, short +of moving all the ``.mv`` files away or programmatically removing them +in some custom start up code. In Python 3.0, the remappings will be +eliminated, leaving only the "new" names. + + +Programmatic Interface +====================== + +Several methods are added to the ``sys.stdlib_remapper`` object, which +third party packages can use to register their own remappings. Note +however that in all cases, there is one and only one mapping from an +old name to a new name. If two ``.mv`` files contain different +mappings for an old name, or if a programmatic call is made with an +old name that is already remapped, the previous mapping is lost. This +will not affect any already imported modules. + +The following methods are available on the ``sys.stdlib_remapper`` +object: + +- ``read_mv_file(filename)`` -- Read the given file and register all + remappings found in the file. + +- ``read_directory_mv_files(dirname, suffix='.mv')`` -- List the given + directory, reading all files in that directory that have the + matching suffix (``.mv`` by default). For each parsed file, + register all the remappings found in that file. + +- ``set_mapping(oldname, newname)`` -- Register a new mapping from an + old module name to a new module name. Both must be the full + dotted-path name to the module. newname may be ``None`` in which + case any existing mapping for oldname will be removed (it is not an + error if there is no existing mapping). + +- ``get_mapping(oldname, default=None)`` -- Return any registered + newname for the given oldname. If there is no registered remapping, + default is returned. + + +Open Issues +=========== + + - Should there be a command line switch and/or environment variable to + disable all remappings? + + - Should remappings occur recursively? + + - Should we automatically parse package directories for .mv files when + the package's __init__.py is loaded? This would allow packages to + easily include .mv files for their own remappings. Compare what the + email package currently has to do if we place its ``.mv`` file in + the email package instead of in the oldlib package:: + + # Expose old names + import os, sys + sys.stdlib_remapper.read_directory_mv_files(os.path.dirname(__file__)) + + I think we should automatically read a package's directory for any + ``.mv`` files it might contain. + + +Reference Implementation +======================== + +A reference implementation, in the form of a patch against the current +(as of this writing) state of the Python 2.6 svn trunk, is available +as SourceForge patch #1675334 [4]_. Note that this patch includes a +rename of ``cStringIO`` to ``cstringio``, but this is primarily for +illustrative and unit testing purposes. Should the patch be accepted, +we might want to split this change off into other PEP 3108 changes. + + +References +========== + +.. [1] PEP 3108, Standard Library Reorganization, Cannon + (http://www.python.org/dev/peps/pep-3108) + +.. [2] PEP 8, Style Guide for Python Code, GvR, Warsaw + (http://www.python.org/dev/peps/pep-0008) + +.. [3] PEP 302, New Import Hooks, JvR, Moore + (http://www.python.org/dev/peps/pep-0302) + +.. [4] Reference implementation on SourceForge + (https://sourceforge.net/tracker/index.php?func=detail&aid=1675334&group_id=5470&atid=305470) + + +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 + coding: utf-8 + End: From python-checkins at python.org Wed Mar 7 00:27:38 2007 From: python-checkins at python.org (ka-ping.yee) Date: Wed, 7 Mar 2007 00:27:38 +0100 (CET) Subject: [Python-checkins] r54187 - peps/trunk/pep-3114.txt Message-ID: <20070306232738.C524D1E400D@bag.python.org> Author: ka-ping.yee Date: Wed Mar 7 00:27:37 2007 New Revision: 54187 Added: peps/trunk/pep-3114.txt Log: Add PEP 3114: renaming .next() to .__next__(). Added: peps/trunk/pep-3114.txt ============================================================================== --- (empty file) +++ peps/trunk/pep-3114.txt Wed Mar 7 00:27:37 2007 @@ -0,0 +1,210 @@ +PEP: 3114 +Title: Renaming iterator.next() to iterator.__next__() +Version: $Revision$ +Last-Modified: $Date$ +Author: Ka-Ping Yee +Status: Accepted +Type: Standards Track +Python-version: 3.0 +Content-Type: text/x-rst +Created: 04-Mar-2007 + + +Abstract +======== + +The iterator protocol in Python 2.x consists of two methods: +``__iter__()`` called on an iterable object to yield an iterator, and +``next()`` called on an iterator object to yield the next item in the +sequence. Using a ``for`` loop to iterate over an iterable object +implicitly calls both of these methods. This PEP proposes that the +``next`` method be renamed to ``__next__``, consistent with all the +other protocols in Python in which a method is implicitly called as +part of a language-level protocol, and that a built-in function named +``next`` be introduced to invoke ``__next__`` method, consistent with +the manner in which other protocols are explicitly invoked. + + +Names With Double Underscores +============================= + +In Python, double underscores before and after a name are used to +distinguish names that belong to the language itself. Attributes and +methods that are implicitly used or created by the interpreter employ +this naming convention; some examples are: + +* ``__file__`` - an attribute automatically created by the interpreter + +* ``__dict__`` - an attribute with special meaning to the interpreter + +* ``__init__`` - a method implicitly called by the interpreter + +Note that this convention applies to methods such as ``__init__`` that +are explicitly defined by the programmer, as well as attributes such as +``__file__`` that can only be accessed by naming them explicitly, so it +includes names that are used *or* created by the interpreter. + +(Not all things that are called "protocols" are made of methods with +double-underscore names. For example, the ``__contains__`` method has +double underscores because the language construct ``x in y`` implicitly +calls ``__contains__``. But even though the ``read`` method is part of +the file protocol, it does not have double underscores because there is +no language construct that implicitly invokes ``x.read()``.) + +The use of double underscores creates a separate namespace for names +that are part of the Python language definition, so that programmers +are free to create variables, attributes, and methods that start with +letters, without fear of silently colliding with names that have a +language-defined purpose. (Colliding with reserved keywords is still +a concern, but at least this will immediately yield a syntax error.) + +The naming of the ``next`` method on iterators is an exception to +this convention. Code that nowhere contains an explicit call to a +``next`` method can nonetheless be silently affected by the presence +of such a method. Therefore, this PEP proposes that iterators should +have a ``__next__`` method instead of a ``next`` method (with no +change in semantics). + + +Double-Underscore Methods and Built-In Functions +================================================ + +The Python language defines several protocols that are implemented or +customized by defining methods with double-underscore names. In each +case, the protocol is provided by an internal method implemented as a +C function in the interpreter. For objects defined in Python, this +C function supports customization by implicitly invoking a Python method +with a double-underscore name (it often does a little bit of additional +work beyond just calling the Python method.) + +Sometimes the protocol is invoked by a syntactic construct: + +* ``x[y]`` --> internal ``tp_getitem`` --> ``x.__getitem__(y)`` + +* ``x + y`` --> internal ``nb_add`` --> ``x.__add__(y)`` + +* ``-x`` --> internal ``nb_negative`` --> ``x.__neg__()`` + +Sometimes there is no syntactic construct, but it is still useful to be +able to explicitly invoke the protocol. For such cases Python offers a +built-in function of the same name but without the double underscores. + +* ``len(x)`` --> internal ``sq_length`` --> ``x.__len__()`` + +* ``hash(x)`` --> internal ``tp_hash`` --> ``x.__hash__()`` + +* ``iter(x)`` --> internal ``tp_iter`` --> ``x.__iter__()`` + +Following this pattern, the natural way to handle ``next`` is to add a +``next`` built-in function that behaves in exactly the same fashion. + +* ``next(x)`` --> internal ``tp_iternext`` --> ``x.__next__()`` + +Further, it is proposed that the ``next`` built-in function accept a +sentinel value as an optional second argument, following the style of +the ``getattr`` and ``iter`` built-in functions. When called with two +arguments, ``next`` catches the StopIteration exception and returns +the sentinel value instead of propagating the exception. This creates +a nice duality between ``iter`` and ``next``: + + iter(function, sentinel) <--> next(iterator, sentinel) + + +Previous Proposals +================== + +This proposal is not a new idea. The idea proposed here was supported +by the BDFL on python-dev [1]_ and is even mentioned in the original +iterator PEP, PEP 234:: + + (In retrospect, it might have been better to go for __next__() + and have a new built-in, next(it), which calls it.__next__(). + But alas, it's too late; this has been deployed in Python 2.2 + since December 2001.) + + +Objections +========== + +There have been a few objections to the addition of more built-ins. +In particular, Martin von Loewis writes [2]_:: + + I dislike the introduction of more builtins unless they have a true + generality (i.e. are likely to be needed in many programs). For this + one, I think the normal usage of __next__ will be with a for loop, so + I don't think one would often need an explicit next() invocation. + + It is also not true that most protocols are explicitly invoked through + builtin functions. Instead, most protocols are can be explicitly invoked + through methods in the operator module. So following tradition, it + should be operator.next. + + ... + + As an alternative, I propose that object grows a .next() method, + which calls __next__ by default. + + +Transition Plan +=============== + +(This section is likely to be updated.) + +Two additional transformations will be added to the 2to3 translation +tool [3]_: + +* Method definitions named ``next`` will be renamed to ``__next__``. + +* Explicit calls to the ``next`` method will be replaced with calls + to the built-in ``next`` function. For example, ``x.next()`` will + become ``next(x)``. + +If the module being processed already contains a binding for the name +``next``, the second transformation will not be done; instead, calls to +``x.next()`` will be replaced with ``x.__next__()`` and a warning will +be emitted. (Collin Winter has looked into this [4]_ and found that +it's difficult to make the second transformation depend on the presence +of a module-level binding; warning about the existence of bindings to +``next`` should be possible, though.) + + +Approval +======== + +This PEP was accepted by Guido on March 6, 2007 [5]_. + + +References +========== + +.. [1] Single- vs. Multi-pass iterability (Guido van Rossum) + http://mail.python.org/pipermail/python-dev/2002-July/026814.html + +.. [2] PEP: rename it.next() to it.__next__()... (Martin von Loewis) + http://mail.python.org/pipermail/python-3000/2007-March/005965.html + +.. [3] 2to3 refactoring tool + http://svn.python.org/view/sandbox/trunk/2to3/ + +.. [4] PEP: rename it.next() to it.__next__()... (Collin Winter) + http://mail.python.org/pipermail/python-3000/2007-March/006020.html + +.. [5] PEP: rename it.next() to it.__next__()... (Guido van Rossum) + http://mail.python.org/pipermail/python-3000/2007-March/006027.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 + coding: utf-8 + End: From python-checkins at python.org Wed Mar 7 01:34:53 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 01:34:53 +0100 (CET) Subject: [Python-checkins] r54188 - in python/trunk: Include/pydebug.h Misc/NEWS Modules/main.c Python/pythonrun.c Message-ID: <20070307003453.8AFCA1E400D@bag.python.org> Author: georg.brandl Date: Wed Mar 7 01:34:46 2007 New Revision: 54188 Modified: python/trunk/Include/pydebug.h python/trunk/Misc/NEWS python/trunk/Modules/main.c python/trunk/Python/pythonrun.c Log: Variant of patch #697613: don't exit the interpreter on a SystemExit exception if the -i command line option or PYTHONINSPECT environment variable is given, but break into the interactive interpreter just like on other exceptions or normal program exit. (backport) Modified: python/trunk/Include/pydebug.h ============================================================================== --- python/trunk/Include/pydebug.h (original) +++ python/trunk/Include/pydebug.h Wed Mar 7 01:34:46 2007 @@ -8,6 +8,7 @@ PyAPI_DATA(int) Py_DebugFlag; PyAPI_DATA(int) Py_VerboseFlag; PyAPI_DATA(int) Py_InteractiveFlag; +PyAPI_DATA(int) Py_InspectFlag; PyAPI_DATA(int) Py_OptimizeFlag; PyAPI_DATA(int) Py_NoSiteFlag; PyAPI_DATA(int) Py_UseClassExceptionsFlag; Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 7 01:34:46 2007 @@ -12,6 +12,11 @@ Core and builtins ----------------- +- Variant of patch #697613: don't exit the interpreter on a SystemExit + exception if the -i command line option or PYTHONINSPECT environment + variable is given, but break into the interactive interpreter just like + on other exceptions or normal program exit. + - Patch #1638879: don't accept strings with embedded NUL bytes in long(). - Bug #1674503: close the file opened by execfile() in an error condition. Modified: python/trunk/Modules/main.c ============================================================================== --- python/trunk/Modules/main.c (original) +++ python/trunk/Modules/main.c Wed Mar 7 01:34:46 2007 @@ -216,13 +216,11 @@ char *module = NULL; FILE *fp = stdin; char *p; - int inspect = 0; int unbuffered = 0; int skipfirstline = 0; int stdin_is_interactive = 0; int help = 0; int version = 0; - int saw_inspect_flag = 0; int saw_unbuffered_flag = 0; PyCompilerFlags cf; @@ -297,8 +295,7 @@ /* NOTREACHED */ case 'i': - inspect++; - saw_inspect_flag = 1; + Py_InspectFlag++; Py_InteractiveFlag++; break; @@ -369,9 +366,9 @@ return 0; } - if (!saw_inspect_flag && + if (!Py_InspectFlag && (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') - inspect = 1; + Py_InspectFlag = 1; if (!saw_unbuffered_flag && (p = Py_GETENV("PYTHONUNBUFFERED")) && *p != '\0') unbuffered = 1; @@ -499,7 +496,7 @@ PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind); - if ((inspect || (command == NULL && filename == NULL && module == NULL)) && + if ((Py_InspectFlag || (command == NULL && filename == NULL && module == NULL)) && isatty(fileno(stdin))) { PyObject *v; v = PyImport_ImportModule("readline"); @@ -518,6 +515,7 @@ } else { if (filename == NULL && stdin_is_interactive) { + Py_InspectFlag = 0; /* do exit on SystemExit */ RunStartupFile(&cf); } /* XXX */ @@ -530,16 +528,18 @@ /* Check this environment variable at the end, to give programs the * opportunity to set it from Python. */ - if (!saw_inspect_flag && + if (!Py_InspectFlag && (p = Py_GETENV("PYTHONINSPECT")) && *p != '\0') { - inspect = 1; + Py_InspectFlag = 1; } - if (inspect && stdin_is_interactive && - (filename != NULL || command != NULL || module != NULL)) + if (Py_InspectFlag && stdin_is_interactive && + (filename != NULL || command != NULL || module != NULL)) { + Py_InspectFlag = 0; /* XXX */ sts = PyRun_AnyFileFlags(stdin, "", &cf) != 0; + } WaitForThreadShutdown(); Modified: python/trunk/Python/pythonrun.c ============================================================================== --- python/trunk/Python/pythonrun.c (original) +++ python/trunk/Python/pythonrun.c Wed Mar 7 01:34:46 2007 @@ -69,6 +69,7 @@ int Py_DebugFlag; /* Needed by parser.c */ int Py_VerboseFlag; /* Needed by import.c */ int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ +int Py_InspectFlag; /* Needed to determine whether to exit at SystemError */ int Py_NoSiteFlag; /* Suppress 'import site' */ int Py_UseClassExceptionsFlag = 1; /* Needed by bltinmodule.c: deprecated */ int Py_FrozenFlag; /* Needed by getpath.c */ @@ -1019,6 +1020,11 @@ PyObject *exception, *value, *tb; int exitcode = 0; + if (Py_InspectFlag) + /* Don't exit if -i flag was given. This flag is set to 0 + * when entering interactive mode for inspecting. */ + return; + PyErr_Fetch(&exception, &value, &tb); if (Py_FlushLine()) PyErr_Clear(); From python-checkins at python.org Wed Mar 7 01:40:29 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 01:40:29 +0100 (CET) Subject: [Python-checkins] r54189 - in python/trunk: Misc/NEWS Python/pythonrun.c Message-ID: <20070307004029.8E1B91E400D@bag.python.org> Author: georg.brandl Date: Wed Mar 7 01:40:28 2007 New Revision: 54189 Modified: python/trunk/Misc/NEWS python/trunk/Python/pythonrun.c Log: Patch #703779: unset __file__ in __main__ after running a file. This makes the filenames the warning module prints much more sensible when a PYTHONSTARTUP file is used. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 7 01:40:28 2007 @@ -12,6 +12,10 @@ Core and builtins ----------------- +- Patch #703779: unset __file__ in __main__ after running a file. This + makes the filenames the warning module prints much more sensible when + a PYTHONSTARTUP file is used. + - Variant of patch #697613: don't exit the interpreter on a SystemExit exception if the -i command line option or PYTHONINSPECT environment variable is given, but break into the interactive interpreter just like Modified: python/trunk/Python/pythonrun.c ============================================================================== --- python/trunk/Python/pythonrun.c (original) +++ python/trunk/Python/pythonrun.c Wed Mar 7 01:40:28 2007 @@ -849,6 +849,7 @@ { PyObject *m, *d, *v; const char *ext; + int set_file_name = 0, ret; m = PyImport_AddModule("__main__"); if (m == NULL) @@ -862,6 +863,7 @@ Py_DECREF(f); return -1; } + set_file_name = 1; Py_DECREF(f); } ext = filename + strlen(filename) - 4; @@ -871,7 +873,8 @@ fclose(fp); if ((fp = fopen(filename, "rb")) == NULL) { fprintf(stderr, "python: Can't reopen .pyc file\n"); - return -1; + ret = -1; + goto done; } /* Turn on optimization if a .pyo file is given */ if (strcmp(ext, ".pyo") == 0) @@ -883,12 +886,17 @@ } if (v == NULL) { PyErr_Print(); - return -1; + ret = -1; + goto done; } Py_DECREF(v); if (Py_FlushLine()) PyErr_Clear(); - return 0; + ret = 0; + done: + if (set_file_name && PyDict_DelItemString(d, "__file__")) + PyErr_Clear(); + return ret; } int From buildbot at python.org Wed Mar 7 02:10:58 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 01:10:58 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable trunk Message-ID: <20070307011058.B6D981E401B@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%2520trunk/builds/128 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl,walter.doerwald Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Wed Mar 7 02:58:18 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 01:58:18 +0000 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk Message-ID: <20070307015818.385851E4002@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%2520trunk/builds/1797 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Wed Mar 7 03:19:21 2007 From: python-checkins at python.org (ka-ping.yee) Date: Wed, 7 Mar 2007 03:19:21 +0100 (CET) Subject: [Python-checkins] r54191 - peps/trunk/pep-3114.txt Message-ID: <20070307021921.139D11E4002@bag.python.org> Author: ka-ping.yee Date: Wed Mar 7 03:19:15 2007 New Revision: 54191 Modified: peps/trunk/pep-3114.txt Log: Update transition plan (according to e-mail from Collin Winter). Modified: peps/trunk/pep-3114.txt ============================================================================== --- peps/trunk/pep-3114.txt (original) +++ peps/trunk/pep-3114.txt Wed Mar 7 03:19:15 2007 @@ -148,8 +148,6 @@ Transition Plan =============== -(This section is likely to be updated.) - Two additional transformations will be added to the 2to3 translation tool [3]_: @@ -159,13 +157,20 @@ to the built-in ``next`` function. For example, ``x.next()`` will become ``next(x)``. -If the module being processed already contains a binding for the name -``next``, the second transformation will not be done; instead, calls to -``x.next()`` will be replaced with ``x.__next__()`` and a warning will -be emitted. (Collin Winter has looked into this [4]_ and found that -it's difficult to make the second transformation depend on the presence -of a module-level binding; warning about the existence of bindings to -``next`` should be possible, though.) +Collin Winter looked into the possibility of automatically deciding +whether to perform the second transformation depending on the presence +of a module-level binding to ``next`` [4]_ and found that it would be +"ugly and slow". Instead, the translation tool will emit warnings +upon detecting such a binding. Collin has proposed warnings for the +following conditions [5]_: + +* Module-level assignments to ``next``. + +* Module-level definitions of a function named ``next``. + +* Module-level imports of the name ``next``. + +* Assignments to ``__builtin__.next``. Approval @@ -189,7 +194,10 @@ .. [4] PEP: rename it.next() to it.__next__()... (Collin Winter) http://mail.python.org/pipermail/python-3000/2007-March/006020.html -.. [5] PEP: rename it.next() to it.__next__()... (Guido van Rossum) +.. [5] PEP 3113 transition plan + http://mail.python.org/pipermail/python-3000/2007-March/006044.html + +.. [6] PEP: rename it.next() to it.__next__()... (Guido van Rossum) http://mail.python.org/pipermail/python-3000/2007-March/006027.html From python-checkins at python.org Wed Mar 7 05:21:25 2007 From: python-checkins at python.org (george.yoshida) Date: Wed, 7 Mar 2007 05:21:25 +0100 (CET) Subject: [Python-checkins] r54192 - python/trunk/Doc/lib/libzipfile.tex Message-ID: <20070307042125.2E1E91E4003@bag.python.org> Author: george.yoshida Date: Wed Mar 7 05:21:18 2007 New Revision: 54192 Modified: python/trunk/Doc/lib/libzipfile.tex Log: add versionadded info Modified: python/trunk/Doc/lib/libzipfile.tex ============================================================================== --- python/trunk/Doc/lib/libzipfile.tex (original) +++ python/trunk/Doc/lib/libzipfile.tex Wed Mar 7 05:21:18 2007 @@ -165,6 +165,8 @@ by the ZipExtFile, allowing it to operate independently of the ZipFile. \end{notice} + + \versionadded{2.6} \end{methoddesc} \begin{methoddesc}{printdir}{} From python-checkins at python.org Wed Mar 7 05:46:28 2007 From: python-checkins at python.org (patrick.maupin) Date: Wed, 7 Mar 2007 05:46:28 +0100 (CET) Subject: [Python-checkins] r54193 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070307044628.DC8751E4003@bag.python.org> Author: patrick.maupin Date: Wed Mar 7 05:46:21 2007 New Revision: 54193 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Found/fixed bug with useall and no keyword dictionary Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Wed Mar 7 05:46:21 2007 @@ -350,6 +350,8 @@ self.formatEquals(result, s, 'a', 'b', bar=bar, foo=1) self.formatEquals(result, s, 'a', 'b', bar=bar, foo=1, sam=27) self.formatRaises(ValueError, s2, 'a', 'b', bar=bar, foo=1, sam=27) + self.formatRaises(ValueError, '{!useall}', 1) + self.formatRaises(ValueError, '{!useall}', foo=1) def test_comments(self): self.formatEquals('Hi there','''{#Comment}Hi{# Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Wed Mar 7 05:46:21 2007 @@ -2113,7 +2113,7 @@ PyObject *used = fs->keyword_arg_set; if (result != NULL) { num_unused = fs->positional_arg_set; - if (!num_unused) { + if (!num_unused && (used != NULL)) { num_unused = PySet_GET_SIZE(used); i = 0; while (num_unused && (ignore[i] != NULL)) { @@ -2132,7 +2132,7 @@ result = SetError(fs, "Not all arguments consumed"); } } - Py_DECREF(used); + Py_XDECREF(used); return result; } @@ -2151,12 +2151,16 @@ fs.max_recursion = 4; fs.do_markup = do_markup; + /* XXX -- I really want to say fs.keywords = keywords, + but this exposes a different set of potential bugs... */ + fs.keywords = (keywords != NULL && PyDict_Size(keywords)) + ? keywords : NULL; fs.keywords = keywords; result = build_string(&fs); Py_XDECREF(fs.keywords_tuple); Py_XDECREF(fs.hookfunc); - return (fs.keyword_arg_set != NULL) + return ((fs.keyword_arg_set != NULL) || fs.positional_arg_set) ? check_args_consumed(&fs, result) : result; } From python-checkins at python.org Wed Mar 7 08:39:08 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 08:39:08 +0100 (CET) Subject: [Python-checkins] r54195 - python/trunk/Lib/urllib2.py Message-ID: <20070307073908.7C2DA1E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 08:39:06 2007 New Revision: 54195 Modified: python/trunk/Lib/urllib2.py Log: Patch #812285: allow multiple auth schemes in AbstractBasicAuthHandler. Modified: python/trunk/Lib/urllib2.py ============================================================================== --- python/trunk/Lib/urllib2.py (original) +++ python/trunk/Lib/urllib2.py Wed Mar 7 08:39:06 2007 @@ -767,11 +767,10 @@ class AbstractBasicAuthHandler: - rx = re.compile('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', re.I) + # XXX this allows for multiple auth-schemes, but will stupidly pick + # the last one with a realm specified. - # XXX there can actually be multiple auth-schemes in a - # www-authenticate header. should probably be a lot more careful - # in parsing them to extract multiple alternatives + rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', re.I) # XXX could pre-emptively send auth info already accepted (RFC 2617, # end of section 2, and section 1.2 immediately after "credentials" From python-checkins at python.org Wed Mar 7 08:39:17 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 08:39:17 +0100 (CET) Subject: [Python-checkins] r54196 - python/branches/release25-maint/Lib/urllib2.py Message-ID: <20070307073917.23AC11E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 08:39:13 2007 New Revision: 54196 Modified: python/branches/release25-maint/Lib/urllib2.py Log: Patch #812285: allow multiple auth schemes in AbstractBasicAuthHandler. (backport from rev. 54195) Modified: python/branches/release25-maint/Lib/urllib2.py ============================================================================== --- python/branches/release25-maint/Lib/urllib2.py (original) +++ python/branches/release25-maint/Lib/urllib2.py Wed Mar 7 08:39:13 2007 @@ -766,11 +766,10 @@ class AbstractBasicAuthHandler: - rx = re.compile('[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', re.I) + # XXX this allows for multiple auth-schemes, but will stupidly pick + # the last one with a realm specified. - # XXX there can actually be multiple auth-schemes in a - # www-authenticate header. should probably be a lot more careful - # in parsing them to extract multiple alternatives + rx = re.compile('(?:.*,)*[ \t]*([^ \t]+)[ \t]+realm="([^"]*)"', re.I) # XXX could pre-emptively send auth info already accepted (RFC 2617, # end of section 2, and section 1.2 immediately after "credentials" From python-checkins at python.org Wed Mar 7 09:31:53 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 09:31:53 +0100 (CET) Subject: [Python-checkins] r54197 - in python/trunk: Lib/glob.py Lib/test/test_glob.py Misc/NEWS Message-ID: <20070307083153.578C41E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 09:31:51 2007 New Revision: 54197 Modified: python/trunk/Lib/glob.py python/trunk/Lib/test/test_glob.py python/trunk/Misc/NEWS Log: Patch #1001604: glob.glob() now returns unicode filenames if it was given a unicode argument and os.listdir() returns unicode filenames. Modified: python/trunk/Lib/glob.py ============================================================================== --- python/trunk/Lib/glob.py (original) +++ python/trunk/Lib/glob.py Wed Mar 7 09:31:51 2007 @@ -1,8 +1,9 @@ """Filename globbing utility.""" +import sys import os -import fnmatch import re +import fnmatch __all__ = ["glob", "iglob"] @@ -48,13 +49,15 @@ def glob1(dirname, pattern): if not dirname: dirname = os.curdir + if isinstance(pattern, unicode) and not isinstance(dirname, unicode): + dirname = unicode(dirname, sys.getfilesystemencoding()) try: names = os.listdir(dirname) except os.error: return [] - if pattern[0]!='.': - names=filter(lambda x: x[0]!='.',names) - return fnmatch.filter(names,pattern) + if pattern[0] != '.': + names = filter(lambda x: x[0] != '.', names) + return fnmatch.filter(names, pattern) def glob0(dirname, basename): if basename == '': Modified: python/trunk/Lib/test/test_glob.py ============================================================================== --- python/trunk/Lib/test/test_glob.py (original) +++ python/trunk/Lib/test/test_glob.py Wed Mar 7 09:31:51 2007 @@ -52,6 +52,16 @@ eq(self.glob('aab'), [self.norm('aab')]) eq(self.glob('zymurgy'), []) + # test return types are unicode, but only if os.listdir + # returns unicode filenames + uniset = set([unicode]) + tmp = os.listdir(u'.') + if set(type(x) for x in tmp) == uniset: + u1 = glob.glob(u'*') + u2 = glob.glob(u'./*') + self.assertEquals(set(type(r) for r in u1), uniset) + self.assertEquals(set(type(r) for r in u2), uniset) + def test_glob_one_directory(self): eq = self.assertSequencesEqual_noorder eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa'])) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 7 09:31:51 2007 @@ -152,6 +152,9 @@ Library ------- +- Patch #1001604: glob.glob() now returns unicode filenames if it was + given a unicode argument and os.listdir() returns unicode filenames. + - Patch #1673619: setup.py identifies extension modules it doesn't know how to build and those it knows how to build but that fail to build. From python-checkins at python.org Wed Mar 7 09:32:26 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 09:32:26 +0100 (CET) Subject: [Python-checkins] r54198 - in python/branches/release25-maint: Lib/glob.py Lib/test/test_glob.py Misc/NEWS Message-ID: <20070307083226.905111E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 09:32:24 2007 New Revision: 54198 Modified: python/branches/release25-maint/Lib/glob.py python/branches/release25-maint/Lib/test/test_glob.py python/branches/release25-maint/Misc/NEWS Log: Patch #1001604: glob.glob() now returns unicode filenames if it was given a unicode argument and os.listdir() returns unicode filenames. (backport from rev. 54197) Modified: python/branches/release25-maint/Lib/glob.py ============================================================================== --- python/branches/release25-maint/Lib/glob.py (original) +++ python/branches/release25-maint/Lib/glob.py Wed Mar 7 09:32:24 2007 @@ -1,8 +1,9 @@ """Filename globbing utility.""" +import sys import os -import fnmatch import re +import fnmatch __all__ = ["glob", "iglob"] @@ -48,13 +49,15 @@ def glob1(dirname, pattern): if not dirname: dirname = os.curdir + if isinstance(pattern, unicode) and not isinstance(dirname, unicode): + dirname = unicode(dirname, sys.getfilesystemencoding()) try: names = os.listdir(dirname) except os.error: return [] - if pattern[0]!='.': - names=filter(lambda x: x[0]!='.',names) - return fnmatch.filter(names,pattern) + if pattern[0] != '.': + names = filter(lambda x: x[0] != '.', names) + return fnmatch.filter(names, pattern) def glob0(dirname, basename): if basename == '': Modified: python/branches/release25-maint/Lib/test/test_glob.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_glob.py (original) +++ python/branches/release25-maint/Lib/test/test_glob.py Wed Mar 7 09:32:24 2007 @@ -52,6 +52,16 @@ eq(self.glob('aab'), [self.norm('aab')]) eq(self.glob('zymurgy'), []) + # test return types are unicode, but only if os.listdir + # returns unicode filenames + uniset = set([unicode]) + tmp = os.listdir(u'.') + if set(type(x) for x in tmp) == uniset: + u1 = glob.glob(u'*') + u2 = glob.glob(u'./*') + self.assertEquals(set(type(r) for r in u1), uniset) + self.assertEquals(set(type(r) for r in u2), uniset) + def test_glob_one_directory(self): eq = self.assertSequencesEqual_noorder eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa'])) Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Wed Mar 7 09:32:24 2007 @@ -197,6 +197,9 @@ Library ------- +- Patch #1001604: glob.glob() now returns unicode filenames if it was + given a unicode argument and os.listdir() returns unicode filenames. + - Patch #685268: Consider a package's __path__ in imputil. - Patch 1463026: Support default namespace in XMLGenerator. From buildbot at python.org Wed Mar 7 09:40:03 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 08:40:03 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 2.5 Message-ID: <20070307084003.EDAC11E4010@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%25202.5/builds/190 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl,walter.doerwald Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_operator ====================================================================== ERROR: test_delslice (test.test_operator.OperatorTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/net/ringneck/scratch1/nnorwitz/python/2.5.norwitz-tru64/build/Lib/test/test_operator.py", line 146, in test_delslice operator.delslice(a, 0, test_support.MAX_Py_ssize_t) OverflowError: signed integer is greater than maximum ====================================================================== ERROR: test_getslice (test.test_operator.OperatorTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/net/ringneck/scratch1/nnorwitz/python/2.5.norwitz-tru64/build/Lib/test/test_operator.py", line 175, in test_getslice b = operator.getslice(a, 0, test_support.MAX_Py_ssize_t) OverflowError: signed integer is greater than maximum ====================================================================== ERROR: test_setslice (test.test_operator.OperatorTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/net/ringneck/scratch1/nnorwitz/python/2.5.norwitz-tru64/build/Lib/test/test_operator.py", line 325, in test_setslice operator.setslice(a, 0, test_support.MAX_Py_ssize_t, []) OverflowError: signed integer is greater than maximum sincerely, -The Buildbot From python-checkins at python.org Wed Mar 7 10:09:49 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 10:09:49 +0100 (CET) Subject: [Python-checkins] r54199 - in python/trunk: Lib/test/test_unittest.py Lib/unittest.py Misc/NEWS Message-ID: <20070307090949.BF7081E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 10:09:40 2007 New Revision: 54199 Modified: python/trunk/Lib/test/test_unittest.py python/trunk/Lib/unittest.py python/trunk/Misc/NEWS Log: Patches #1550273, #1550272: fix a few bugs in unittest and add a comprehensive test suite for the module. Modified: python/trunk/Lib/test/test_unittest.py ============================================================================== --- python/trunk/Lib/test/test_unittest.py (original) +++ python/trunk/Lib/test/test_unittest.py Wed Mar 7 10:09:40 2007 @@ -1,31 +1,2289 @@ """Test script for unittest. -This just includes tests for new features. We really need a -full set of tests. +By Collin Winter + +Still need testing: + TestCase.{assert,fail}* methods (some are tested implicitly) """ +from test import test_support import unittest +from unittest import TestCase + +### Support code +################################################################ + +class LoggingResult(unittest.TestResult): + def __init__(self, log): + self._events = log + super(LoggingResult, self).__init__() + + def startTest(self, test): + self._events.append('startTest') + super(LoggingResult, self).startTest(test) + + def stopTest(self, test): + self._events.append('stopTest') + super(LoggingResult, self).stopTest(test) + + def addFailure(self, *args): + self._events.append('addFailure') + super(LoggingResult, self).addFailure(*args) + + def addError(self, *args): + self._events.append('addError') + super(LoggingResult, self).addError(*args) + +class TestEquality(object): + # Check for a valid __eq__ implementation + def test_eq(self): + for obj_1, obj_2 in self.eq_pairs: + self.assertEqual(obj_1, obj_2) + self.assertEqual(obj_2, obj_1) + + # Check for a valid __ne__ implementation + def test_ne(self): + for obj_1, obj_2 in self.ne_pairs: + self.failIfEqual(obj_1, obj_2) + self.failIfEqual(obj_2, obj_1) + +class TestHashing(object): + # Check for a valid __hash__ implementation + def test_hash(self): + for obj_1, obj_2 in self.eq_pairs: + try: + assert hash(obj_1) == hash(obj_2) + except KeyboardInterrupt: + raise + except AssertionError: + self.fail("%s and %s do not hash equal" % (obj_1, obj_2)) + except Exception, e: + self.fail("Problem hashing %s and %s: %s" % (obj_1, obj_2, e)) + + for obj_1, obj_2 in self.ne_pairs: + try: + assert hash(obj_1) != hash(obj_2) + except KeyboardInterrupt: + raise + except AssertionError: + self.fail("%s and %s hash equal, but shouldn't" % (obj_1, obj_2)) + except Exception, e: + self.fail("Problem hashing %s and %s: %s" % (obj_1, obj_2, e)) + + +################################################################ +### /Support code + +class Test_TestLoader(TestCase): + + ### Tests for TestLoader.loadTestsFromTestCase + ################################################################ + + # "Return a suite of all tests cases contained in the TestCase-derived + # class testCaseClass" + def test_loadTestsFromTestCase(self): + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foo_bar(self): pass + + tests = unittest.TestSuite([Foo('test_1'), Foo('test_2')]) + + loader = unittest.TestLoader() + self.assertEqual(loader.loadTestsFromTestCase(Foo), tests) + + # "Return a suite of all tests cases contained in the TestCase-derived + # class testCaseClass" + # + # Make sure it does the right thing even if no tests were found + def test_loadTestsFromTestCase__no_matches(self): + class Foo(unittest.TestCase): + def foo_bar(self): pass + + empty_suite = unittest.TestSuite() + + loader = unittest.TestLoader() + self.assertEqual(loader.loadTestsFromTestCase(Foo), empty_suite) + + # "Return a suite of all tests cases contained in the TestCase-derived + # class testCaseClass" + # + # What happens if loadTestsFromTestCase() is given an object + # that isn't a subclass of TestCase? Specifically, what happens + # if testCaseClass is a subclass of TestSuite? + # + # This is checked for specifically in the code, so we better add a + # test for it. + def test_loadTestsFromTestCase__TestSuite_subclass(self): + class NotATestCase(unittest.TestSuite): + pass + + loader = unittest.TestLoader() + try: + loader.loadTestsFromTestCase(NotATestCase) + except TypeError: + pass + else: + self.fail('Should raise TypeError') + + # "Return a suite of all tests cases contained in the TestCase-derived + # class testCaseClass" + # + # Make sure loadTestsFromTestCase() picks up the default test method + # name (as specified by TestCase), even though the method name does + # not match the default TestLoader.testMethodPrefix string + def test_loadTestsFromTestCase__default_method_name(self): + class Foo(unittest.TestCase): + def runTest(self): + pass + + loader = unittest.TestLoader() + # This has to be false for the test to succeed + self.failIf('runTest'.startswith(loader.testMethodPrefix)) + + suite = loader.loadTestsFromTestCase(Foo) + self.failUnless(isinstance(suite, loader.suiteClass)) + self.assertEqual(list(suite), [Foo('runTest')]) + + ################################################################ + ### /Tests for TestLoader.loadTestsFromTestCase + + ### Tests for TestLoader.loadTestsFromModule + ################################################################ + + # "This method searches `module` for classes derived from TestCase" + def test_loadTestsFromModule__TestCase_subclass(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + def test(self): + pass + m.testcase_1 = MyTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromModule(m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + expected = [loader.suiteClass([MyTestCase('test')])] + self.assertEqual(list(suite), expected) + + # "This method searches `module` for classes derived from TestCase" + # + # What happens if no tests are found (no TestCase instances)? + def test_loadTestsFromModule__no_TestCase_instances(self): + import new + m = new.module('m') + + loader = unittest.TestLoader() + suite = loader.loadTestsFromModule(m) + self.failUnless(isinstance(suite, loader.suiteClass)) + self.assertEqual(list(suite), []) + + # "This method searches `module` for classes derived from TestCase" + # + # What happens if no tests are found (TestCases instances, but no tests)? + def test_loadTestsFromModule__no_TestCase_tests(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + pass + m.testcase_1 = MyTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromModule(m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + self.assertEqual(list(suite), [loader.suiteClass()]) + + # "This method searches `module` for classes derived from TestCase"s + # + # What happens if loadTestsFromModule() is given something other + # than a module? + # + # XXX Currently, it succeeds anyway. This flexibility + # should either be documented or loadTestsFromModule() should + # raise a TypeError + # + # XXX Certain people are using this behaviour. We'll add a test for it + def test_loadTestsFromModule__not_a_module(self): + class MyTestCase(unittest.TestCase): + def test(self): + pass + + class NotAModule(object): + test_2 = MyTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromModule(NotAModule) + + reference = [unittest.TestSuite([MyTestCase('test')])] + self.assertEqual(list(suite), reference) + + ################################################################ + ### /Tests for TestLoader.loadTestsFromModule() + + ### Tests for TestLoader.loadTestsFromName() + ################################################################ + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # Is ValueError raised in response to an empty name? + def test_loadTestsFromName__empty_name(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromName('') + except ValueError, e: + self.assertEqual(str(e), "Empty module name") + else: + self.fail("TestLoader.loadTestsFromName failed to raise ValueError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # What happens when the name contains invalid characters? + def test_loadTestsFromName__malformed_name(self): + loader = unittest.TestLoader() + + # XXX Should this raise ValueError or ImportError? + try: + loader.loadTestsFromName('abc () //') + except ValueError: + pass + except ImportError: + pass + else: + self.fail("TestLoader.loadTestsFromName failed to raise ValueError") + + # "The specifier name is a ``dotted name'' that may resolve ... to a + # module" + # + # What happens when a module by that name can't be found? + def test_loadTestsFromName__unknown_module_name(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromName('sdasfasfasdf') + except ImportError, e: + self.assertEqual(str(e), "No module named sdasfasfasdf") + else: + self.fail("TestLoader.loadTestsFromName failed to raise ImportError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # What happens when the module is found, but the attribute can't? + def test_loadTestsFromName__unknown_attr_name(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromName('unittest.sdasfasfasdf') + except AttributeError, e: + self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") + else: + self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # What happens when we provide the module, but the attribute can't be + # found? + def test_loadTestsFromName__relative_unknown_name(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromName('sdasfasfasdf', unittest) + except AttributeError, e: + self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") + else: + self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # ... + # "The method optionally resolves name relative to the given module" + # + # Does loadTestsFromName raise ValueError when passed an empty + # name relative to a provided module? + # + # XXX Should probably raise a ValueError instead of an AttributeError + def test_loadTestsFromName__relative_empty_name(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromName('', unittest) + except AttributeError, e: + pass + else: + self.fail("Failed to raise AttributeError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # ... + # "The method optionally resolves name relative to the given module" + # + # What happens when an impossible name is given, relative to the provided + # `module`? + def test_loadTestsFromName__relative_malformed_name(self): + loader = unittest.TestLoader() + + # XXX Should this raise AttributeError or ValueError? + try: + loader.loadTestsFromName('abc () //', unittest) + except ValueError: + pass + except AttributeError: + pass + else: + self.fail("TestLoader.loadTestsFromName failed to raise ValueError") + + # "The method optionally resolves name relative to the given module" + # + # Does loadTestsFromName raise TypeError when the `module` argument + # isn't a module object? + # + # XXX Accepts the not-a-module object, ignorning the object's type + # This should raise an exception or the method name should be changed + # + # XXX Some people are relying on this, so keep it for now + def test_loadTestsFromName__relative_not_a_module(self): + class MyTestCase(unittest.TestCase): + def test(self): + pass + + class NotAModule(object): + test_2 = MyTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromName('test_2', NotAModule) + + reference = [MyTestCase('test')] + self.assertEqual(list(suite), reference) + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # Does it raise an exception if the name resolves to an invalid + # object? + def test_loadTestsFromName__relative_bad_object(self): + import new + m = new.module('m') + m.testcase_1 = object() + + loader = unittest.TestLoader() + try: + loader.loadTestsFromName('testcase_1', m) + except TypeError: + pass + else: + self.fail("Should have raised TypeError") + + # "The specifier name is a ``dotted name'' that may + # resolve either to ... a test case class" + def test_loadTestsFromName__relative_TestCase_subclass(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + def test(self): + pass + m.testcase_1 = MyTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromName('testcase_1', m) + self.failUnless(isinstance(suite, loader.suiteClass)) + self.assertEqual(list(suite), [MyTestCase('test')]) + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + def test_loadTestsFromName__relative_TestSuite(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + def test(self): + pass + m.testsuite = unittest.TestSuite([MyTestCase('test')]) + + loader = unittest.TestLoader() + suite = loader.loadTestsFromName('testsuite', m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + self.assertEqual(list(suite), [MyTestCase('test')]) + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a test method within a test case class" + def test_loadTestsFromName__relative_testmethod(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + def test(self): + pass + m.testcase_1 = MyTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromName('testcase_1.test', m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + self.assertEqual(list(suite), [MyTestCase('test')]) + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # Does loadTestsFromName() raise the proper exception when trying to + # resolve "a test method within a test case class" that doesn't exist + # for the given name (relative to a provided module)? + def test_loadTestsFromName__relative_invalid_testmethod(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + def test(self): + pass + m.testcase_1 = MyTestCase + + loader = unittest.TestLoader() + try: + loader.loadTestsFromName('testcase_1.testfoo', m) + except AttributeError, e: + self.assertEqual(str(e), "type object 'MyTestCase' has no attribute 'testfoo'") + else: + self.fail("Failed to raise AttributeError") + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a callable object which returns a ... TestSuite instance" + def test_loadTestsFromName__callable__TestSuite(self): + import new + m = new.module('m') + testcase_1 = unittest.FunctionTestCase(lambda: None) + testcase_2 = unittest.FunctionTestCase(lambda: None) + def return_TestSuite(): + return unittest.TestSuite([testcase_1, testcase_2]) + m.return_TestSuite = return_TestSuite + + loader = unittest.TestLoader() + suite = loader.loadTestsFromName('return_TestSuite', m) + self.failUnless(isinstance(suite, loader.suiteClass)) + self.assertEqual(list(suite), [testcase_1, testcase_2]) + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a callable object which returns a TestCase ... instance" + def test_loadTestsFromName__callable__TestCase_instance(self): + import new + m = new.module('m') + testcase_1 = unittest.FunctionTestCase(lambda: None) + def return_TestCase(): + return testcase_1 + m.return_TestCase = return_TestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromName('return_TestCase', m) + self.failUnless(isinstance(suite, loader.suiteClass)) + self.assertEqual(list(suite), [testcase_1]) + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a callable object which returns a TestCase or TestSuite instance" + # + # What happens if the callable returns something else? + def test_loadTestsFromName__callable__wrong_type(self): + import new + m = new.module('m') + def return_wrong(): + return 6 + m.return_wrong = return_wrong + + loader = unittest.TestLoader() + try: + suite = loader.loadTestsFromName('return_wrong', m) + except TypeError: + pass + else: + self.fail("TestLoader.loadTestsFromName failed to raise TypeError") + + # "The specifier can refer to modules and packages which have not been + # imported; they will be imported as a side-effect" + def test_loadTestsFromName__module_not_loaded(self): + # We're going to try to load this module as a side-effect, so it + # better not be loaded before we try. + # + # Why pick audioop? Google shows it isn't used very often, so there's + # a good chance that it won't be imported when this test is run + module_name = 'audioop' + + import sys + if module_name in sys.modules: + del sys.modules[module_name] + + loader = unittest.TestLoader() + try: + suite = loader.loadTestsFromName(module_name) + + self.failUnless(isinstance(suite, loader.suiteClass)) + self.assertEqual(list(suite), []) + + # audioop should now be loaded, thanks to loadTestsFromName() + self.failUnless(module_name in sys.modules) + finally: + del sys.modules[module_name] + + ################################################################ + ### Tests for TestLoader.loadTestsFromName() + + ### Tests for TestLoader.loadTestsFromNames() + ################################################################ + + # "Similar to loadTestsFromName(), but takes a sequence of names rather + # than a single name." + # + # What happens if that sequence of names is empty? + def test_loadTestsFromNames__empty_name_list(self): + loader = unittest.TestLoader() + + suite = loader.loadTestsFromNames([]) + self.failUnless(isinstance(suite, loader.suiteClass)) + self.assertEqual(list(suite), []) + + # "Similar to loadTestsFromName(), but takes a sequence of names rather + # than a single name." + # ... + # "The method optionally resolves name relative to the given module" + # + # What happens if that sequence of names is empty? + # + # XXX Should this raise a ValueError or just return an empty TestSuite? + def test_loadTestsFromNames__relative_empty_name_list(self): + loader = unittest.TestLoader() + + suite = loader.loadTestsFromNames([], unittest) + self.failUnless(isinstance(suite, loader.suiteClass)) + self.assertEqual(list(suite), []) + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # Is ValueError raised in response to an empty name? + def test_loadTestsFromNames__empty_name(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromNames(['']) + except ValueError, e: + self.assertEqual(str(e), "Empty module name") + else: + self.fail("TestLoader.loadTestsFromNames failed to raise ValueError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # What happens when presented with an impossible module name? + def test_loadTestsFromNames__malformed_name(self): + loader = unittest.TestLoader() + + # XXX Should this raise ValueError or ImportError? + try: + loader.loadTestsFromNames(['abc () //']) + except ValueError: + pass + except ImportError: + pass + else: + self.fail("TestLoader.loadTestsFromNames failed to raise ValueError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # What happens when no module can be found for the given name? + def test_loadTestsFromNames__unknown_module_name(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromNames(['sdasfasfasdf']) + except ImportError, e: + self.assertEqual(str(e), "No module named sdasfasfasdf") + else: + self.fail("TestLoader.loadTestsFromNames failed to raise ImportError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # What happens when the module can be found, but not the attribute? + def test_loadTestsFromNames__unknown_attr_name(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromNames(['unittest.sdasfasfasdf', 'unittest']) + except AttributeError, e: + self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") + else: + self.fail("TestLoader.loadTestsFromNames failed to raise AttributeError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # ... + # "The method optionally resolves name relative to the given module" + # + # What happens when given an unknown attribute on a specified `module` + # argument? + def test_loadTestsFromNames__unknown_name_relative_1(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromNames(['sdasfasfasdf'], unittest) + except AttributeError, e: + self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") + else: + self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # ... + # "The method optionally resolves name relative to the given module" + # + # Do unknown attributes (relative to a provided module) still raise an + # exception even in the presence of valid attribute names? + def test_loadTestsFromNames__unknown_name_relative_2(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromNames(['TestCase', 'sdasfasfasdf'], unittest) + except AttributeError, e: + self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") + else: + self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # ... + # "The method optionally resolves name relative to the given module" + # + # What happens when faced with the empty string? + # + # XXX This currently raises AttributeError, though ValueError is probably + # more appropriate + def test_loadTestsFromNames__relative_empty_name(self): + loader = unittest.TestLoader() + + try: + loader.loadTestsFromNames([''], unittest) + except AttributeError: + pass + else: + self.fail("Failed to raise ValueError") + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # ... + # "The method optionally resolves name relative to the given module" + # + # What happens when presented with an impossible attribute name? + def test_loadTestsFromNames__relative_malformed_name(self): + loader = unittest.TestLoader() + + # XXX Should this raise AttributeError or ValueError? + try: + loader.loadTestsFromNames(['abc () //'], unittest) + except AttributeError: + pass + except ValueError: + pass + else: + self.fail("TestLoader.loadTestsFromNames failed to raise ValueError") + + # "The method optionally resolves name relative to the given module" + # + # Does loadTestsFromNames() make sure the provided `module` is in fact + # a module? + # + # XXX This validation is currently not done. This flexibility should + # either be documented or a TypeError should be raised. + def test_loadTestsFromNames__relative_not_a_module(self): + class MyTestCase(unittest.TestCase): + def test(self): + pass + + class NotAModule(object): + test_2 = MyTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromNames(['test_2'], NotAModule) + + reference = [unittest.TestSuite([MyTestCase('test')])] + self.assertEqual(list(suite), reference) + + # "The specifier name is a ``dotted name'' that may resolve either to + # a module, a test case class, a TestSuite instance, a test method + # within a test case class, or a callable object which returns a + # TestCase or TestSuite instance." + # + # Does it raise an exception if the name resolves to an invalid + # object? + def test_loadTestsFromNames__relative_bad_object(self): + import new + m = new.module('m') + m.testcase_1 = object() + + loader = unittest.TestLoader() + try: + loader.loadTestsFromNames(['testcase_1'], m) + except TypeError: + pass + else: + self.fail("Should have raised TypeError") + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a test case class" + def test_loadTestsFromNames__relative_TestCase_subclass(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + def test(self): + pass + m.testcase_1 = MyTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromNames(['testcase_1'], m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + expected = loader.suiteClass([MyTestCase('test')]) + self.assertEqual(list(suite), [expected]) + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a TestSuite instance" + def test_loadTestsFromNames__relative_TestSuite(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + def test(self): + pass + m.testsuite = unittest.TestSuite([MyTestCase('test')]) + + loader = unittest.TestLoader() + suite = loader.loadTestsFromNames(['testsuite'], m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + self.assertEqual(list(suite), [m.testsuite]) + + # "The specifier name is a ``dotted name'' that may resolve ... to ... a + # test method within a test case class" + def test_loadTestsFromNames__relative_testmethod(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + def test(self): + pass + m.testcase_1 = MyTestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromNames(['testcase_1.test'], m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + ref_suite = unittest.TestSuite([MyTestCase('test')]) + self.assertEqual(list(suite), [ref_suite]) + + # "The specifier name is a ``dotted name'' that may resolve ... to ... a + # test method within a test case class" + # + # Does the method gracefully handle names that initially look like they + # resolve to "a test method within a test case class" but don't? + def test_loadTestsFromNames__relative_invalid_testmethod(self): + import new + m = new.module('m') + class MyTestCase(unittest.TestCase): + def test(self): + pass + m.testcase_1 = MyTestCase + + loader = unittest.TestLoader() + try: + loader.loadTestsFromNames(['testcase_1.testfoo'], m) + except AttributeError, e: + self.assertEqual(str(e), "type object 'MyTestCase' has no attribute 'testfoo'") + else: + self.fail("Failed to raise AttributeError") + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a callable object which returns a ... TestSuite instance" + def test_loadTestsFromNames__callable__TestSuite(self): + import new + m = new.module('m') + testcase_1 = unittest.FunctionTestCase(lambda: None) + testcase_2 = unittest.FunctionTestCase(lambda: None) + def return_TestSuite(): + return unittest.TestSuite([testcase_1, testcase_2]) + m.return_TestSuite = return_TestSuite + + loader = unittest.TestLoader() + suite = loader.loadTestsFromNames(['return_TestSuite'], m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + expected = unittest.TestSuite([testcase_1, testcase_2]) + self.assertEqual(list(suite), [expected]) + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a callable object which returns a TestCase ... instance" + def test_loadTestsFromNames__callable__TestCase_instance(self): + import new + m = new.module('m') + testcase_1 = unittest.FunctionTestCase(lambda: None) + def return_TestCase(): + return testcase_1 + m.return_TestCase = return_TestCase + + loader = unittest.TestLoader() + suite = loader.loadTestsFromNames(['return_TestCase'], m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + ref_suite = unittest.TestSuite([testcase_1]) + self.assertEqual(list(suite), [ref_suite]) + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a callable object which returns a TestCase or TestSuite instance" + # + # Are staticmethods handled correctly? + def test_loadTestsFromNames__callable__call_staticmethod(self): + import new + m = new.module('m') + class Test1(unittest.TestCase): + def test(self): + pass + + testcase_1 = Test1('test') + class Foo(unittest.TestCase): + @staticmethod + def foo(): + return testcase_1 + m.Foo = Foo + + loader = unittest.TestLoader() + suite = loader.loadTestsFromNames(['Foo.foo'], m) + self.failUnless(isinstance(suite, loader.suiteClass)) + + ref_suite = unittest.TestSuite([testcase_1]) + self.assertEqual(list(suite), [ref_suite]) + + # "The specifier name is a ``dotted name'' that may resolve ... to + # ... a callable object which returns a TestCase or TestSuite instance" + # + # What happens when the callable returns something else? + def test_loadTestsFromNames__callable__wrong_type(self): + import new + m = new.module('m') + def return_wrong(): + return 6 + m.return_wrong = return_wrong + + loader = unittest.TestLoader() + try: + suite = loader.loadTestsFromNames(['return_wrong'], m) + except TypeError: + pass + else: + self.fail("TestLoader.loadTestsFromNames failed to raise TypeError") + + # "The specifier can refer to modules and packages which have not been + # imported; they will be imported as a side-effect" + def test_loadTestsFromNames__module_not_loaded(self): + # We're going to try to load this module as a side-effect, so it + # better not be loaded before we try. + # + # Why pick audioop? Google shows it isn't used very often, so there's + # a good chance that it won't be imported when this test is run + module_name = 'audioop' + + import sys + if module_name in sys.modules: + del sys.modules[module_name] + + loader = unittest.TestLoader() + try: + suite = loader.loadTestsFromNames([module_name]) + + self.failUnless(isinstance(suite, loader.suiteClass)) + self.assertEqual(list(suite), [unittest.TestSuite()]) + + # audioop should now be loaded, thanks to loadTestsFromName() + self.failUnless(module_name in sys.modules) + finally: + del sys.modules[module_name] + + ################################################################ + ### /Tests for TestLoader.loadTestsFromNames() + + ### Tests for TestLoader.getTestCaseNames() + ################################################################ + + # "Return a sorted sequence of method names found within testCaseClass" + # + # Test.foobar is defined to make sure getTestCaseNames() respects + # loader.testMethodPrefix + def test_getTestCaseNames(self): + class Test(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foobar(self): pass + + loader = unittest.TestLoader() + + self.assertEqual(loader.getTestCaseNames(Test), ['test_1', 'test_2']) + + # "Return a sorted sequence of method names found within testCaseClass" + # + # Does getTestCaseNames() behave appropriately if no tests are found? + def test_getTestCaseNames__no_tests(self): + class Test(unittest.TestCase): + def foobar(self): pass + + loader = unittest.TestLoader() + + self.assertEqual(loader.getTestCaseNames(Test), []) + + # "Return a sorted sequence of method names found within testCaseClass" + # + # Are not-TestCases handled gracefully? + # + # XXX This should raise a TypeError, not return a list + # + # XXX It's too late in the 2.5 release cycle to fix this, but it should + # probably be revisited for 2.6 + def test_getTestCaseNames__not_a_TestCase(self): + class BadCase(int): + def test_foo(self): + pass + + loader = unittest.TestLoader() + names = loader.getTestCaseNames(BadCase) + + self.assertEqual(names, ['test_foo']) + + # "Return a sorted sequence of method names found within testCaseClass" + # + # Make sure inherited names are handled. + # + # TestP.foobar is defined to make sure getTestCaseNames() respects + # loader.testMethodPrefix + def test_getTestCaseNames__inheritance(self): + class TestP(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foobar(self): pass + + class TestC(TestP): + def test_1(self): pass + def test_3(self): pass + + loader = unittest.TestLoader() + + names = ['test_1', 'test_2', 'test_3'] + self.assertEqual(loader.getTestCaseNames(TestC), names) + + ################################################################ + ### /Tests for TestLoader.getTestCaseNames() + + ### Tests for TestLoader.testMethodPrefix + ################################################################ + + # "String giving the prefix of method names which will be interpreted as + # test methods" + # + # Implicit in the documentation is that testMethodPrefix is respected by + # all loadTestsFrom* methods. + def test_testMethodPrefix__loadTestsFromTestCase(self): + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foo_bar(self): pass + + tests_1 = unittest.TestSuite([Foo('foo_bar')]) + tests_2 = unittest.TestSuite([Foo('test_1'), Foo('test_2')]) + + loader = unittest.TestLoader() + loader.testMethodPrefix = 'foo' + self.assertEqual(loader.loadTestsFromTestCase(Foo), tests_1) + + loader.testMethodPrefix = 'test' + self.assertEqual(loader.loadTestsFromTestCase(Foo), tests_2) + + # "String giving the prefix of method names which will be interpreted as + # test methods" + # + # Implicit in the documentation is that testMethodPrefix is respected by + # all loadTestsFrom* methods. + def test_testMethodPrefix__loadTestsFromModule(self): + import new + m = new.module('m') + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foo_bar(self): pass + m.Foo = Foo + + tests_1 = [unittest.TestSuite([Foo('foo_bar')])] + tests_2 = [unittest.TestSuite([Foo('test_1'), Foo('test_2')])] + + loader = unittest.TestLoader() + loader.testMethodPrefix = 'foo' + self.assertEqual(list(loader.loadTestsFromModule(m)), tests_1) + + loader.testMethodPrefix = 'test' + self.assertEqual(list(loader.loadTestsFromModule(m)), tests_2) + + # "String giving the prefix of method names which will be interpreted as + # test methods" + # + # Implicit in the documentation is that testMethodPrefix is respected by + # all loadTestsFrom* methods. + def test_testMethodPrefix__loadTestsFromName(self): + import new + m = new.module('m') + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foo_bar(self): pass + m.Foo = Foo + + tests_1 = unittest.TestSuite([Foo('foo_bar')]) + tests_2 = unittest.TestSuite([Foo('test_1'), Foo('test_2')]) + + loader = unittest.TestLoader() + loader.testMethodPrefix = 'foo' + self.assertEqual(loader.loadTestsFromName('Foo', m), tests_1) + + loader.testMethodPrefix = 'test' + self.assertEqual(loader.loadTestsFromName('Foo', m), tests_2) + + # "String giving the prefix of method names which will be interpreted as + # test methods" + # + # Implicit in the documentation is that testMethodPrefix is respected by + # all loadTestsFrom* methods. + def test_testMethodPrefix__loadTestsFromNames(self): + import new + m = new.module('m') + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foo_bar(self): pass + m.Foo = Foo + + tests_1 = unittest.TestSuite([unittest.TestSuite([Foo('foo_bar')])]) + tests_2 = unittest.TestSuite([Foo('test_1'), Foo('test_2')]) + tests_2 = unittest.TestSuite([tests_2]) + + loader = unittest.TestLoader() + loader.testMethodPrefix = 'foo' + self.assertEqual(loader.loadTestsFromNames(['Foo'], m), tests_1) + + loader.testMethodPrefix = 'test' + self.assertEqual(loader.loadTestsFromNames(['Foo'], m), tests_2) + + # "The default value is 'test'" + def test_testMethodPrefix__default_value(self): + loader = unittest.TestLoader() + self.failUnless(loader.testMethodPrefix == 'test') + + ################################################################ + ### /Tests for TestLoader.testMethodPrefix + + ### Tests for TestLoader.sortTestMethodsUsing + ################################################################ + + # "Function to be used to compare method names when sorting them in + # getTestCaseNames() and all the loadTestsFromX() methods" + def test_sortTestMethodsUsing__loadTestsFromTestCase(self): + def reversed_cmp(x, y): + return -cmp(x, y) + + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + + loader = unittest.TestLoader() + loader.sortTestMethodsUsing = reversed_cmp + + tests = loader.suiteClass([Foo('test_2'), Foo('test_1')]) + self.assertEqual(loader.loadTestsFromTestCase(Foo), tests) + + # "Function to be used to compare method names when sorting them in + # getTestCaseNames() and all the loadTestsFromX() methods" + def test_sortTestMethodsUsing__loadTestsFromModule(self): + def reversed_cmp(x, y): + return -cmp(x, y) + + import new + m = new.module('m') + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + m.Foo = Foo + + loader = unittest.TestLoader() + loader.sortTestMethodsUsing = reversed_cmp + + tests = [loader.suiteClass([Foo('test_2'), Foo('test_1')])] + self.assertEqual(list(loader.loadTestsFromModule(m)), tests) + + # "Function to be used to compare method names when sorting them in + # getTestCaseNames() and all the loadTestsFromX() methods" + def test_sortTestMethodsUsing__loadTestsFromName(self): + def reversed_cmp(x, y): + return -cmp(x, y) + + import new + m = new.module('m') + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + m.Foo = Foo + + loader = unittest.TestLoader() + loader.sortTestMethodsUsing = reversed_cmp + + tests = loader.suiteClass([Foo('test_2'), Foo('test_1')]) + self.assertEqual(loader.loadTestsFromName('Foo', m), tests) + + # "Function to be used to compare method names when sorting them in + # getTestCaseNames() and all the loadTestsFromX() methods" + def test_sortTestMethodsUsing__loadTestsFromNames(self): + def reversed_cmp(x, y): + return -cmp(x, y) + + import new + m = new.module('m') + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + m.Foo = Foo + + loader = unittest.TestLoader() + loader.sortTestMethodsUsing = reversed_cmp + + tests = [loader.suiteClass([Foo('test_2'), Foo('test_1')])] + self.assertEqual(list(loader.loadTestsFromNames(['Foo'], m)), tests) + + # "Function to be used to compare method names when sorting them in + # getTestCaseNames()" + # + # Does it actually affect getTestCaseNames()? + def test_sortTestMethodsUsing__getTestCaseNames(self): + def reversed_cmp(x, y): + return -cmp(x, y) + + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + + loader = unittest.TestLoader() + loader.sortTestMethodsUsing = reversed_cmp + + test_names = ['test_2', 'test_1'] + self.assertEqual(loader.getTestCaseNames(Foo), test_names) + + # "The default value is the built-in cmp() function" + def test_sortTestMethodsUsing__default_value(self): + loader = unittest.TestLoader() + self.failUnless(loader.sortTestMethodsUsing is cmp) + + # "it can be set to None to disable the sort." + # + # XXX How is this different from reassigning cmp? Are the tests returned + # in a random order or something? This behaviour should die + def test_sortTestMethodsUsing__None(self): + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + + loader = unittest.TestLoader() + loader.sortTestMethodsUsing = None + + test_names = ['test_2', 'test_1'] + self.assertEqual(set(loader.getTestCaseNames(Foo)), set(test_names)) + + ################################################################ + ### /Tests for TestLoader.sortTestMethodsUsing + + ### Tests for TestLoader.suiteClass + ################################################################ + + # "Callable object that constructs a test suite from a list of tests." + def test_suiteClass__loadTestsFromTestCase(self): + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foo_bar(self): pass + + tests = [Foo('test_1'), Foo('test_2')] + + loader = unittest.TestLoader() + loader.suiteClass = list + self.assertEqual(loader.loadTestsFromTestCase(Foo), tests) + + # It is implicit in the documentation for TestLoader.suiteClass that + # all TestLoader.loadTestsFrom* methods respect it. Let's make sure + def test_suiteClass__loadTestsFromModule(self): + import new + m = new.module('m') + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foo_bar(self): pass + m.Foo = Foo + + tests = [[Foo('test_1'), Foo('test_2')]] + + loader = unittest.TestLoader() + loader.suiteClass = list + self.assertEqual(loader.loadTestsFromModule(m), tests) + + # It is implicit in the documentation for TestLoader.suiteClass that + # all TestLoader.loadTestsFrom* methods respect it. Let's make sure + def test_suiteClass__loadTestsFromName(self): + import new + m = new.module('m') + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foo_bar(self): pass + m.Foo = Foo + + tests = [Foo('test_1'), Foo('test_2')] + + loader = unittest.TestLoader() + loader.suiteClass = list + self.assertEqual(loader.loadTestsFromName('Foo', m), tests) + + # It is implicit in the documentation for TestLoader.suiteClass that + # all TestLoader.loadTestsFrom* methods respect it. Let's make sure + def test_suiteClass__loadTestsFromNames(self): + import new + m = new.module('m') + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def foo_bar(self): pass + m.Foo = Foo + + tests = [[Foo('test_1'), Foo('test_2')]] + + loader = unittest.TestLoader() + loader.suiteClass = list + self.assertEqual(loader.loadTestsFromNames(['Foo'], m), tests) + + # "The default value is the TestSuite class" + def test_suiteClass__default_value(self): + loader = unittest.TestLoader() + self.failUnless(loader.suiteClass is unittest.TestSuite) + + ################################################################ + ### /Tests for TestLoader.suiteClass + +### Support code for Test_TestSuite +################################################################ + +class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + def test_3(self): pass + def runTest(self): pass + +def _mk_TestSuite(*names): + return unittest.TestSuite(Foo(n) for n in names) + +################################################################ +### /Support code for Test_TestSuite + +class Test_TestSuite(TestCase, TestEquality): + + ### Set up attributes needed by inherited tests + ################################################################ + + # Used by TestEquality.test_eq + eq_pairs = [(unittest.TestSuite(), unittest.TestSuite()) + ,(unittest.TestSuite(), unittest.TestSuite([])) + ,(_mk_TestSuite('test_1'), _mk_TestSuite('test_1'))] + + # Used by TestEquality.test_ne + ne_pairs = [(unittest.TestSuite(), _mk_TestSuite('test_1')) + ,(unittest.TestSuite([]), _mk_TestSuite('test_1')) + ,(_mk_TestSuite('test_1', 'test_2'), _mk_TestSuite('test_1', 'test_3')) + ,(_mk_TestSuite('test_1'), _mk_TestSuite('test_2'))] + + ################################################################ + ### /Set up attributes needed by inherited tests + + ### Tests for TestSuite.__init__ + ################################################################ + + # "class TestSuite([tests])" + # + # The tests iterable should be optional + def test_init__tests_optional(self): + suite = unittest.TestSuite() + + self.assertEqual(suite.countTestCases(), 0) + + # "class TestSuite([tests])" + # ... + # "If tests is given, it must be an iterable of individual test cases + # or other test suites that will be used to build the suite initially" + # + # TestSuite should deal with empty tests iterables by allowing the + # creation of an empty suite + def test_init__empty_tests(self): + suite = unittest.TestSuite([]) + + self.assertEqual(suite.countTestCases(), 0) + + # "class TestSuite([tests])" + # ... + # "If tests is given, it must be an iterable of individual test cases + # or other test suites that will be used to build the suite initially" + # + # TestSuite should allow any iterable to provide tests + def test_init__tests_from_any_iterable(self): + def tests(): + yield unittest.FunctionTestCase(lambda: None) + yield unittest.FunctionTestCase(lambda: None) + + suite_1 = unittest.TestSuite(tests()) + self.assertEqual(suite_1.countTestCases(), 2) + + suite_2 = unittest.TestSuite(suite_1) + self.assertEqual(suite_2.countTestCases(), 2) + + suite_3 = unittest.TestSuite(set(suite_1)) + self.assertEqual(suite_3.countTestCases(), 2) + + # "class TestSuite([tests])" + # ... + # "If tests is given, it must be an iterable of individual test cases + # or other test suites that will be used to build the suite initially" + # + # Does TestSuite() also allow other TestSuite() instances to be present + # in the tests iterable? + def test_init__TestSuite_instances_in_tests(self): + def tests(): + ftc = unittest.FunctionTestCase(lambda: None) + yield unittest.TestSuite([ftc]) + yield unittest.FunctionTestCase(lambda: None) + + suite = unittest.TestSuite(tests()) + self.assertEqual(suite.countTestCases(), 2) + + ################################################################ + ### /Tests for TestSuite.__init__ + + # Container types should support the iter protocol + def test_iter(self): + test1 = unittest.FunctionTestCase(lambda: None) + test2 = unittest.FunctionTestCase(lambda: None) + suite = unittest.TestSuite((test1, test2)) + + self.assertEqual(list(suite), [test1, test2]) + + # "Return the number of tests represented by the this test object. + # ...this method is also implemented by the TestSuite class, which can + # return larger [greater than 1] values" + # + # Presumably an empty TestSuite returns 0? + def test_countTestCases_zero_simple(self): + suite = unittest.TestSuite() + + self.assertEqual(suite.countTestCases(), 0) + + # "Return the number of tests represented by the this test object. + # ...this method is also implemented by the TestSuite class, which can + # return larger [greater than 1] values" + # + # Presumably an empty TestSuite (even if it contains other empty + # TestSuite instances) returns 0? + def test_countTestCases_zero_nested(self): + class Test1(unittest.TestCase): + def test(self): + pass + + suite = unittest.TestSuite([unittest.TestSuite()]) + + self.assertEqual(suite.countTestCases(), 0) + + # "Return the number of tests represented by the this test object. + # ...this method is also implemented by the TestSuite class, which can + # return larger [greater than 1] values" + def test_countTestCases_simple(self): + test1 = unittest.FunctionTestCase(lambda: None) + test2 = unittest.FunctionTestCase(lambda: None) + suite = unittest.TestSuite((test1, test2)) + + self.assertEqual(suite.countTestCases(), 2) + + # "Return the number of tests represented by the this test object. + # ...this method is also implemented by the TestSuite class, which can + # return larger [greater than 1] values" + # + # Make sure this holds for nested TestSuite instances, too + def test_countTestCases_nested(self): + class Test1(unittest.TestCase): + def test1(self): pass + def test2(self): pass + + test2 = unittest.FunctionTestCase(lambda: None) + test3 = unittest.FunctionTestCase(lambda: None) + child = unittest.TestSuite((Test1('test2'), test2)) + parent = unittest.TestSuite((test3, child, Test1('test1'))) + + self.assertEqual(parent.countTestCases(), 4) + + # "Run the tests associated with this suite, collecting the result into + # the test result object passed as result." + # + # And if there are no tests? What then? + def test_run__empty_suite(self): + events = [] + result = LoggingResult(events) + + suite = unittest.TestSuite() + + suite.run(result) + + self.assertEqual(events, []) + + # "Note that unlike TestCase.run(), TestSuite.run() requires the + # "result object to be passed in." + def test_run__requires_result(self): + suite = unittest.TestSuite() + + try: + suite.run() + except TypeError: + pass + else: + self.fail("Failed to raise TypeError") + + # "Run the tests associated with this suite, collecting the result into + # the test result object passed as result." + def test_run(self): + events = [] + result = LoggingResult(events) + + class LoggingCase(unittest.TestCase): + def run(self, result): + events.append('run %s' % self._testMethodName) + + def test1(self): pass + def test2(self): pass + + tests = [LoggingCase('test1'), LoggingCase('test2')] + + unittest.TestSuite(tests).run(result) + + self.assertEqual(events, ['run test1', 'run test2']) + + # "Add a TestCase ... to the suite" + def test_addTest__TestCase(self): + class Foo(unittest.TestCase): + def test(self): pass + + test = Foo('test') + suite = unittest.TestSuite() + + suite.addTest(test) + + self.assertEqual(suite.countTestCases(), 1) + self.assertEqual(list(suite), [test]) + + # "Add a ... TestSuite to the suite" + def test_addTest__TestSuite(self): + class Foo(unittest.TestCase): + def test(self): pass + + suite_2 = unittest.TestSuite([Foo('test')]) + + suite = unittest.TestSuite() + suite.addTest(suite_2) + + self.assertEqual(suite.countTestCases(), 1) + self.assertEqual(list(suite), [suite_2]) + + # "Add all the tests from an iterable of TestCase and TestSuite + # instances to this test suite." + # + # "This is equivalent to iterating over tests, calling addTest() for + # each element" + def test_addTests(self): + class Foo(unittest.TestCase): + def test_1(self): pass + def test_2(self): pass + + test_1 = Foo('test_1') + test_2 = Foo('test_2') + inner_suite = unittest.TestSuite([test_2]) + + def gen(): + yield test_1 + yield test_2 + yield inner_suite + + suite_1 = unittest.TestSuite() + suite_1.addTests(gen()) + + self.assertEqual(list(suite_1), list(gen())) + + # "This is equivalent to iterating over tests, calling addTest() for + # each element" + suite_2 = unittest.TestSuite() + for t in gen(): + suite_2.addTest(t) + + self.assertEqual(suite_1, suite_2) + + # "Add all the tests from an iterable of TestCase and TestSuite + # instances to this test suite." + # + # What happens if it doesn't get an iterable? + def test_addTest__noniterable(self): + suite = unittest.TestSuite() + + try: + suite.addTests(5) + except TypeError: + pass + else: + self.fail("Failed to raise TypeError") + + +class Test_FunctionTestCase(TestCase): + + # "Return the number of tests represented by the this test object. For + # TestCase instances, this will always be 1" + def test_countTestCases(self): + test = unittest.FunctionTestCase(lambda: None) + + self.assertEqual(test.countTestCases(), 1) + + # "When a setUp() method is defined, the test runner will run that method + # prior to each test. Likewise, if a tearDown() method is defined, the + # test runner will invoke that method after each test. In the example, + # setUp() was used to create a fresh sequence for each test." + # + # Make sure the proper call order is maintained, even if setUp() raises + # an exception. + def test_run_call_order__error_in_setUp(self): + events = [] + result = LoggingResult(events) + + def setUp(): + events.append('setUp') + raise RuntimeError('raised by setUp') + + def test(): + events.append('test') + + def tearDown(): + events.append('tearDown') + + expected = ['startTest', 'setUp', 'addError', 'stopTest'] + unittest.FunctionTestCase(test, setUp, tearDown).run(result) + self.assertEqual(events, expected) + + # "When a setUp() method is defined, the test runner will run that method + # prior to each test. Likewise, if a tearDown() method is defined, the + # test runner will invoke that method after each test. In the example, + # setUp() was used to create a fresh sequence for each test." + # + # Make sure the proper call order is maintained, even if the test raises + # an error (as opposed to a failure). + def test_run_call_order__error_in_test(self): + events = [] + result = LoggingResult(events) + + def setUp(): + events.append('setUp') + + def test(): + events.append('test') + raise RuntimeError('raised by test') + + def tearDown(): + events.append('tearDown') + + expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown', + 'stopTest'] + unittest.FunctionTestCase(test, setUp, tearDown).run(result) + self.assertEqual(events, expected) + + # "When a setUp() method is defined, the test runner will run that method + # prior to each test. Likewise, if a tearDown() method is defined, the + # test runner will invoke that method after each test. In the example, + # setUp() was used to create a fresh sequence for each test." + # + # Make sure the proper call order is maintained, even if the test signals + # a failure (as opposed to an error). + def test_run_call_order__failure_in_test(self): + events = [] + result = LoggingResult(events) + + def setUp(): + events.append('setUp') + + def test(): + events.append('test') + self.fail('raised by test') + + def tearDown(): + events.append('tearDown') + + expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown', + 'stopTest'] + unittest.FunctionTestCase(test, setUp, tearDown).run(result) + self.assertEqual(events, expected) + + # "When a setUp() method is defined, the test runner will run that method + # prior to each test. Likewise, if a tearDown() method is defined, the + # test runner will invoke that method after each test. In the example, + # setUp() was used to create a fresh sequence for each test." + # + # Make sure the proper call order is maintained, even if tearDown() raises + # an exception. + def test_run_call_order__error_in_tearDown(self): + events = [] + result = LoggingResult(events) + + def setUp(): + events.append('setUp') + + def test(): + events.append('test') + + def tearDown(): + events.append('tearDown') + raise RuntimeError('raised by tearDown') + + expected = ['startTest', 'setUp', 'test', 'tearDown', 'addError', + 'stopTest'] + unittest.FunctionTestCase(test, setUp, tearDown).run(result) + self.assertEqual(events, expected) + + # "Return a string identifying the specific test case." + # + # Because of the vague nature of the docs, I'm not going to lock this + # test down too much. Really all that can be asserted is that the id() + # will be a string (either 8-byte or unicode -- again, because the docs + # just say "string") + def test_id(self): + test = unittest.FunctionTestCase(lambda: None) + + self.failUnless(isinstance(test.id(), basestring)) + + # "Returns a one-line description of the test, or None if no description + # has been provided. The default implementation of this method returns + # the first line of the test method's docstring, if available, or None." + def test_shortDescription__no_docstring(self): + test = unittest.FunctionTestCase(lambda: None) + + self.assertEqual(test.shortDescription(), None) + + # "Returns a one-line description of the test, or None if no description + # has been provided. The default implementation of this method returns + # the first line of the test method's docstring, if available, or None." + def test_shortDescription__singleline_docstring(self): + desc = "this tests foo" + test = unittest.FunctionTestCase(lambda: None, description=desc) + + self.assertEqual(test.shortDescription(), "this tests foo") + +class Test_TestResult(TestCase): + # Note: there are not separate tests for TestResult.wasSuccessful(), + # TestResult.errors, TestResult.failures, TestResult.testsRun or + # TestResult.shouldStop because these only have meaning in terms of + # other TestResult methods. + # + # Accordingly, tests for the aforenamed attributes are incorporated + # in with the tests for the defining methods. + ################################################################ + + def test_init(self): + result = unittest.TestResult() + + self.failUnless(result.wasSuccessful()) + self.assertEqual(len(result.errors), 0) + self.assertEqual(len(result.failures), 0) + self.assertEqual(result.testsRun, 0) + self.assertEqual(result.shouldStop, False) + + # "This method can be called to signal that the set of tests being + # run should be aborted by setting the TestResult's shouldStop + # attribute to True." + def test_stop(self): + result = unittest.TestResult() + + result.stop() + + self.assertEqual(result.shouldStop, True) + + # "Called when the test case test is about to be run. The default + # implementation simply increments the instance's testsRun counter." + def test_startTest(self): + class Foo(unittest.TestCase): + def test_1(self): + pass + + test = Foo('test_1') + + result = unittest.TestResult() + + result.startTest(test) + + self.failUnless(result.wasSuccessful()) + self.assertEqual(len(result.errors), 0) + self.assertEqual(len(result.failures), 0) + self.assertEqual(result.testsRun, 1) + self.assertEqual(result.shouldStop, False) + + result.stopTest(test) + + # "Called after the test case test has been executed, regardless of + # the outcome. The default implementation does nothing." + def test_stopTest(self): + class Foo(unittest.TestCase): + def test_1(self): + pass + + test = Foo('test_1') + + result = unittest.TestResult() + + result.startTest(test) + + self.failUnless(result.wasSuccessful()) + self.assertEqual(len(result.errors), 0) + self.assertEqual(len(result.failures), 0) + self.assertEqual(result.testsRun, 1) + self.assertEqual(result.shouldStop, False) + + result.stopTest(test) + + # Same tests as above; make sure nothing has changed + self.failUnless(result.wasSuccessful()) + self.assertEqual(len(result.errors), 0) + self.assertEqual(len(result.failures), 0) + self.assertEqual(result.testsRun, 1) + self.assertEqual(result.shouldStop, False) + + # "addSuccess(test)" + # ... + # "Called when the test case test succeeds" + # ... + # "wasSuccessful() - Returns True if all tests run so far have passed, + # otherwise returns False" + # ... + # "testsRun - The total number of tests run so far." + # ... + # "errors - A list containing 2-tuples of TestCase instances and + # formatted tracebacks. Each tuple represents a test which raised an + # unexpected exception. Contains formatted + # tracebacks instead of sys.exc_info() results." + # ... + # "failures - A list containing 2-tuples of TestCase instances and + # formatted tracebacks. Each tuple represents a test where a failure was + # explicitly signalled using the TestCase.fail*() or TestCase.assert*() + # methods. Contains formatted tracebacks instead + # of sys.exc_info() results." + def test_addSuccess(self): + class Foo(unittest.TestCase): + def test_1(self): + pass + + test = Foo('test_1') + + result = unittest.TestResult() + + result.startTest(test) + result.addSuccess(test) + result.stopTest(test) + + self.failUnless(result.wasSuccessful()) + self.assertEqual(len(result.errors), 0) + self.assertEqual(len(result.failures), 0) + self.assertEqual(result.testsRun, 1) + self.assertEqual(result.shouldStop, False) + + # "addFailure(test, err)" + # ... + # "Called when the test case test signals a failure. err is a tuple of + # the form returned by sys.exc_info(): (type, value, traceback)" + # ... + # "wasSuccessful() - Returns True if all tests run so far have passed, + # otherwise returns False" + # ... + # "testsRun - The total number of tests run so far." + # ... + # "errors - A list containing 2-tuples of TestCase instances and + # formatted tracebacks. Each tuple represents a test which raised an + # unexpected exception. Contains formatted + # tracebacks instead of sys.exc_info() results." + # ... + # "failures - A list containing 2-tuples of TestCase instances and + # formatted tracebacks. Each tuple represents a test where a failure was + # explicitly signalled using the TestCase.fail*() or TestCase.assert*() + # methods. Contains formatted tracebacks instead + # of sys.exc_info() results." + def test_addFailure(self): + import sys + + class Foo(unittest.TestCase): + def test_1(self): + pass + + test = Foo('test_1') + try: + test.fail("foo") + except: + exc_info_tuple = sys.exc_info() + + result = unittest.TestResult() + + result.startTest(test) + result.addFailure(test, exc_info_tuple) + result.stopTest(test) + + self.failIf(result.wasSuccessful()) + self.assertEqual(len(result.errors), 0) + self.assertEqual(len(result.failures), 1) + self.assertEqual(result.testsRun, 1) + self.assertEqual(result.shouldStop, False) + + test_case, formatted_exc = result.failures[0] + self.failUnless(test_case is test) + self.failUnless(isinstance(formatted_exc, str)) + + # "addError(test, err)" + # ... + # "Called when the test case test raises an unexpected exception err + # is a tuple of the form returned by sys.exc_info(): + # (type, value, traceback)" + # ... + # "wasSuccessful() - Returns True if all tests run so far have passed, + # otherwise returns False" + # ... + # "testsRun - The total number of tests run so far." + # ... + # "errors - A list containing 2-tuples of TestCase instances and + # formatted tracebacks. Each tuple represents a test which raised an + # unexpected exception. Contains formatted + # tracebacks instead of sys.exc_info() results." + # ... + # "failures - A list containing 2-tuples of TestCase instances and + # formatted tracebacks. Each tuple represents a test where a failure was + # explicitly signalled using the TestCase.fail*() or TestCase.assert*() + # methods. Contains formatted tracebacks instead + # of sys.exc_info() results." + def test_addError(self): + import sys + + class Foo(unittest.TestCase): + def test_1(self): + pass + + test = Foo('test_1') + try: + raise TypeError() + except: + exc_info_tuple = sys.exc_info() + + result = unittest.TestResult() + + result.startTest(test) + result.addError(test, exc_info_tuple) + result.stopTest(test) + + self.failIf(result.wasSuccessful()) + self.assertEqual(len(result.errors), 1) + self.assertEqual(len(result.failures), 0) + self.assertEqual(result.testsRun, 1) + self.assertEqual(result.shouldStop, False) + + test_case, formatted_exc = result.errors[0] + self.failUnless(test_case is test) + self.failUnless(isinstance(formatted_exc, str)) + +### Support code for Test_TestCase +################################################################ + +class Foo(unittest.TestCase): + def runTest(self): pass + def test1(self): pass + +class Bar(Foo): + def test2(self): pass + +################################################################ +### /Support code for Test_TestCase + +class Test_TestCase(TestCase, TestEquality, TestHashing): + + ### Set up attributes used by inherited tests + ################################################################ + + # Used by TestHashing.test_hash and TestEquality.test_eq + eq_pairs = [(Foo('test1'), Foo('test1'))] + + # Used by TestEquality.test_ne + ne_pairs = [(Foo('test1'), Foo('runTest')) + ,(Foo('test1'), Bar('test1')) + ,(Foo('test1'), Bar('test2'))] + + ################################################################ + ### /Set up attributes used by inherited tests + -def test_TestSuite_iter(): - """ - >>> test1 = unittest.FunctionTestCase(lambda: None) - >>> test2 = unittest.FunctionTestCase(lambda: None) - >>> suite = unittest.TestSuite((test1, test2)) - >>> tests = [] - >>> for test in suite: - ... tests.append(test) - >>> tests == [test1, test2] - True - """ + # "class TestCase([methodName])" + # ... + # "Each instance of TestCase will run a single test method: the + # method named methodName." + # ... + # "methodName defaults to "runTest"." + # + # Make sure it really is optional, and that it defaults to the proper + # thing. + def test_init__no_test_name(self): + class Test(unittest.TestCase): + def runTest(self): raise MyException() + def test(self): pass + + self.assertEqual(Test().id()[-13:], '.Test.runTest') + + # "class TestCase([methodName])" + # ... + # "Each instance of TestCase will run a single test method: the + # method named methodName." + def test_init__test_name__valid(self): + class Test(unittest.TestCase): + def runTest(self): raise MyException() + def test(self): pass + + self.assertEqual(Test('test').id()[-10:], '.Test.test') + + # "class TestCase([methodName])" + # ... + # "Each instance of TestCase will run a single test method: the + # method named methodName." + def test_init__test_name__invalid(self): + class Test(unittest.TestCase): + def runTest(self): raise MyException() + def test(self): pass + + try: + Test('testfoo') + except ValueError: + pass + else: + self.fail("Failed to raise ValueError") + + # "Return the number of tests represented by the this test object. For + # TestCase instances, this will always be 1" + def test_countTestCases(self): + class Foo(unittest.TestCase): + def test(self): pass + + self.assertEqual(Foo('test').countTestCases(), 1) + + # "Return the default type of test result object to be used to run this + # test. For TestCase instances, this will always be + # unittest.TestResult; subclasses of TestCase should + # override this as necessary." + def test_defaultTestResult(self): + class Foo(unittest.TestCase): + def runTest(self): + pass + + result = Foo().defaultTestResult() + self.assertEqual(type(result), unittest.TestResult) + # "When a setUp() method is defined, the test runner will run that method + # prior to each test. Likewise, if a tearDown() method is defined, the + # test runner will invoke that method after each test. In the example, + # setUp() was used to create a fresh sequence for each test." + # + # Make sure the proper call order is maintained, even if setUp() raises + # an exception. + def test_run_call_order__error_in_setUp(self): + events = [] + result = LoggingResult(events) + + class Foo(unittest.TestCase): + def setUp(self): + events.append('setUp') + raise RuntimeError('raised by Foo.setUp') + + def test(self): + events.append('test') + + def tearDown(self): + events.append('tearDown') + + Foo('test').run(result) + expected = ['startTest', 'setUp', 'addError', 'stopTest'] + self.assertEqual(events, expected) + + # "When a setUp() method is defined, the test runner will run that method + # prior to each test. Likewise, if a tearDown() method is defined, the + # test runner will invoke that method after each test. In the example, + # setUp() was used to create a fresh sequence for each test." + # + # Make sure the proper call order is maintained, even if the test raises + # an error (as opposed to a failure). + def test_run_call_order__error_in_test(self): + events = [] + result = LoggingResult(events) + + class Foo(unittest.TestCase): + def setUp(self): + events.append('setUp') + + def test(self): + events.append('test') + raise RuntimeError('raised by Foo.test') + + def tearDown(self): + events.append('tearDown') + + expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown', + 'stopTest'] + Foo('test').run(result) + self.assertEqual(events, expected) + + # "When a setUp() method is defined, the test runner will run that method + # prior to each test. Likewise, if a tearDown() method is defined, the + # test runner will invoke that method after each test. In the example, + # setUp() was used to create a fresh sequence for each test." + # + # Make sure the proper call order is maintained, even if the test signals + # a failure (as opposed to an error). + def test_run_call_order__failure_in_test(self): + events = [] + result = LoggingResult(events) + + class Foo(unittest.TestCase): + def setUp(self): + events.append('setUp') + + def test(self): + events.append('test') + self.fail('raised by Foo.test') + + def tearDown(self): + events.append('tearDown') + + expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown', + 'stopTest'] + Foo('test').run(result) + self.assertEqual(events, expected) + + # "When a setUp() method is defined, the test runner will run that method + # prior to each test. Likewise, if a tearDown() method is defined, the + # test runner will invoke that method after each test. In the example, + # setUp() was used to create a fresh sequence for each test." + # + # Make sure the proper call order is maintained, even if tearDown() raises + # an exception. + def test_run_call_order__error_in_tearDown(self): + events = [] + result = LoggingResult(events) + + class Foo(unittest.TestCase): + def setUp(self): + events.append('setUp') + + def test(self): + events.append('test') + + def tearDown(self): + events.append('tearDown') + raise RuntimeError('raised by Foo.tearDown') + + Foo('test').run(result) + expected = ['startTest', 'setUp', 'test', 'tearDown', 'addError', + 'stopTest'] + self.assertEqual(events, expected) + + # "This class attribute gives the exception raised by the test() method. + # If a test framework needs to use a specialized exception, possibly to + # carry additional information, it must subclass this exception in + # order to ``play fair'' with the framework. The initial value of this + # attribute is AssertionError" + def test_failureException__default(self): + class Foo(unittest.TestCase): + def test(self): + pass + + self.failUnless(Foo('test').failureException is AssertionError) + + # "This class attribute gives the exception raised by the test() method. + # If a test framework needs to use a specialized exception, possibly to + # carry additional information, it must subclass this exception in + # order to ``play fair'' with the framework." + # + # Make sure TestCase.run() respects the designated failureException + def test_failureException__subclassing__explicit_raise(self): + events = [] + result = LoggingResult(events) + + class Foo(unittest.TestCase): + def test(self): + raise RuntimeError() + + failureException = RuntimeError + + self.failUnless(Foo('test').failureException is RuntimeError) + + + Foo('test').run(result) + expected = ['startTest', 'addFailure', 'stopTest'] + self.assertEqual(events, expected) + + # "This class attribute gives the exception raised by the test() method. + # If a test framework needs to use a specialized exception, possibly to + # carry additional information, it must subclass this exception in + # order to ``play fair'' with the framework." + # + # Make sure TestCase.run() respects the designated failureException + def test_failureException__subclassing__implicit_raise(self): + events = [] + result = LoggingResult(events) + + class Foo(unittest.TestCase): + def test(self): + self.fail("foo") + + failureException = RuntimeError + + self.failUnless(Foo('test').failureException is RuntimeError) + + + Foo('test').run(result) + expected = ['startTest', 'addFailure', 'stopTest'] + self.assertEqual(events, expected) + + # "The default implementation does nothing." + def test_setUp(self): + class Foo(unittest.TestCase): + def runTest(self): + pass + + # ... and nothing should happen + Foo().setUp() + + # "The default implementation does nothing." + def test_tearDown(self): + class Foo(unittest.TestCase): + def runTest(self): + pass + + # ... and nothing should happen + Foo().tearDown() + + # "Return a string identifying the specific test case." + # + # Because of the vague nature of the docs, I'm not going to lock this + # test down too much. Really all that can be asserted is that the id() + # will be a string (either 8-byte or unicode -- again, because the docs + # just say "string") + def test_id(self): + class Foo(unittest.TestCase): + def runTest(self): + pass + + self.failUnless(isinstance(Foo().id(), basestring)) + + # "Returns a one-line description of the test, or None if no description + # has been provided. The default implementation of this method returns + # the first line of the test method's docstring, if available, or None." + def test_shortDescription__no_docstring(self): + class Foo(unittest.TestCase): + def runTest(self): + pass + + self.assertEqual(Foo().shortDescription(), None) + + # "Returns a one-line description of the test, or None if no description + # has been provided. The default implementation of this method returns + # the first line of the test method's docstring, if available, or None." + def test_shortDescription__singleline_docstring(self): + class Foo(unittest.TestCase): + def runTest(self): + "this tests foo" + pass + + self.assertEqual(Foo().shortDescription(), "this tests foo") + + # "Returns a one-line description of the test, or None if no description + # has been provided. The default implementation of this method returns + # the first line of the test method's docstring, if available, or None." + def test_shortDescription__multiline_docstring(self): + class Foo(unittest.TestCase): + def runTest(self): + """this tests foo + blah, bar and baz are also tested""" + pass + + self.assertEqual(Foo().shortDescription(), "this tests foo") + + # "If result is omitted or None, a temporary result object is created + # and used, but is not made available to the caller" + def test_run__uses_defaultTestResult(self): + events = [] + + class Foo(unittest.TestCase): + def test(self): + events.append('test') + + def defaultTestResult(self): + return LoggingResult(events) + + # Make run() find a result object on its own + Foo('test').run() + + expected = ['startTest', 'test', 'stopTest'] + self.assertEqual(events, expected) ###################################################################### ## Main ###################################################################### def test_main(): - from test import test_support, test_unittest - test_support.run_doctest(test_unittest, verbosity=True) + test_support.run_unittest(Test_TestCase, Test_TestLoader, + Test_TestSuite, Test_TestResult, Test_FunctionTestCase) -if __name__ == '__main__': - test_main() +if __name__ == "__main__": + test_main() Modified: python/trunk/Lib/unittest.py ============================================================================== --- python/trunk/Lib/unittest.py (original) +++ python/trunk/Lib/unittest.py Wed Mar 7 10:09:40 2007 @@ -25,7 +25,7 @@ Further information is available in the bundled documentation, and from - http://pyunit.sourceforge.net/ + http://docs.python.org/lib/module-unittest.html Copyright (c) 1999-2003 Steve Purcell This module is free software, and you may redistribute it and/or modify @@ -107,7 +107,7 @@ self.failures = [] self.errors = [] self.testsRun = 0 - self.shouldStop = 0 + self.shouldStop = False def startTest(self, test): "Called when the given test is about to be run" @@ -235,6 +235,18 @@ def id(self): return "%s.%s" % (_strclass(self.__class__), self._testMethodName) + def __eq__(self, other): + if type(self) is not type(other): + return False + + return self._testMethodName == other._testMethodName + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(str(hash(type(self))) + str(hash(self._testMethodName))) + def __str__(self): return "%s (%s)" % (self._testMethodName, _strclass(self.__class__)) @@ -291,10 +303,7 @@ minimised; usually the top level of the traceback frame is not needed. """ - exctype, excvalue, tb = sys.exc_info() - if sys.platform[:4] == 'java': ## tracebacks look different in Jython - return (exctype, excvalue, tb) - return (exctype, excvalue, tb) + return sys.exc_info() def fail(self, msg=None): """Fail immediately, with the given message.""" @@ -401,6 +410,14 @@ __str__ = __repr__ + def __eq__(self, other): + if type(self) is not type(other): + return False + return self._tests == other._tests + + def __ne__(self, other): + return not self == other + def __iter__(self): return iter(self._tests) @@ -436,7 +453,7 @@ """A test case that wraps a test function. This is useful for slipping pre-existing test functions into the - PyUnit framework. Optionally, set-up and tidy-up functions can be + unittest framework. Optionally, set-up and tidy-up functions can be supplied. As with TestCase, the tidy-up ('tearDown') function will always be called if the set-up ('setUp') function ran successfully. """ @@ -463,6 +480,23 @@ def id(self): return self.__testFunc.__name__ + def __eq__(self, other): + if type(self) is not type(other): + return False + + return self.__setUpFunc == other.__setUpFunc and \ + self.__tearDownFunc == other.__tearDownFunc and \ + self.__testFunc == other.__testFunc and \ + self.__description == other.__description + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(''.join(str(hash(x)) for x in [ + type(self), self.__setUpFunc, self.__tearDownFunc, self.__testFunc, + self.__description])) + def __str__(self): return "%s (%s)" % (_strclass(self.__class__), self.__testFunc.__name__) @@ -482,7 +516,7 @@ class TestLoader: """This class is responsible for loading tests according to various - criteria and returning them wrapped in a Test + criteria and returning them wrapped in a TestSuite """ testMethodPrefix = 'test' sortTestMethodsUsing = cmp @@ -536,18 +570,23 @@ elif (isinstance(obj, (type, types.ClassType)) and issubclass(obj, TestCase)): return self.loadTestsFromTestCase(obj) - elif type(obj) == types.UnboundMethodType: - return parent(obj.__name__) + elif (type(obj) == types.UnboundMethodType and + isinstance(parent, (type, types.ClassType)) and + issubclass(parent, TestCase)): + return TestSuite([parent(obj.__name__)]) elif isinstance(obj, TestSuite): return obj elif callable(obj): test = obj() - if not isinstance(test, (TestCase, TestSuite)): - raise ValueError, \ - "calling %s returned %s, not a test" % (obj,test) - return test + if isinstance(test, TestSuite): + return test + elif isinstance(test, TestCase): + return TestSuite([test]) + else: + raise TypeError("calling %s returned %s, not a test" % + (obj, test)) else: - raise ValueError, "don't know how to make test from: %s" % obj + raise TypeError("don't know how to make test from: %s" % obj) def loadTestsFromNames(self, names, module=None): """Return a suite of all tests cases found using the given sequence @@ -562,10 +601,6 @@ def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix): return attrname.startswith(prefix) and callable(getattr(testCaseClass, attrname)) testFnNames = filter(isTestMethod, dir(testCaseClass)) - for baseclass in testCaseClass.__bases__: - for testFnName in self.getTestCaseNames(baseclass): - if testFnName not in testFnNames: # handle overridden methods - testFnNames.append(testFnName) if self.sortTestMethodsUsing: testFnNames.sort(self.sortTestMethodsUsing) return testFnNames Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 7 10:09:40 2007 @@ -152,6 +152,9 @@ Library ------- +- Patches #1550273, #1550272: fix a few bugs in unittest and add a + comprehensive test suite for the module. + - Patch #1001604: glob.glob() now returns unicode filenames if it was given a unicode argument and os.listdir() returns unicode filenames. From python-checkins at python.org Wed Mar 7 10:17:43 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 10:17:43 +0100 (CET) Subject: [Python-checkins] r54200 - python/branches/release25-maint/Doc/lib/libunittest.tex Message-ID: <20070307091743.64C551E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 10:17:42 2007 New Revision: 54200 Modified: python/branches/release25-maint/Doc/lib/libunittest.tex Log: Typo fix. Modified: python/branches/release25-maint/Doc/lib/libunittest.tex ============================================================================== --- python/branches/release25-maint/Doc/lib/libunittest.tex (original) +++ python/branches/release25-maint/Doc/lib/libunittest.tex Wed Mar 7 10:17:42 2007 @@ -540,7 +540,7 @@ \begin{funcdesc}{main}{\optional{module\optional{, defaultTest\optional{, argv\optional{, - testRunner\optional{, testRunner}}}}}} + testRunner\optional{, testLoader}}}}}} A command-line program that runs a set of tests; this is primarily for making test modules conveniently executable. The simplest use for this function is to include the following line at the end of a From python-checkins at python.org Wed Mar 7 10:21:12 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 10:21:12 +0100 (CET) Subject: [Python-checkins] r54201 - in python/trunk: Doc/lib/libunittest.tex Lib/unittest.py Misc/NEWS Message-ID: <20070307092112.81BA71E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 10:21:06 2007 New Revision: 54201 Modified: python/trunk/Doc/lib/libunittest.tex python/trunk/Lib/unittest.py python/trunk/Misc/NEWS Log: Patch #787789: allow to pass custom TestRunner instances to unittest's main() function. Modified: python/trunk/Doc/lib/libunittest.tex ============================================================================== --- python/trunk/Doc/lib/libunittest.tex (original) +++ python/trunk/Doc/lib/libunittest.tex Wed Mar 7 10:21:06 2007 @@ -290,6 +290,7 @@ we would end up subclassing \class{SimpleWidgetTestCase} into many small one-method classes such as \class{DefaultWidgetSizeTestCase}. This is time-consuming and + discouraging, so in the same vein as JUnit, \module{unittest} provides a simpler mechanism: @@ -540,7 +541,7 @@ \begin{funcdesc}{main}{\optional{module\optional{, defaultTest\optional{, argv\optional{, - testRunner\optional{, testRunner}}}}}} + testRunner\optional{, testLoader}}}}}} A command-line program that runs a set of tests; this is primarily for making test modules conveniently executable. The simplest use for this function is to include the following line at the end of a @@ -550,6 +551,9 @@ if __name__ == '__main__': unittest.main() \end{verbatim} + + The \var{testRunner} argument can either be a test runner class or + an already created instance of it. \end{funcdesc} In some cases, the existing tests may have been written using the Modified: python/trunk/Lib/unittest.py ============================================================================== --- python/trunk/Lib/unittest.py (original) +++ python/trunk/Lib/unittest.py Wed Mar 7 10:21:06 2007 @@ -776,7 +776,8 @@ in MyTestCase """ def __init__(self, module='__main__', defaultTest=None, - argv=None, testRunner=None, testLoader=defaultTestLoader): + argv=None, testRunner=TextTestRunner, + testLoader=defaultTestLoader): if type(module) == type(''): self.module = __import__(module) for part in module.split('.')[1:]: @@ -826,9 +827,16 @@ self.module) def runTests(self): - if self.testRunner is None: - self.testRunner = TextTestRunner(verbosity=self.verbosity) - result = self.testRunner.run(self.test) + if isinstance(self.testRunner, (type, types.ClassType)): + try: + testRunner = self.testRunner(verbosity=self.verbosity) + except TypeError: + # didn't accept the verbosity argument + testRunner = self.testRunner() + else: + # it is assumed to be a TestRunner instance + testRunner = self.testRunner + result = testRunner.run(self.test) sys.exit(not result.wasSuccessful()) main = TestProgram Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 7 10:21:06 2007 @@ -152,6 +152,9 @@ Library ------- +- Patch #787789: allow to pass custom TestRunner instances to unittest's + main() function. + - Patches #1550273, #1550272: fix a few bugs in unittest and add a comprehensive test suite for the module. From python-checkins at python.org Wed Mar 7 10:34:45 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 10:34:45 +0100 (CET) Subject: [Python-checkins] r54202 - python/trunk/Doc/lib/libshutil.tex Message-ID: <20070307093445.EE1CB1E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 10:34:45 2007 New Revision: 54202 Modified: python/trunk/Doc/lib/libshutil.tex Log: Patch #1669331: clarify shutil.copyfileobj() behavior wrt. file position. Modified: python/trunk/Doc/lib/libshutil.tex ============================================================================== --- python/trunk/Doc/lib/libshutil.tex (original) +++ python/trunk/Doc/lib/libshutil.tex Wed Mar 7 10:34:45 2007 @@ -34,7 +34,9 @@ is the buffer size. In particular, a negative \var{length} value means to copy the data without looping over the source data in chunks; by default the data is read in chunks to avoid uncontrolled - memory consumption. + memory consumption. Note that if the current file position of the + \var{fsrc} object is not 0, only the contents from the current file + position to the end of the file will be copied. \end{funcdesc} \begin{funcdesc}{copymode}{src, dst} From python-checkins at python.org Wed Mar 7 10:34:52 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 10:34:52 +0100 (CET) Subject: [Python-checkins] r54203 - python/branches/release25-maint/Doc/lib/libshutil.tex Message-ID: <20070307093452.BBF561E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 10:34:52 2007 New Revision: 54203 Modified: python/branches/release25-maint/Doc/lib/libshutil.tex Log: Patch #1669331: clarify shutil.copyfileobj() behavior wrt. file position. (backport from rev. 54202) Modified: python/branches/release25-maint/Doc/lib/libshutil.tex ============================================================================== --- python/branches/release25-maint/Doc/lib/libshutil.tex (original) +++ python/branches/release25-maint/Doc/lib/libshutil.tex Wed Mar 7 10:34:52 2007 @@ -34,7 +34,9 @@ is the buffer size. In particular, a negative \var{length} value means to copy the data without looping over the source data in chunks; by default the data is read in chunks to avoid uncontrolled - memory consumption. + memory consumption. Note that if the current file position of the + \var{fsrc} object is not 0, only the contents from the current file + position to the end of the file will be copied. \end{funcdesc} \begin{funcdesc}{copymode}{src, dst} From buildbot at python.org Wed Mar 7 10:48:42 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 09:48:42 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable 2.5 Message-ID: <20070307094842.85E911E4003@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%25202.5/builds/50 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socketserver Traceback (most recent call last): File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/test/test_socketserver.py", line 81, in run svr = svrcls(self.__addr, self.__hdlrcls) File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/SocketServer.py", line 330, in __init__ self.server_bind() File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/SocketServer.py", line 341, in server_bind self.socket.bind(self.server_address) File "", line 1, in bind error: (98, 'Address already in use') Traceback (most recent call last): File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/SocketServer.py", line 466, in process_request_thread self.handle_error(request, client_address) File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/SocketServer.py", line 463, in process_request_thread self.finish_request(request, client_address) File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/SocketServer.py", line 254, in finish_request self.RequestHandlerClass(request, client_address, self) File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/SocketServer.py", line 521, in __init__ self.handle() File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/test/test_socketserver.py", line 21, in handle time.sleep(DELAY) AttributeError: 'NoneType' object has no attribute 'sleep' Traceback (most recent call last): File "./Lib/test/regrtest.py", line 554, in runtest_inner indirect_test() File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/test/test_socketserver.py", line 209, in test_main testall() File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/test/test_socketserver.py", line 192, in testall testloop(socket.AF_INET, tcpservers, MyStreamHandler, teststream) File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/test/test_socketserver.py", line 141, in testloop testfunc(proto, addr) File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/test/test_socketserver.py", line 64, in teststream buf = data = receive(s, 100) File "/home/pybot/buildarea/2.5.klose-debian-ppc/build/Lib/test/test_socketserver.py", line 46, in receive return sock.recv(n) error: (104, 'Connection reset by peer') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Wed Mar 7 11:05:07 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 10:05:07 +0000 Subject: [Python-checkins] buildbot warnings in ia64 Ubuntu trunk trunk Message-ID: <20070307100508.27C6F1E400D@bag.python.org> The Buildbot has detected a new failure of ia64 Ubuntu trunk trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ia64%2520Ubuntu%2520trunk%2520trunk/builds/436 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Wed Mar 7 11:30:19 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 10:30:19 +0000 Subject: [Python-checkins] buildbot warnings in S-390 Debian trunk Message-ID: <20070307103020.3117C1E401C@bag.python.org> The Buildbot has detected a new failure of S-390 Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/S-390%2520Debian%2520trunk/builds/727 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Wed Mar 7 11:52:34 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 10:52:34 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable trunk Message-ID: <20070307105234.6EC4D1E4016@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%2520trunk/builds/133 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: Traceback (most recent call last): File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/test/test_thread.py", line 281, in readerThread rec = dbutils.DeadlockWrap(c.next, max_retries=10) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/dbutils.py", line 62, in DeadlockWrap return function(*_args, **_kwargs) DBLockDeadlockError: (-30995, 'DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock') Traceback (most recent call last): File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/test/test_thread.py", line 245, in writerThread self.assertEqual(data, self.makeData(key)) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/unittest.py", line 343, in failUnlessEqual (msg or '%r != %r' % (first, second)) AssertionError: None != '0091-0091-0091-0091-0091' Traceback (most recent call last): File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/test/test_thread.py", line 260, in writerThread self.assertEqual(data, self.makeData(key)) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/unittest.py", line 343, in failUnlessEqual (msg or '%r != %r' % (first, second)) AssertionError: None != '2000-2000-2000-2000-2000' Traceback (most recent call last): File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/test/test_thread.py", line 260, in writerThread self.assertEqual(data, self.makeData(key)) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/unittest.py", line 343, in failUnlessEqual (msg or '%r != %r' % (first, second)) AssertionError: None != '1000-1000-1000-1000-1000' 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Wed Mar 7 12:04:37 2007 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 7 Mar 2007 12:04:37 +0100 (CET) Subject: [Python-checkins] r54204 - in python/trunk: Doc/lib/libposixpath.tex Lib/genericpath.py Lib/macpath.py Lib/ntpath.py Lib/posixpath.py Lib/test/test_macpath.py Lib/test/test_ntpath.py Lib/test/test_posixpath.py Misc/NEWS Message-ID: <20070307110437.139941E4003@bag.python.org> Author: martin.v.loewis Date: Wed Mar 7 12:04:33 2007 New Revision: 54204 Modified: python/trunk/Doc/lib/libposixpath.tex python/trunk/Lib/genericpath.py python/trunk/Lib/macpath.py python/trunk/Lib/ntpath.py python/trunk/Lib/posixpath.py python/trunk/Lib/test/test_macpath.py python/trunk/Lib/test/test_ntpath.py python/trunk/Lib/test/test_posixpath.py python/trunk/Misc/NEWS Log: Bug #1115886: os.path.splitext('.cshrc') gives now ('.cshrc', ''). Modified: python/trunk/Doc/lib/libposixpath.tex ============================================================================== --- python/trunk/Doc/lib/libposixpath.tex (original) +++ python/trunk/Doc/lib/libposixpath.tex Wed Mar 7 12:04:33 2007 @@ -234,7 +234,12 @@ Split the pathname \var{path} into a pair \code{(\var{root}, \var{ext})} such that \code{\var{root} + \var{ext} == \var{path}}, and \var{ext} is empty or begins with a period and contains -at most one period. +at most one period. Leading periods on the basename are +ignored; \code{\var{splitext}.('.cshrc')} returns +\code{('.cshrc', '')}. + +\versionchanged[Earlier versions could produce an empty root when +the only period was the first character]{2.6} \end{funcdesc} \begin{funcdesc}{splitunc}{path} Modified: python/trunk/Lib/genericpath.py ============================================================================== --- python/trunk/Lib/genericpath.py (original) +++ python/trunk/Lib/genericpath.py Wed Mar 7 12:04:33 2007 @@ -75,3 +75,32 @@ if s1[i] != s2[i]: return s1[:i] return s1[:n] + +# Split a path in root and extension. +# The extension is everything starting at the last dot in the last +# pathname component; the root is everything before that. +# It is always true that root + ext == p. + +# Generic implementation of splitext, to be parametrized with +# the separators +def _splitext(p, sep, altsep, extsep): + """Split the extension from a pathname. + + Extension is everything from the last dot to the end, ignoring + leading dots. Returns "(root, ext)"; ext may be empty.""" + + sepIndex = p.rfind(sep) + if altsep: + altsepIndex = p.rfind(altsep) + sepIndex = max(sepIndex, altsepIndex) + + dotIndex = p.rfind(extsep) + if dotIndex > sepIndex: + # skip all leading dots + filenameIndex = sepIndex + 1 + while filenameIndex < dotIndex: + if p[filenameIndex] != extsep: + return p[:dotIndex], p[dotIndex:] + filenameIndex += 1 + + return p, '' Modified: python/trunk/Lib/macpath.py ============================================================================== --- python/trunk/Lib/macpath.py (original) +++ python/trunk/Lib/macpath.py Wed Mar 7 12:04:33 2007 @@ -2,6 +2,7 @@ import os from stat import * +import genericpath from genericpath import * __all__ = ["normcase","isabs","join","splitdrive","split","splitext", @@ -69,17 +70,8 @@ def splitext(p): - """Split a path into root and extension. - The extension is everything starting at the last dot in the last - pathname component; the root is everything before that. - It is always true that root + ext == p.""" - - i = p.rfind('.') - if i<=p.rfind(':'): - return p, '' - else: - return p[:i], p[i:] - + return genericpath._splitext(p, sep, altsep, extsep) +splitext.__doc__ = genericpath._splitext.__doc__ def splitdrive(p): """Split a pathname into a drive specification and the rest of the Modified: python/trunk/Lib/ntpath.py ============================================================================== --- python/trunk/Lib/ntpath.py (original) +++ python/trunk/Lib/ntpath.py Wed Mar 7 12:04:33 2007 @@ -8,6 +8,7 @@ import os import stat import sys +import genericpath from genericpath import * __all__ = ["normcase","isabs","join","splitdrive","split","splitext", @@ -182,16 +183,8 @@ # It is always true that root + ext == p. def splitext(p): - """Split the extension from a pathname. - - Extension is everything from the last dot to the end. - Return (root, ext), either part may be empty.""" - - i = p.rfind('.') - if i<=max(p.rfind('/'), p.rfind('\\')): - return p, '' - else: - return p[:i], p[i:] + return genericpath._splitext(p, sep, altsep, extsep) +splitext.__doc__ = genericpath._splitext.__doc__ # Return the tail (basename) part of a path. Modified: python/trunk/Lib/posixpath.py ============================================================================== --- python/trunk/Lib/posixpath.py (original) +++ python/trunk/Lib/posixpath.py Wed Mar 7 12:04:33 2007 @@ -12,6 +12,7 @@ import os import stat +import genericpath from genericpath import * __all__ = ["normcase","isabs","join","splitdrive","split","splitext", @@ -88,14 +89,8 @@ # It is always true that root + ext == p. def splitext(p): - """Split the extension from a pathname. Extension is everything from the - last dot to the end. Returns "(root, ext)", either part may be empty.""" - i = p.rfind('.') - if i<=p.rfind('/'): - return p, '' - else: - return p[:i], p[i:] - + return genericpath._splitext(p, sep, altsep, extsep) +splitext.__doc__ = genericpath._splitext.__doc__ # Split a pathname into a drive specification and the rest of the # path. Useful on DOS/Windows/NT; on Unix, the drive is always empty. Modified: python/trunk/Lib/test/test_macpath.py ============================================================================== --- python/trunk/Lib/test/test_macpath.py (original) +++ python/trunk/Lib/test/test_macpath.py Wed Mar 7 12:04:33 2007 @@ -48,7 +48,7 @@ splitext = macpath.splitext self.assertEquals(splitext(":foo.ext"), (':foo', '.ext')) self.assertEquals(splitext("foo:foo.ext"), ('foo:foo', '.ext')) - self.assertEquals(splitext(".ext"), ('', '.ext')) + self.assertEquals(splitext(".ext"), ('.ext', '')) self.assertEquals(splitext("foo.ext:foo"), ('foo.ext:foo', '')) self.assertEquals(splitext(":foo.ext:"), (':foo.ext:', '')) self.assertEquals(splitext(""), ('', '')) Modified: python/trunk/Lib/test/test_ntpath.py ============================================================================== --- python/trunk/Lib/test/test_ntpath.py (original) +++ python/trunk/Lib/test/test_ntpath.py Wed Mar 7 12:04:33 2007 @@ -18,13 +18,14 @@ tester('ntpath.splitext("foo.ext")', ('foo', '.ext')) tester('ntpath.splitext("/foo/foo.ext")', ('/foo/foo', '.ext')) -tester('ntpath.splitext(".ext")', ('', '.ext')) +tester('ntpath.splitext(".ext")', ('.ext', '')) tester('ntpath.splitext("\\foo.ext\\foo")', ('\\foo.ext\\foo', '')) tester('ntpath.splitext("foo.ext\\")', ('foo.ext\\', '')) tester('ntpath.splitext("")', ('', '')) tester('ntpath.splitext("foo.bar.ext")', ('foo.bar', '.ext')) tester('ntpath.splitext("xx/foo.bar.ext")', ('xx/foo.bar', '.ext')) tester('ntpath.splitext("xx\\foo.bar.ext")', ('xx\\foo.bar', '.ext')) +tester('ntpath.splitext("c:a/b\\c.d")', ('c:a/b\\c', '.d')) tester('ntpath.splitdrive("c:\\foo\\bar")', ('c:', '\\foo\\bar')) Modified: python/trunk/Lib/test/test_posixpath.py ============================================================================== --- python/trunk/Lib/test/test_posixpath.py (original) +++ python/trunk/Lib/test/test_posixpath.py Wed Mar 7 12:04:33 2007 @@ -43,15 +43,27 @@ self.assertRaises(TypeError, posixpath.split) - def test_splitext(self): - self.assertEqual(posixpath.splitext("foo.ext"), ("foo", ".ext")) - self.assertEqual(posixpath.splitext("/foo/foo.ext"), ("/foo/foo", ".ext")) - self.assertEqual(posixpath.splitext(".ext"), ("", ".ext")) - self.assertEqual(posixpath.splitext("/foo.ext/foo"), ("/foo.ext/foo", "")) - self.assertEqual(posixpath.splitext("foo.ext/"), ("foo.ext/", "")) - self.assertEqual(posixpath.splitext(""), ("", "")) - self.assertEqual(posixpath.splitext("foo.bar.ext"), ("foo.bar", ".ext")) + def splitextTest(self, path, filename, ext): + self.assertEqual(posixpath.splitext(path), (filename, ext)) + self.assertEqual(posixpath.splitext("/" + path), ("/" + filename, ext)) + self.assertEqual(posixpath.splitext("abc/" + path), ("abc/" + filename, ext)) + self.assertEqual(posixpath.splitext("abc.def/" + path), ("abc.def/" + filename, ext)) + self.assertEqual(posixpath.splitext("/abc.def/" + path), ("/abc.def/" + filename, ext)) + self.assertEqual(posixpath.splitext(path + "/"), (filename + ext + "/", "")) + def test_splitext(self): + self.splitextTest("foo.bar", "foo", ".bar") + self.splitextTest("foo.boo.bar", "foo.boo", ".bar") + self.splitextTest("foo.boo.biff.bar", "foo.boo.biff", ".bar") + self.splitextTest(".csh.rc", ".csh", ".rc") + self.splitextTest("nodots", "nodots", "") + self.splitextTest(".cshrc", ".cshrc", "") + self.splitextTest("...manydots", "...manydots", "") + self.splitextTest("...manydots.ext", "...manydots", ".ext") + self.splitextTest(".", ".", "") + self.splitextTest("..", "..", "") + self.splitextTest("........", "........", "") + self.splitextTest("", "", "") self.assertRaises(TypeError, posixpath.splitext) def test_isabs(self): Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 7 12:04:33 2007 @@ -152,6 +152,8 @@ Library ------- +- Bug #1115886: os.path.splitext('.cshrc') gives now ('.cshrc', ''). + - Patch #787789: allow to pass custom TestRunner instances to unittest's main() function. From buildbot at python.org Wed Mar 7 12:07:23 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 11:07:23 +0000 Subject: [Python-checkins] buildbot warnings in PPC64 Debian trunk Message-ID: <20070307110723.ED4421E4003@bag.python.org> The Buildbot has detected a new failure of PPC64 Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/PPC64%2520Debian%2520trunk/builds/131 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Wed Mar 7 12:23:05 2007 From: python-checkins at python.org (eric.smith) Date: Wed, 7 Mar 2007 12:23:05 +0100 (CET) Subject: [Python-checkins] r54205 - sandbox/trunk/pep3101/test_simpleformat.py Message-ID: <20070307112305.703EF1E4003@bag.python.org> Author: eric.smith Date: Wed Mar 7 12:23:01 2007 New Revision: 54205 Modified: sandbox/trunk/pep3101/test_simpleformat.py Log: Added test cases for invalid types passed to formatters. Added test case for deriving from long and making sure correct __format__ is called. This is a future-proofness test in case __format__ gets implemented by long. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Wed Mar 7 12:23:01 2007 @@ -140,7 +140,7 @@ self.formatEqualsWithUnicode("'abcdefg", "{0:8r}", "abcdefg") def test_decimal_specifiers(self): - self.assertRaises(TypeError, "{0:d}", "non-number") + self.formatRaises(TypeError, "{0:d}", "non-number") self.formatEqualsWithUnicode("0", "{0:d}", 0) self.formatEqualsWithUnicode("0", "{0:d}", long(0)) @@ -182,7 +182,7 @@ def test_octal_specifiers(self): n = int("31415", 8) - self.assertRaises(TypeError, "{0:o", "non-number") + self.formatRaises(TypeError, "{0:o}", "non-number") self.formatEqualsWithUnicode("0", "{0:o}", 0) self.formatEqualsWithUnicode("31415", "{0:o}", n) @@ -225,16 +225,28 @@ #self.formatRaises(TypeError, "{0:c}", 3.14) def test_exponent_specifiers(self): + self.formatRaises(TypeError, "{0:e}", "a string") + self.formatRaises(TypeError, "{0:E}", "a string") + self.formatRaises(TypeError, "{0:e}", 1j) + self.formatRaises(TypeError, "{0:E}", 1j) self.formatEqualsWithUnicodeUC("3.141500e+00", "{0:e}", 3.1415) self.formatEqualsWithUnicodeUC("3.1415000000e+00", "{0:.10e}", 3.1415) def test_fixed_specifiers(self): + self.formatRaises(TypeError, "{0:f}", "a string") + self.formatRaises(TypeError, "{0:F}", "a string") + self.formatRaises(TypeError, "{0:f}", 1j) + self.formatRaises(TypeError, "{0:F}", 1j) self.formatEqualsWithUnicode("3.141500", "{0:f}", 3.1415) self.formatEqualsWithUnicode("3.1415000000", "{0:.10f}", 3.1415) self.formatEqualsWithUnicode("3.1415e+200", "{0:f}", 3.1415e200) self.formatEqualsWithUnicode("3.1415e+200", "{0:F}", 3.1415e200) def test_general_specifiers(self): + self.formatRaises(TypeError, "{0:g}", "a string") + self.formatRaises(TypeError, "{0:G}", "a string") + self.formatRaises(TypeError, "{0:g}", 1j) + self.formatRaises(TypeError, "{0:G}", 1j) self.formatEqualsWithUnicodeUC("3.1415", "{0:g}", 3.1415) self.formatEqualsWithUnicodeUC("3.1415", "{0:.10g}", 3.1415) self.formatEqualsWithUnicodeUC("3.1415e+200", "{0:g}", 3.1415e200) @@ -311,6 +323,24 @@ self.formatRaises(ValueError, "{0:k}", 0) self.formatRaises(ValueError, "{0:4<10.20K}", 0) + def test_derive_from_long(self): + # make sure classes that inherit from long and don't specify + # __format__ get long's default format + class SimpleLong(long): + pass + + l = SimpleLong(2**100) + self.formatEquals("1" + "0" * 100, "{0:b}", l) + + # make sure that classes that inherit from long and do specify + # __format__ get it called + class FormatLong(long): + def __format__(self, specifiers): + return "how now brown cow" + + l = FormatLong(2**100) + self.formatEquals("how now brown cow", "{0:b}", l) + def test_name_mapper(self): mydict = dict(foo=1, bar=2) dict2 = mydict, dict(foobar=3) From python-checkins at python.org Wed Mar 7 12:37:43 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 12:37:43 +0100 (CET) Subject: [Python-checkins] r54206 - in python/trunk/Lib/test: output/test_pty test_pty.py Message-ID: <20070307113743.D2A211E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 12:37:42 2007 New Revision: 54206 Removed: python/trunk/Lib/test/output/test_pty Modified: python/trunk/Lib/test/test_pty.py Log: Patch #1675471: convert test_pty to unittest. Deleted: /python/trunk/Lib/test/output/test_pty ============================================================================== --- /python/trunk/Lib/test/output/test_pty Wed Mar 7 12:37:42 2007 +++ (empty file) @@ -1,3 +0,0 @@ -test_pty -I wish to buy a fish license. -For my pet fish, Eric. Modified: python/trunk/Lib/test/test_pty.py ============================================================================== --- python/trunk/Lib/test/test_pty.py (original) +++ python/trunk/Lib/test/test_pty.py Wed Mar 7 12:37:42 2007 @@ -1,5 +1,8 @@ -import pty, os, sys, signal -from test.test_support import verbose, TestFailed, TestSkipped +import pty +import os +import signal +from test.test_support import verbose, TestSkipped, run_unittest +import unittest TEST_STRING_1 = "I wish to buy a fish license.\n" TEST_STRING_2 = "For my pet fish, Eric.\n" @@ -11,6 +14,7 @@ def debug(msg): pass + def normalize_output(data): # Some operating systems do conversions on newline. We could possibly # fix that by doing the appropriate termios.tcsetattr()s. I couldn't @@ -32,116 +36,122 @@ return data + # Marginal testing of pty suite. Cannot do extensive 'do or fail' testing # because pty code is not too portable. +class PtyTest(unittest.TestCase): + def setUp(self): + # isatty() and close() can hang on some platforms. Set an alarm + # before running the test to make sure we don't hang forever. + self.old_alarm = signal.signal(signal.SIGALRM, self.handle_sig) + signal.alarm(10) + + def tearDown(self): + # remove alarm, restore old alarm handler + signal.alarm(0) + signal.signal(signal.SIGALRM, self.old_alarm) + + def handle_sig(self, sig, frame): + self.fail("isatty hung") + + def test_basic(self): + try: + debug("Calling master_open()") + master_fd, slave_name = pty.master_open() + debug("Got master_fd '%d', slave_name '%s'" % + (master_fd, slave_name)) + debug("Calling slave_open(%r)" % (slave_name,)) + slave_fd = pty.slave_open(slave_name) + debug("Got slave_fd '%d'" % slave_fd) + except OSError: + # " An optional feature could not be imported " ... ? + raise TestSkipped, "Pseudo-terminals (seemingly) not functional." + + self.assertTrue(os.isatty(slave_fd), 'slave_fd is not a tty') + + debug("Writing to slave_fd") + os.write(slave_fd, TEST_STRING_1) + s1 = os.read(master_fd, 1024) + self.assertEquals('I wish to buy a fish license.\n', + normalize_output(s1)) + + debug("Writing chunked output") + os.write(slave_fd, TEST_STRING_2[:5]) + os.write(slave_fd, TEST_STRING_2[5:]) + s2 = os.read(master_fd, 1024) + self.assertEquals('For my pet fish, Eric.\n', normalize_output(s2)) + + os.close(slave_fd) + os.close(master_fd) + + + def test_fork(self): + debug("calling pty.fork()") + pid, master_fd = pty.fork() + if pid == pty.CHILD: + # stdout should be connected to a tty. + if not os.isatty(1): + debug("Child's fd 1 is not a tty?!") + os._exit(3) + + # After pty.fork(), the child should already be a session leader. + # (on those systems that have that concept.) + debug("In child, calling os.setsid()") + try: + os.setsid() + except OSError: + # Good, we already were session leader + debug("Good: OSError was raised.") + pass + except AttributeError: + # Have pty, but not setsid()? + debug("No setsid() available?") + pass + except: + # We don't want this error to propagate, escaping the call to + # os._exit() and causing very peculiar behavior in the calling + # regrtest.py ! + # Note: could add traceback printing here. + debug("An unexpected error was raised.") + os._exit(1) + else: + debug("os.setsid() succeeded! (bad!)") + os._exit(2) + os._exit(4) + else: + debug("Waiting for child (%d) to finish." % pid) + ##line = os.read(master_fd, 80) + ##lines = line.replace('\r\n', '\n').split('\n') + ##if False and lines != ['In child, calling os.setsid()', + ## 'Good: OSError was raised.', '']: + ## raise TestFailed("Unexpected output from child: %r" % line) + + (pid, status) = os.waitpid(pid, 0) + res = status >> 8 + debug("Child (%d) exited with status %d (%d)." % (pid, res, status)) + if res == 1: + self.fail("Child raised an unexpected exception in os.setsid()") + elif res == 2: + self.fail("pty.fork() failed to make child a session leader.") + elif res == 3: + self.fail("Child spawned by pty.fork() did not have a tty as stdout") + elif res != 4: + self.fail("pty.fork() failed for unknown reasons.") + + ##debug("Reading from master_fd now that the child has exited") + ##try: + ## s1 = os.read(master_fd, 1024) + ##except os.error: + ## pass + ##else: + ## raise TestFailed("Read from master_fd did not raise exception") + + os.close(master_fd) + + # pty.fork() passed. -def test_basic_pty(): - try: - debug("Calling master_open()") - master_fd, slave_name = pty.master_open() - debug("Got master_fd '%d', slave_name '%s'"%(master_fd, slave_name)) - debug("Calling slave_open(%r)"%(slave_name,)) - slave_fd = pty.slave_open(slave_name) - debug("Got slave_fd '%d'"%slave_fd) - except OSError: - # " An optional feature could not be imported " ... ? - raise TestSkipped, "Pseudo-terminals (seemingly) not functional." - - if not os.isatty(slave_fd): - raise TestFailed, "slave_fd is not a tty" - - debug("Writing to slave_fd") - os.write(slave_fd, TEST_STRING_1) - s1 = os.read(master_fd, 1024) - sys.stdout.write(normalize_output(s1)) - - debug("Writing chunked output") - os.write(slave_fd, TEST_STRING_2[:5]) - os.write(slave_fd, TEST_STRING_2[5:]) - s2 = os.read(master_fd, 1024) - sys.stdout.write(normalize_output(s2)) - - os.close(slave_fd) - os.close(master_fd) - -def handle_sig(sig, frame): - raise TestFailed, "isatty hung" - -# isatty() and close() can hang on some platforms -# set an alarm before running the test to make sure we don't hang forever -old_alarm = signal.signal(signal.SIGALRM, handle_sig) -signal.alarm(10) - -try: - test_basic_pty() -finally: - # remove alarm, restore old alarm handler - signal.alarm(0) - signal.signal(signal.SIGALRM, old_alarm) - -# basic pty passed. - -debug("calling pty.fork()") -pid, master_fd = pty.fork() -if pid == pty.CHILD: - # stdout should be connected to a tty. - if not os.isatty(1): - debug("Child's fd 1 is not a tty?!") - os._exit(3) - - # After pty.fork(), the child should already be a session leader. - # (on those systems that have that concept.) - debug("In child, calling os.setsid()") - try: - os.setsid() - except OSError: - # Good, we already were session leader - debug("Good: OSError was raised.") - pass - except AttributeError: - # Have pty, but not setsid() ? - debug("No setsid() available ?") - pass - except: - # We don't want this error to propagate, escaping the call to - # os._exit() and causing very peculiar behavior in the calling - # regrtest.py ! - # Note: could add traceback printing here. - debug("An unexpected error was raised.") - os._exit(1) - else: - debug("os.setsid() succeeded! (bad!)") - os._exit(2) - os._exit(4) -else: - debug("Waiting for child (%d) to finish."%pid) - ##line = os.read(master_fd, 80) - ##lines = line.replace('\r\n', '\n').split('\n') - ##if False and lines != ['In child, calling os.setsid()', - ## 'Good: OSError was raised.', '']: - ## raise TestFailed("Unexpected output from child: %r" % line) - - (pid, status) = os.waitpid(pid, 0) - res = status >> 8 - debug("Child (%d) exited with status %d (%d)."%(pid, res, status)) - if res == 1: - raise TestFailed, "Child raised an unexpected exception in os.setsid()" - elif res == 2: - raise TestFailed, "pty.fork() failed to make child a session leader." - elif res == 3: - raise TestFailed, "Child spawned by pty.fork() did not have a tty as stdout" - elif res != 4: - raise TestFailed, "pty.fork() failed for unknown reasons." - - ##debug("Reading from master_fd now that the child has exited") - ##try: - ## s1 = os.read(master_fd, 1024) - ##except os.error: - ## pass - ##else: - ## raise TestFailed("Read from master_fd did not raise exception") - - -os.close(master_fd) +def test_main(verbose=None): + run_unittest(PtyTest) -# pty.fork() passed. +if __name__ == "__main__": + test_main() From python-checkins at python.org Wed Mar 7 12:54:54 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 12:54:54 +0100 (CET) Subject: [Python-checkins] r54207 - in python/trunk/Lib: test/test_unittest.py unittest.py Message-ID: <20070307115454.BC2E51E4003@bag.python.org> Author: georg.brandl Date: Wed Mar 7 12:54:49 2007 New Revision: 54207 Modified: python/trunk/Lib/test/test_unittest.py python/trunk/Lib/unittest.py Log: Add some sanity checks to unittest.TestSuite's addTest(s) methods. Fixes #878275. Modified: python/trunk/Lib/test/test_unittest.py ============================================================================== --- python/trunk/Lib/test/test_unittest.py (original) +++ python/trunk/Lib/test/test_unittest.py Wed Mar 7 12:54:49 2007 @@ -1580,6 +1580,19 @@ pass else: self.fail("Failed to raise TypeError") + + def test_addTest__noncallable(self): + suite = unittest.TestSuite() + self.assertRaises(TypeError, suite.addTest, 5) + + def test_addTest__casesuiteclass(self): + suite = unittest.TestSuite() + self.assertRaises(TypeError, suite.addTest, Test_TestSuite) + self.assertRaises(TypeError, suite.addTest, unittest.TestSuite) + + def test_addTests__string(self): + suite = unittest.TestSuite() + self.assertRaises(TypeError, suite.addTests, "foo") class Test_FunctionTestCase(TestCase): Modified: python/trunk/Lib/unittest.py ============================================================================== --- python/trunk/Lib/unittest.py (original) +++ python/trunk/Lib/unittest.py Wed Mar 7 12:54:49 2007 @@ -428,9 +428,18 @@ return cases def addTest(self, test): + # sanity checks + if not callable(test): + raise TypeError("the test to add must be callable") + if (isinstance(test, (type, types.ClassType)) and + issubclass(test, (TestCase, TestSuite))): + raise TypeError("TestCases and TestSuites must be instantiated " + "before passing them to addTest()") self._tests.append(test) def addTests(self, tests): + if isinstance(tests, basestring): + raise TypeError("tests must be an iterable of tests, not a string") for test in tests: self.addTest(test) From python-checkins at python.org Wed Mar 7 12:55:27 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 12:55:27 +0100 (CET) Subject: [Python-checkins] r54208 - python/branches/release25-maint/Lib/unittest.py Message-ID: <20070307115527.E88C41E400D@bag.python.org> Author: georg.brandl Date: Wed Mar 7 12:55:25 2007 New Revision: 54208 Modified: python/branches/release25-maint/Lib/unittest.py Log: backport rev. 54207: add a few sanity checks in unittest.TestSuite.addTest(s). Modified: python/branches/release25-maint/Lib/unittest.py ============================================================================== --- python/branches/release25-maint/Lib/unittest.py (original) +++ python/branches/release25-maint/Lib/unittest.py Wed Mar 7 12:55:25 2007 @@ -411,9 +411,18 @@ return cases def addTest(self, test): + # sanity checks + if not callable(test): + raise TypeError("the test to add must be callable") + if (isinstance(test, (type, types.ClassType)) and + issubclass(test, (TestCase, TestSuite))): + raise TypeError("TestCases and TestSuites must be instantiated " + "before passing them to addTest()") self._tests.append(test) def addTests(self, tests): + if isinstance(tests, basestring): + raise TypeError("tests must be an iterable of tests, not a string") for test in tests: self.addTest(test) From buildbot at python.org Wed Mar 7 13:26:10 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 12:26:10 +0000 Subject: [Python-checkins] buildbot warnings in sparc solaris10 gcc trunk Message-ID: <20070307122610.D25741E4003@bag.python.org> The Buildbot has detected a new failure of sparc solaris10 gcc trunk. Full details are available at: http://www.python.org/dev/buildbot/all/sparc%2520solaris10%2520gcc%2520trunk/builds/1821 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 2 tests failed: test_posixpath test_pty ====================================================================== FAIL: test_basic (test.test_pty.PtyTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/opt/users/buildbot/slave/trunk.loewis-sun/build/Lib/test/test_pty.py", line 76, in test_basic normalize_output(s1)) AssertionError: 'I wish to buy a fish license.\n' != '' sincerely, -The Buildbot From buildbot at python.org Wed Mar 7 13:26:30 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 12:26:30 +0000 Subject: [Python-checkins] buildbot warnings in ia64 Ubuntu trunk trunk Message-ID: <20070307122631.0DF8B1E4003@bag.python.org> The Buildbot has detected a new failure of ia64 Ubuntu trunk trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ia64%2520Ubuntu%2520trunk%2520trunk/builds/438 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl,martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Wed Mar 7 13:41:17 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 12:41:17 +0000 Subject: [Python-checkins] buildbot warnings in x86 mvlgcc trunk Message-ID: <20070307124117.C3E901E4016@bag.python.org> The Buildbot has detected a new failure of x86 mvlgcc trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520mvlgcc%2520trunk/builds/310 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Wed Mar 7 13:58:10 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 12:58:10 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 2.5 Message-ID: <20070307125811.4A5A01E4003@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%25202.5/builds/192 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 2 tests failed: test_signal test_socket sincerely, -The Buildbot From buildbot at python.org Wed Mar 7 14:12:20 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 13:12:20 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070307131220.BAFFD1E4003@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/90 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Wed Mar 7 16:16:32 2007 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 7 Mar 2007 16:16:32 +0100 (CET) Subject: [Python-checkins] r54209 - python/trunk/Lib/test/test_datetime.py Message-ID: <20070307151632.BE5351E400D@bag.python.org> Author: guido.van.rossum Date: Wed Mar 7 16:16:29 2007 New Revision: 54209 Modified: python/trunk/Lib/test/test_datetime.py Log: Windows doesn't support negative timestamps. Skip the tests involving them if os.name == "nt". Modified: python/trunk/Lib/test/test_datetime.py ============================================================================== --- python/trunk/Lib/test/test_datetime.py (original) +++ python/trunk/Lib/test/test_datetime.py Wed Mar 7 16:16:29 2007 @@ -3,6 +3,7 @@ See http://www.zope.org/Members/fdrake/DateTimeWiki/TestCases """ +import os import sys import pickle import cPickle @@ -1426,11 +1427,17 @@ insane) def test_negative_float_fromtimestamp(self): + # Windows doesn't accept negative timestamps + if os.name == "nt": + return # The result is tz-dependent; at least test that this doesn't # fail (like it did before bug 1646728 was fixed). self.theclass.fromtimestamp(-1.05) def test_negative_float_utcfromtimestamp(self): + # Windows doesn't accept negative timestamps + if os.name == "nt": + return d = self.theclass.utcfromtimestamp(-1.05) self.assertEquals(d, self.theclass(1969, 12, 31, 23, 59, 58, 950000)) From buildbot at python.org Wed Mar 7 16:39:43 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 15:39:43 +0000 Subject: [Python-checkins] buildbot warnings in x86 gentoo trunk Message-ID: <20070307153943.D648F1E4003@bag.python.org> The Buildbot has detected a new failure of x86 gentoo trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%2520trunk/builds/1987 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: guido.van.rossum Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Wed Mar 7 16:46:37 2007 From: python-checkins at python.org (eric.smith) Date: Wed, 7 Mar 2007 16:46:37 +0100 (CET) Subject: [Python-checkins] r54210 - sandbox/trunk/pep3101/test_simpleformat.py Message-ID: <20070307154637.75ECF1E4003@bag.python.org> Author: eric.smith Date: Wed Mar 7 16:46:33 2007 New Revision: 54210 Modified: sandbox/trunk/pep3101/test_simpleformat.py Log: Added more extensive binary formatting (':b') tests. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Wed Mar 7 16:46:33 2007 @@ -276,6 +276,16 @@ self.formatEqualsWithUnicode("-" + "1" * 100, "{0:b}", -(2**100 - 1)) self.formatEqualsWithUnicode("(" + "1" * 100 + ")", "{0:()b}", -(2**100 - 1)) self.formatEqualsWithUnicode("(" + " " * 98 + "1" * 100 + ")", "{0:=()200b}", -(2**100 - 1)) + for n in range(1, 100): + # build an n bit integer, alternating ones and zeros + # as n gets large, these will become longs + s = "10" * (n / 2) + (n % 2 and "1" or "") + i = int(s, 2) + self.formatEquals(s, "{0:b}", i) + + # make sure negative also works, hoping to catch an + # overflow off the end of the digits + self.formatEquals("(" + s + ")", "{0:()b}", -i) def test_number_specifier(self): def test(value): From python-checkins at python.org Wed Mar 7 17:12:12 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 7 Mar 2007 17:12:12 +0100 (CET) Subject: [Python-checkins] r54211 - python/branches/release25-maint/Lib/test/test_datetime.py Message-ID: <20070307161212.BEE721E4004@bag.python.org> Author: georg.brandl Date: Wed Mar 7 17:12:05 2007 New Revision: 54211 Modified: python/branches/release25-maint/Lib/test/test_datetime.py Log: Backport skipping fromtimestamp(negative value) tests on Windows (from rev. 54209) Modified: python/branches/release25-maint/Lib/test/test_datetime.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_datetime.py (original) +++ python/branches/release25-maint/Lib/test/test_datetime.py Wed Mar 7 17:12:05 2007 @@ -3,6 +3,7 @@ See http://www.zope.org/Members/fdrake/DateTimeWiki/TestCases """ +import os import sys import pickle import cPickle @@ -1426,11 +1427,17 @@ insane) def test_negative_float_fromtimestamp(self): + # Windows doesn't accept negative timestamps + if os.name == "nt": + return # The result is tz-dependent; at least test that this doesn't # fail (like it did before bug 1646728 was fixed). self.theclass.fromtimestamp(-1.05) def test_negative_float_utcfromtimestamp(self): + # Windows doesn't accept negative timestamps + if os.name == "nt": + return d = self.theclass.utcfromtimestamp(-1.05) self.assertEquals(d, self.theclass(1969, 12, 31, 23, 59, 58, 950000)) From buildbot at python.org Wed Mar 7 18:38:41 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 07 Mar 2007 17:38:41 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 Message-ID: <20070307173841.C2EC21E4004@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/47 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Wed Mar 7 23:07:13 2007 From: python-checkins at python.org (eric.smith) Date: Wed, 7 Mar 2007 23:07:13 +0100 (CET) Subject: [Python-checkins] r54212 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070307220713.583131E4014@bag.python.org> Author: eric.smith Date: Wed Mar 7 23:07:08 2007 New Revision: 54212 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Removed longintrepr.h. I no longer look at PyLong internals; instead everything works through functions exported by PyLong, although some begin with underscores like _PyLong_Sign(). The only code this affected is the base 2 output for longs in _format_long_binary(). Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Wed Mar 7 23:07:08 2007 @@ -20,9 +20,6 @@ #define C_UNICODE 1 #endif -/* we need access to a PyLongObject's internals */ -#include "longintrepr.h" - #if C_UNICODE #define CH_TYPE Py_UNICODE #define CH_TYPE_ISDECIMAL Py_UNICODE_ISDECIMAL @@ -1115,21 +1112,33 @@ return p_digits; } +/* call _PyLong_AsByteArray to get the bytes, then do the formatting. + note that for negative numbers, the byte array will be two's + complement, and we need to undo that. */ static int -_format_long_binary(PyObject *v, FmtState *fs, const InternalFormatSpec *format) -{ - /* we know that v is a PyLongObject */ +_format_long_binary(PyObject *v, FmtState *fs, const +InternalFormatSpec *format) { /* we know that v is a PyLongObject */ PyLongObject* l = (PyLongObject*)v; IntegerFieldWidths spec; CH_TYPE *pbuf; CH_TYPE *start; - char sign = _PyLong_Sign(v) >= 0 ? '\0' : '-'; + + size_t bytes_required; + int is_negative = _PyLong_Sign(v) < 0; + unsigned char* byte_buffer; + unsigned char* start_byte_buffer; + char sign = is_negative ? '-' : '\0'; Py_ssize_t n_digits = _PyLong_NumBits(v); - Py_ssize_t i; + int is_zero = n_digits == 0; + int carry_bit; - /* special case for zero */ - if (l->ob_size == 0) + /* check for error getting number of bits */ + if (n_digits < 0) + return 0; + + /* special case for zero. it takes one digit, despite having zero bits */ + if (is_zero) n_digits = 1; _calc_integer_widths(&spec, sign, n_digits, format); @@ -1143,24 +1152,71 @@ format->fill_char == '\0' ? ' ' : format->fill_char); /* degenerate case for zero. handle it and get out */ - if (l->ob_size == 0) { + if (is_zero) { *pbuf = '0'; return 1; } - /* finally, fill in the digits, starting at the right and working left */ + /* copy the bytes into the output buffer. we know they'll fit, + because we have enough space for a textual representation */ + + /* how many bytes this long will require. we allocate on extra + bit (by not subtracting 1 from the number of bits) because the + sign bit might be needed */ + bytes_required = n_digits / 8 + 1; + byte_buffer = (unsigned char*)start; /* where to put the bytes */ + start_byte_buffer = byte_buffer; + /* use little endian so we can start at the lsb and overwrite as we + go higher */ + if (_PyLong_AsByteArray(l, byte_buffer, bytes_required, 0, 1) < 0) + return 0; + + /* adjust byte_buffer to point to the end of the string of digits */ + byte_buffer += bytes_required - 1; + /* and adjust the output pointer to point to the end of the + CH_TYPE output buffer */ pbuf = start + n_digits - 1; - for (i = 0; i < ABS(l->ob_size); i++) { - Py_ssize_t j; - digit d = l->ob_digit[i]; - for (j = 0; j < SHIFT; j++, d >>= 1) { - if (d & 1) + carry_bit = 1; /* two's complement setup */ + + /* finally, fill in the digits, starting at the right and working + left */ + while (1) { + int j; + unsigned char byte = *byte_buffer; + + /* this test is just trying to make sure we don't go past the + beginning of the byte buffer. IIRC, it's illegal to + decrement a pointer past the beginning of what it points + to. not that it probably matters, but let's be as + conformant as possible */ + if (byte_buffer != start_byte_buffer) + byte_buffer--; + + /* two's complement algorithm */ + if (is_negative) { + byte = ~byte; + if (byte == 0xff && carry_bit) { + /* this is the only case where the carry bit will be + set */ + byte = 0; + carry_bit = 1; + } else { + /* we know adding won't overflow */ + byte += carry_bit; + carry_bit = 0; + } + } + + /* loop over each bit. this could be sped up with a table + lookup, but the mid-byte termination makes it complex */ + for (j = 0; j < 8; j++, byte >>= 1) { + if (byte & 1) *pbuf = '1'; else *pbuf = '0'; - /* see if we're done mid-digit */ + /* see if we're done mid-byte */ if (pbuf == start) goto DONE; pbuf--; From buildbot at python.org Thu Mar 8 01:32:00 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 00:32:00 +0000 Subject: [Python-checkins] buildbot warnings in MIPS Debian trunk Message-ID: <20070308003201.5930F1E4002@bag.python.org> The Buildbot has detected a new failure of MIPS Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/MIPS%2520Debian%2520trunk/builds/659 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl,guido.van.rossum,martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Thu Mar 8 04:03:01 2007 From: python-checkins at python.org (eric.smith) Date: Thu, 8 Mar 2007 04:03:01 +0100 (CET) Subject: [Python-checkins] r54217 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070308030301.6F6E81E4002@bag.python.org> Author: eric.smith Date: Thu Mar 8 04:02:55 2007 New Revision: 54217 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Fixed a comment that got stepped on due to reformatting. Improved some other comments. Added test cases, primarily focusing on longs. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Thu Mar 8 04:02:55 2007 @@ -171,6 +171,11 @@ # XXX I'm not sure this is correct, maybe it should be " (123)" self.formatEqualsWithUnicode("( 123)", "{0:=()10d}", -123) + self.formatEqualsWithUnicode(" (123)", "{0:>()10d}", -123) + self.formatEqualsWithUnicode("(123) ", "{0:<()10d}", -123) + self.formatEqualsWithUnicode("( 123)", "{0:=()10d}", long(-123)) + self.formatEqualsWithUnicode(" (123)", "{0:>()10d}", long(-123)) + self.formatEqualsWithUnicode("(123) ", "{0:<()10d}", long(-123)) self.formatEqualsWithUnicode("1" + "0" * 100, "{0:d}", 10**100) self.formatEqualsWithUnicode("-1" + "0" * 100, "{0:d}", -10**100) @@ -179,6 +184,11 @@ self.formatEqualsWithUnicode("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) self.formatEqualsWithUnicode("( 1" + "0" * 100 + ")", "{0:()110d}", -10**100) + for base in (0, 10**10, 10**100): + for i in range(base+1, base+2000): + self.formatEqualsWithUnicode(str(i), "{0:d}", i) + self.formatEqualsWithUnicode("(" + str(i) + ")", "{0:()d}", -i) + def test_octal_specifiers(self): n = int("31415", 8) @@ -199,17 +209,25 @@ self.formatRaises(TypeError, "{0:x}", "non-number") self.formatEqualsWithUnicodeUC("0", "{0:x}", 0) + self.formatEqualsWithUnicodeUC("0", "{0:x}", long(0)) self.formatEqualsWithUnicodeUC("beef", "{0:x}", n) self.formatEqualsWithUnicodeUC("-beef", "{0:x}", -n) n = int("deadbeef", 16) self.formatEqualsWithUnicodeUC("deadbeef", "{0:x}", n) self.formatEqualsWithUnicodeUC("-deadbeef", "{0:x}", -n) + self.formatEqualsWithUnicodeUC("(deadbeef)", "{0:()x}", -n) + self.formatEqualsWithUnicodeUC("( deadbeef)", "{0:()11x}", -n) + self.formatEqualsWithUnicodeUC(" (deadbeef)", "{0:>()11x}", -n) + self.formatEqualsWithUnicodeUC(" (deadbeef)", "{0:>()11x}", long(-n)) + self.formatEqualsWithUnicodeUC("(deadbeef) ", "{0:<()11x}", -n) + self.formatEqualsWithUnicodeUC("(deadbeef) ", "{0:<()11x}", long(-n)) def test_char_specifiers(self): self.formatEqualsWithUnicode("A", "{0:c}", "A") self.formatEqualsWithUnicode("8", "{0:c}", "8") self.formatEqualsWithUnicode(";", "{0:c}", ";") + self.formatEqualsWithUnicode(";", "{0:c}", ord(";")) self.formatEqualsWithUnicode(";", "{0:c}", long(ord(";"))) self.formatEquals(u"f", u"{0:c}", u"f") @@ -276,16 +294,19 @@ self.formatEqualsWithUnicode("-" + "1" * 100, "{0:b}", -(2**100 - 1)) self.formatEqualsWithUnicode("(" + "1" * 100 + ")", "{0:()b}", -(2**100 - 1)) self.formatEqualsWithUnicode("(" + " " * 98 + "1" * 100 + ")", "{0:=()200b}", -(2**100 - 1)) - for n in range(1, 100): + for n in range(1, 1000): # build an n bit integer, alternating ones and zeros # as n gets large, these will become longs s = "10" * (n / 2) + (n % 2 and "1" or "") i = int(s, 2) - self.formatEquals(s, "{0:b}", i) + self.formatEqualsWithUnicode(s, "{0:b}", i) # make sure negative also works, hoping to catch an - # overflow off the end of the digits - self.formatEquals("(" + s + ")", "{0:()b}", -i) + # overflow off the end of the digits. an internal + # implementation detail is that the parens are inserted + # into the output buffer before the digits are, so any + # error in writing the digits might write over the parens + self.formatEqualsWithUnicode("(" + s + ")", "{0:()b}", -i) def test_number_specifier(self): def test(value): Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Thu Mar 8 04:02:55 2007 @@ -67,8 +67,8 @@ /* MAXLEN_INT_STRING is the maximum length of an integer represented - * as a string. The analysis in stringobject.c shows that 24 is the - * worst case. Allocate more, just in case. */ + * as a string, in base 10. The analysis in stringobject.c shows that + * 24 is the worst case. Allocate more, just in case. */ /* fmt = '%#.' + `prec` + 'l' + `type` worst case length = 3 + 19 (worst len of INT_MAX on 64-bit machine) + 1 + 1 = 24 */ @@ -1117,7 +1117,9 @@ complement, and we need to undo that. */ static int _format_long_binary(PyObject *v, FmtState *fs, const -InternalFormatSpec *format) { /* we know that v is a PyLongObject */ + InternalFormatSpec *format) +{ + /* we know that v is a PyLongObject */ PyLongObject* l = (PyLongObject*)v; IntegerFieldWidths spec; @@ -1129,7 +1131,9 @@ unsigned char* byte_buffer; unsigned char* start_byte_buffer; char sign = is_negative ? '-' : '\0'; - Py_ssize_t n_digits = _PyLong_NumBits(v); + Py_ssize_t n_digits = _PyLong_NumBits(v); /* same number of + output digits as we + have binary bits */ int is_zero = n_digits == 0; int carry_bit; From nnorwitz at gmail.com Thu Mar 8 05:54:23 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Wed, 7 Mar 2007 20:54:23 -0800 Subject: [Python-checkins] r54208 - python/branches/release25-maint/Lib/unittest.py In-Reply-To: <20070307115527.E88C41E400D@bag.python.org> References: <20070307115527.E88C41E400D@bag.python.org> Message-ID: I'm not sure it's the best thing to backport this. I agree with the change, but worry that people writing bad unit tests will suddenly have it break. They might have the proper signature, even if they don't inherit from the right classes. I guess the only part I'm worried about is the second if in addTest. The callable and basestring checks will just error out earlier which definitely seems reasonable. If you really feel strongly that this should go in, it should have a NEWS entry. n -- On 3/7/07, georg.brandl wrote: > Author: georg.brandl > Date: Wed Mar 7 12:55:25 2007 > New Revision: 54208 > > Modified: > python/branches/release25-maint/Lib/unittest.py > Log: > backport rev. 54207: add a few sanity checks in unittest.TestSuite.addTest(s). > > > Modified: python/branches/release25-maint/Lib/unittest.py > ============================================================================== > --- python/branches/release25-maint/Lib/unittest.py (original) > +++ python/branches/release25-maint/Lib/unittest.py Wed Mar 7 12:55:25 2007 > @@ -411,9 +411,18 @@ > return cases > > def addTest(self, test): > + # sanity checks > + if not callable(test): > + raise TypeError("the test to add must be callable") > + if (isinstance(test, (type, types.ClassType)) and > + issubclass(test, (TestCase, TestSuite))): > + raise TypeError("TestCases and TestSuites must be instantiated " > + "before passing them to addTest()") > self._tests.append(test) > > def addTests(self, tests): > + if isinstance(tests, basestring): > + raise TypeError("tests must be an iterable of tests, not a string") > for test in tests: > self.addTest(test) > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > From python-checkins at python.org Thu Mar 8 06:03:49 2007 From: python-checkins at python.org (patrick.maupin) Date: Thu, 8 Mar 2007 06:03:49 +0100 (CET) Subject: [Python-checkins] r54218 - sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070308050349.2913B1E4004@bag.python.org> Author: patrick.maupin Date: Thu Mar 8 06:03:44 2007 New Revision: 54218 Modified: sandbox/trunk/pep3101/unicodeformat.c Log: Better exception handling will require the fmtstr object, so I merged the SubString and SubstrObj structures. (I guess that was a premature optimization :) Also added comment headers to functions that didn't have them. Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Thu Mar 8 06:03:44 2007 @@ -89,22 +89,15 @@ #include "pep3101.h" /* - A SubString is a string between two unicode pointers. -*/ -typedef struct { - CH_TYPE *ptr; - CH_TYPE *end; -} SubString; - -/* - A SubStringObj is like a SubString, but also has an associated - object (which may be null). + A SubString consists of the characters between two string or + unicode pointers. It may also have an associated object, + or the object may be null. */ typedef struct { CH_TYPE *ptr; CH_TYPE *end; PyObject *obj; -} SubStringObj; +} SubString; /* A MarkupEscapeHandler allows us to handle different escape @@ -127,8 +120,9 @@ PyObject *args; /* keywords passed to PyString_FormatMethod or PyUnicode_FormatMethod */ PyObject *keywords; - /* arg_param_offset is 1 if not called as a method */ + /* Total number of positional arguments */ int num_args; + /* arg_param_offset is 1 if not called as a method */ int arg_param_offset; /* Function to call to perform markup */ MarkupEscapeHandler do_markup; @@ -137,12 +131,12 @@ /* Used for error reporting */ CH_TYPE *fmtstart, *fieldstart; /* Output string we are constructing, including current and end pointers*/ - SubStringObj outstr; + SubString outstr; /* Field Specifier, after the colon in {1:{2}} This may or may not have a valid object (the field specifier might just be a substring of the fmtstr. If it does not have its own object, the .obj struct member will be NULL */ - SubStringObj fieldspec; + SubString fieldspec; /* size_increment is used for optimizing string growth */ int size_increment; /* max_recursion is used to limit the ability of a malicious string @@ -166,6 +160,9 @@ int syntaxmode; /* Support for hooking render calls */ PyObject *hookfunc; + /* hookalways is true if we should call the hook function + on every single field, false to just call it on fields + with a specifier ending in 'p' */ int hookalways; } FmtState; @@ -277,6 +274,12 @@ return 1; } +/* + get_locals_globals builds a tuple out of our locals() + and globals() dictionaries. It only does this if we + have no positional arguments. (It will not be called + unless we have no keyword arguments.) +*/ static int get_locals_globals(FmtState *fs) { @@ -352,6 +355,11 @@ return SetError(fs, "name lookup failed"); } +/* + read_parameter reads a single parameter out of our "namespace". + + Returns object, or NULL on error. +*/ static PyObject * read_parameter(FmtState *fs, const char *keyword) { @@ -364,6 +372,11 @@ return result; } +/* + read_bool_parameter uses read_parameter to retrieve + a parameter and check it for "truth" Returns + 0 for false, 1 for true, -1 for error. +*/ static int read_bool_parameter(FmtState *fs, const char *keyword) { @@ -377,6 +390,11 @@ return result; } +/* + read_allow_under_parameter determines if leading underscores + are allowed, and saves the value so it doesn't need to + be called again later. +*/ static int read_allow_under_parameter(FmtState *fs) { @@ -385,6 +403,10 @@ return result; } +/* + read_hook_parameter retrieves the hook function, and saves the + object so it doesn't need to be called again later. +*/ static int read_hook_parameter(FmtState *fs) { @@ -398,11 +420,11 @@ /*********** Output string management functions ****************/ /************************************************************************/ -/* Fill in a SubStringObj from a Python string */ -Py_LOCAL_INLINE(SubStringObj) -make_substrobj(PyObject *obj) +/* Fill in a SubString from a Python string */ +Py_LOCAL_INLINE(SubString) +make_substr(PyObject *obj) { - SubStringObj s; + SubString s; s.obj = obj; s.ptr = STROBJ_AS_PTR(obj); s.end = STROBJ_GET_SIZE(obj) + s.ptr; @@ -657,7 +679,7 @@ myobject = recurse_format(fs); if (myobject == NULL) return 0; - fs->fieldspec = make_substrobj(myobject); + fs->fieldspec = make_substr(myobject); fs->fmtstr = savefmt; } return 1; @@ -1786,6 +1808,12 @@ return format_function(fieldobj, &format)(fieldobj, fs, &format); } +/* + get_field_spec_obj creates a string object for the fieldspec, + if necessary. (The field spec might already be an object, + or it might just be a substring of the format string, in + which case we need to copy it into a real string object.) +*/ static PyObject * get_field_spec_obj(FmtState *fs) { @@ -1799,8 +1827,8 @@ } /* - object_self_render is invoked to format an object with a defined __format__ - attribute. + object_self_render is invoked to format an object with a defined + __format__ attribute. */ static int object_self_render(FmtState *fs, PyObject *__format__) @@ -1899,6 +1927,11 @@ return result; } +/* + check_keyword compares a string against an expected + string, a character at a time, so that it works on + unicode vs. regular strings. +*/ static int check_keyword(const CH_TYPE *ptr, const char *expected, int count) { @@ -1908,6 +1941,9 @@ return 1; } +/* + process_metadata handles string metadata, e.g. "{!keyword}" +*/ static int process_metadata(FmtState *fs) { @@ -1983,8 +2019,8 @@ /************************************************************************/ /* - do_markup is the main program loop. It rummages through - the format string, looking for escapes to markup, and + do_markup is the top-level loop for the format() function. It + searches through the format string for escapes to markup codes, and calls other functions to move non-markup text to the output, and to perform the markup to the output. */ @@ -2095,7 +2131,7 @@ fs->fmtstr.end - fs->fmtstr.ptr + INITIAL_SIZE_INCREMENT); if (myobj == NULL) return NULL; - fs->outstr = make_substrobj(myobj); + fs->outstr = make_substr(myobj); fs->size_increment = INITIAL_SIZE_INCREMENT; ok = fs->do_markup(fs); @@ -2119,7 +2155,7 @@ recurse_format(FmtState *fs) { PyObject *result; - SubStringObj saveoutstr = fs->outstr; + SubString saveoutstr = fs->outstr; int saveincrement = fs->size_increment; if (--(fs->max_recursion) < 0) return SetError(fs, "Max string recursion exceeded"); @@ -2155,11 +2191,14 @@ fs->arg_param_offset = 1; fs->num_args -= 1; } - fs->fmtstr.ptr = fs->fmtstart = STROBJ_AS_PTR(self); - fs->fmtstr.end = fs->fmtstr.ptr + STROBJ_GET_SIZE(self); + fs->fmtstr = make_substr(self); return 1; } +/* + if {!useall} is set, check_args_consumed will be called to verify + that all arguments have been used during string processing. +*/ static PyObject * check_args_consumed(FmtState *fs, PyObject *result) { From g.brandl at gmx.net Thu Mar 8 08:47:54 2007 From: g.brandl at gmx.net (Georg Brandl) Date: Thu, 08 Mar 2007 08:47:54 +0100 Subject: [Python-checkins] r54208 - python/branches/release25-maint/Lib/unittest.py In-Reply-To: References: <20070307115527.E88C41E400D@bag.python.org> Message-ID: Neal Norwitz schrieb: > I'm not sure it's the best thing to backport this. I agree with the > change, but worry that people writing bad unit tests will suddenly > have it break. They might have the proper signature, even if they > don't inherit from the right classes. > > I guess the only part I'm worried about is the second if in addTest. > The callable and basestring checks will just error out earlier which > definitely seems reasonable. But this + if (isinstance(test, (type, types.ClassType)) and + issubclass(test, (TestCase, TestSuite))): + raise TypeError("TestCases and TestSuites must be instantiated " + "before passing them to addTest()") does allow for tests that don't inherit from TestCase/Suite. It only checks if the test is a TestCase, which is the common case, whether is instantiated. Georg From python-checkins at python.org Thu Mar 8 14:42:48 2007 From: python-checkins at python.org (martin.v.loewis) Date: Thu, 8 Mar 2007 14:42:48 +0100 (CET) Subject: [Python-checkins] r54219 - python/trunk/Doc/lib/liburlparse.tex Message-ID: <20070308134248.BBD2B1E4002@bag.python.org> Author: martin.v.loewis Date: Thu Mar 8 14:42:43 2007 New Revision: 54219 Modified: python/trunk/Doc/lib/liburlparse.tex Log: Add missing ) in parenthical remark. Modified: python/trunk/Doc/lib/liburlparse.tex ============================================================================== --- python/trunk/Doc/lib/liburlparse.tex (original) +++ python/trunk/Doc/lib/liburlparse.tex Thu Mar 8 14:42:43 2007 @@ -157,7 +157,7 @@ for \function{urlparse()}. \note{If \var{url} is an absolute URL (that is, starting with \code{//} - or \code{scheme://}, the \var{url}'s host name and/or scheme + or \code{scheme://}), the \var{url}'s host name and/or scheme will be present in the result. For example:} \begin{verbatim} From jimjjewett at gmail.com Thu Mar 8 18:35:04 2007 From: jimjjewett at gmail.com (Jim Jewett) Date: Thu, 8 Mar 2007 12:35:04 -0500 Subject: [Python-checkins] r54208 - python/branches/release25-maint/Lib/unittest.py In-Reply-To: References: <20070307115527.E88C41E400D@bag.python.org> Message-ID: On 3/8/07, Georg Brandl wrote: > Neal Norwitz schrieb: > > I'm not sure it's the best thing to backport this. I agree with the > > change, but worry that people writing bad unit tests will suddenly > > have it break. They might have the proper signature, even if they > > don't inherit from the right classes. > + if (isinstance(test, (type, types.ClassType)) and > + issubclass(test, (TestCase, TestSuite))): > + raise TypeError("TestCases and TestSuites must be instantiated > " > + "before passing them to addTest()") > does allow for tests that don't inherit from TestCase/Suite. It only checks > if the test is a TestCase, which is the common case, whether is > instantiated. When trying to emulate prototype-based OO (like javascript), it is common to have classes that are intended to be singletons; sometimes it isn't clear what is a class method and what is an instance method of the single instance. It is possible to create a class that itself has the right signature. I make no claims about sanity, but it is possible, so it is a concern in bugfix releases. Of course, it is also possible to create your own test runner, which might not even insist on callability. That said, it may well be that no one has done this, and that someone is going along with untested code because the checks aren't there ... so I'm not sure what to do. A what's new entry might be enough. Something along the line of: """ unittest now verifies more of its assumptions. If your tests start to fail with 2.5.1, it *might* be a problem with the tests themselves -- and you should verify that they were ever run. """ -jJ From python-checkins at python.org Thu Mar 8 18:49:10 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 8 Mar 2007 18:49:10 +0100 (CET) Subject: [Python-checkins] r54220 - python/trunk/Doc/lib/liburlparse.tex Message-ID: <20070308174910.062611E4002@bag.python.org> Author: georg.brandl Date: Thu Mar 8 18:49:06 2007 New Revision: 54220 Modified: python/trunk/Doc/lib/liburlparse.tex Log: Fix #1676656: \em is different from \emph... Modified: python/trunk/Doc/lib/liburlparse.tex ============================================================================== --- python/trunk/Doc/lib/liburlparse.tex (original) +++ python/trunk/Doc/lib/liburlparse.tex Thu Mar 8 18:49:06 2007 @@ -168,7 +168,7 @@ If you do not want that behavior, preprocess the \var{url} with \function{urlsplit()} and \function{urlunsplit()}, -removing possible \em{scheme} and \em{netloc} parts. +removing possible \emph{scheme} and \emph{netloc} parts. \end{funcdesc} \begin{funcdesc}{urldefrag}{url} From buildbot at python.org Thu Mar 8 18:49:10 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 17:49:10 +0000 Subject: [Python-checkins] buildbot failure in g4 osx.4 2.5 Message-ID: <20070308174910.350361E4004@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%25202.5/builds/251 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Jaren': Ethan Build Source Stamp: [branch Jonatan] Curtis Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From python-checkins at python.org Thu Mar 8 18:49:19 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 8 Mar 2007 18:49:19 +0100 (CET) Subject: [Python-checkins] r54221 - python/branches/release25-maint/Doc/lib/liburlparse.tex Message-ID: <20070308174919.0957C1E4002@bag.python.org> Author: georg.brandl Date: Thu Mar 8 18:49:17 2007 New Revision: 54221 Modified: python/branches/release25-maint/Doc/lib/liburlparse.tex Log: Fix #1676656: \em is different from \emph... (backport from rev. 54220) Modified: python/branches/release25-maint/Doc/lib/liburlparse.tex ============================================================================== --- python/branches/release25-maint/Doc/lib/liburlparse.tex (original) +++ python/branches/release25-maint/Doc/lib/liburlparse.tex Thu Mar 8 18:49:17 2007 @@ -168,7 +168,7 @@ If you do not want that behavior, preprocess the \var{url} with \function{urlsplit()} and \function{urlunsplit()}, -removing possible \em{scheme} and \em{netloc} parts. +removing possible \emph{scheme} and \emph{netloc} parts. \end{funcdesc} \begin{funcdesc}{urldefrag}{url} From buildbot at python.org Thu Mar 8 18:55:54 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 17:55:54 +0000 Subject: [Python-checkins] buildbot failure in x86 gentoo 2.5 Message-ID: <20070308175554.806591E4005@bag.python.org> The Buildbot has detected a new failure of x86 gentoo 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%25202.5/builds/265 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Kendrick': Isidro Build Source Stamp: [branch Javen] Ethen Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From python-checkins at python.org Thu Mar 8 19:37:31 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 8 Mar 2007 19:37:31 +0100 (CET) Subject: [Python-checkins] r54222 - python/trunk/Misc/NEWS Message-ID: <20070308183731.EAE891E4002@bag.python.org> Author: georg.brandl Date: Thu Mar 8 19:37:31 2007 New Revision: 54222 Modified: python/trunk/Misc/NEWS Log: Add a NEWS entry for rev. 54207,8. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Thu Mar 8 19:37:31 2007 @@ -154,6 +154,12 @@ - Bug #1115886: os.path.splitext('.cshrc') gives now ('.cshrc', ''). +- unittest now verifies more of its assumptions. In particular, TestCase + and TestSuite subclasses (not instances) are no longer accepted in + TestSuite.addTest(). This should cause no incompatibility since it + never made sense with ordinary subclasses -- the failure just occurred + later, with a more cumbersome exception. + - Patch #787789: allow to pass custom TestRunner instances to unittest's main() function. From python-checkins at python.org Thu Mar 8 19:37:36 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 8 Mar 2007 19:37:36 +0100 (CET) Subject: [Python-checkins] r54223 - python/branches/release25-maint/Misc/NEWS Message-ID: <20070308183736.52E961E4002@bag.python.org> Author: georg.brandl Date: Thu Mar 8 19:37:35 2007 New Revision: 54223 Modified: python/branches/release25-maint/Misc/NEWS Log: Add a NEWS entry for rev. 54207,8. (backport from rev. 54222) Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Thu Mar 8 19:37:35 2007 @@ -197,6 +197,12 @@ Library ------- +- unittest now verifies more of its assumptions. In particular, TestCase + and TestSuite subclasses (not instances) are no longer accepted in + TestSuite.addTest(). This should cause no incompatibility since it + never made sense with ordinary subclasses -- the failure just occurred + later, with a more cumbersome exception. + - Patch #1001604: glob.glob() now returns unicode filenames if it was given a unicode argument and os.listdir() returns unicode filenames. From g.brandl at gmx.net Thu Mar 8 19:37:31 2007 From: g.brandl at gmx.net (Georg Brandl) Date: Thu, 08 Mar 2007 19:37:31 +0100 Subject: [Python-checkins] r54208 - python/branches/release25-maint/Lib/unittest.py In-Reply-To: References: <20070307115527.E88C41E400D@bag.python.org> Message-ID: Jim Jewett schrieb: > On 3/8/07, Georg Brandl wrote: >> Neal Norwitz schrieb: >> > I'm not sure it's the best thing to backport this. I agree with the >> > change, but worry that people writing bad unit tests will suddenly >> > have it break. They might have the proper signature, even if they >> > don't inherit from the right classes. > >> + if (isinstance(test, (type, types.ClassType)) and >> + issubclass(test, (TestCase, TestSuite))): >> + raise TypeError("TestCases and TestSuites must be instantiated >> " >> + "before passing them to addTest()") > >> does allow for tests that don't inherit from TestCase/Suite. It only checks >> if the test is a TestCase, which is the common case, whether is >> instantiated. > > When trying to emulate prototype-based OO (like javascript), it is > common to have classes that are intended to be singletons; sometimes > it isn't clear what is a class method and what is an instance method > of the single instance. > > It is possible to create a class that itself has the right signature. > I make no claims about sanity, but it is possible, so it is a concern > in bugfix releases. > > Of course, it is also possible to create your own test runner, which > might not even insist on callability. > > That said, it may well be that no one has done this, and that someone > is going along with untested code because the checks aren't there ... > so I'm not sure what to do. A what's new entry might be enough. > Something along the line of: > > """ > unittest now verifies more of its assumptions. If your tests start to > fail with 2.5.1, it *might* be a problem with the tests themselves -- > and you should verify that they were ever run. > """ Agreed. I added a NEWS item. Georg From nnorwitz at gmail.com Thu Mar 8 19:39:59 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Thu, 8 Mar 2007 10:39:59 -0800 Subject: [Python-checkins] r54208 - python/branches/release25-maint/Lib/unittest.py In-Reply-To: References: <20070307115527.E88C41E400D@bag.python.org> Message-ID: On 3/8/07, Georg Brandl wrote: > > Agreed. I added a NEWS item. Thanks! That's good enough for me. n From python-checkins at python.org Thu Mar 8 20:23:26 2007 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 8 Mar 2007 20:23:26 +0100 (CET) Subject: [Python-checkins] r54224 - in python/branches/release25-maint: Lib/sched.py Misc/NEWS Message-ID: <20070308192326.C83401E4002@bag.python.org> Author: raymond.hettinger Date: Thu Mar 8 20:23:25 2007 New Revision: 54224 Modified: python/branches/release25-maint/Lib/sched.py python/branches/release25-maint/Misc/NEWS Log: SF 1676321: empty() returned wrong result Modified: python/branches/release25-maint/Lib/sched.py ============================================================================== --- python/branches/release25-maint/Lib/sched.py (original) +++ python/branches/release25-maint/Lib/sched.py Thu Mar 8 20:23:25 2007 @@ -72,7 +72,7 @@ def empty(self): """Check whether the queue is empty.""" - return not not self.queue + return not self.queue def run(self): """Execute events until the queue is empty. Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Thu Mar 8 20:23:25 2007 @@ -197,6 +197,8 @@ Library ------- +- Bugs #1676321: the empty() function in sched.py returned the wrong result + - unittest now verifies more of its assumptions. In particular, TestCase and TestSuite subclasses (not instances) are no longer accepted in TestSuite.addTest(). This should cause no incompatibility since it From python-checkins at python.org Thu Mar 8 20:24:27 2007 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 8 Mar 2007 20:24:27 +0100 (CET) Subject: [Python-checkins] r54225 - python/trunk/Lib/sched.py Message-ID: <20070308192427.CC7051E4002@bag.python.org> Author: raymond.hettinger Date: Thu Mar 8 20:24:27 2007 New Revision: 54225 Modified: python/trunk/Lib/sched.py Log: SF 1676321: empty() returned wrong result Modified: python/trunk/Lib/sched.py ============================================================================== --- python/trunk/Lib/sched.py (original) +++ python/trunk/Lib/sched.py Thu Mar 8 20:24:27 2007 @@ -72,7 +72,7 @@ def empty(self): """Check whether the queue is empty.""" - return not not self.queue + return not self.queue def run(self): """Execute events until the queue is empty. From python-checkins at python.org Thu Mar 8 20:58:15 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 8 Mar 2007 20:58:15 +0100 (CET) Subject: [Python-checkins] r54227 - python/trunk/Lib/test/regrtest.py Message-ID: <20070308195815.B5EBD1E4002@bag.python.org> Author: collin.winter Date: Thu Mar 8 20:58:14 2007 New Revision: 54227 Modified: python/trunk/Lib/test/regrtest.py Log: Backported r54226 from p3yk: Move test_unittest, test_doctest and test_doctest2 higher up in the testing order. Modified: python/trunk/Lib/test/regrtest.py ============================================================================== --- python/trunk/Lib/test/regrtest.py (original) +++ python/trunk/Lib/test/regrtest.py Thu Mar 8 20:58:14 2007 @@ -474,6 +474,9 @@ 'test_builtin', 'test_exceptions', 'test_types', + 'test_unittest', + 'test_doctest', + 'test_doctest2', ] NOTTESTS = [ From python-checkins at python.org Thu Mar 8 20:58:48 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 8 Mar 2007 20:58:48 +0100 (CET) Subject: [Python-checkins] r54228 - python/branches/release25-maint/Lib/test/regrtest.py Message-ID: <20070308195848.9CE3C1E4002@bag.python.org> Author: collin.winter Date: Thu Mar 8 20:58:46 2007 New Revision: 54228 Modified: python/branches/release25-maint/Lib/test/regrtest.py Log: Backported r54226 from p3yk: Move test_unittest, test_doctest and test_doctest2 higher up in the testing order. Modified: python/branches/release25-maint/Lib/test/regrtest.py ============================================================================== --- python/branches/release25-maint/Lib/test/regrtest.py (original) +++ python/branches/release25-maint/Lib/test/regrtest.py Thu Mar 8 20:58:46 2007 @@ -474,6 +474,9 @@ 'test_builtin', 'test_exceptions', 'test_types', + 'test_unittest', + 'test_doctest', + 'test_doctest2', ] NOTTESTS = [ From python-checkins at python.org Thu Mar 8 22:30:58 2007 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 8 Mar 2007 22:30:58 +0100 (CET) Subject: [Python-checkins] r54229 - in python/branches/release25-maint: Lib/difflib.py Misc/NEWS Message-ID: <20070308213058.9FE7B1E401C@bag.python.org> Author: raymond.hettinger Date: Thu Mar 8 22:30:55 2007 New Revision: 54229 Modified: python/branches/release25-maint/Lib/difflib.py python/branches/release25-maint/Misc/NEWS Log: SF #1637850: make_table in difflib did not work with unicode Modified: python/branches/release25-maint/Lib/difflib.py ============================================================================== --- python/branches/release25-maint/Lib/difflib.py (original) +++ python/branches/release25-maint/Lib/difflib.py Thu Mar 8 22:30:55 2007 @@ -1945,8 +1945,7 @@ fromlist,tolist,flaglist,next_href,next_id = self._convert_flags( fromlist,tolist,flaglist,context,numlines) - import cStringIO - s = cStringIO.StringIO() + s = [] fmt = ' %s%s' + \ '%s%s\n' for i in range(len(flaglist)): @@ -1954,9 +1953,9 @@ # mdiff yields None on separator lines skip the bogus ones # generated for the first line if i > 0: - s.write(' \n \n') + s.append(' \n \n') else: - s.write( fmt % (next_id[i],next_href[i],fromlist[i], + s.append( fmt % (next_id[i],next_href[i],fromlist[i], next_href[i],tolist[i])) if fromdesc or todesc: header_row = '%s%s%s%s' % ( @@ -1968,7 +1967,7 @@ header_row = '' table = self._table_template % dict( - data_rows=s.getvalue(), + data_rows=''.join(s), header_row=header_row, prefix=self._prefix[1]) Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Thu Mar 8 22:30:55 2007 @@ -197,6 +197,8 @@ Library ------- +- Bug #1637850: make_table in difflib did not work with unicode + - Bugs #1676321: the empty() function in sched.py returned the wrong result - unittest now verifies more of its assumptions. In particular, TestCase From python-checkins at python.org Thu Mar 8 22:33:50 2007 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 8 Mar 2007 22:33:50 +0100 (CET) Subject: [Python-checkins] r54230 - python/trunk/Lib/difflib.py Message-ID: <20070308213350.2F8491E4011@bag.python.org> Author: raymond.hettinger Date: Thu Mar 8 22:33:47 2007 New Revision: 54230 Modified: python/trunk/Lib/difflib.py Log: SF #1637850: make_table in difflib did not work with unicode Modified: python/trunk/Lib/difflib.py ============================================================================== --- python/trunk/Lib/difflib.py (original) +++ python/trunk/Lib/difflib.py Thu Mar 8 22:33:47 2007 @@ -1945,8 +1945,7 @@ fromlist,tolist,flaglist,next_href,next_id = self._convert_flags( fromlist,tolist,flaglist,context,numlines) - import cStringIO - s = cStringIO.StringIO() + s = [] fmt = ' %s%s' + \ '%s%s\n' for i in range(len(flaglist)): @@ -1954,9 +1953,9 @@ # mdiff yields None on separator lines skip the bogus ones # generated for the first line if i > 0: - s.write(' \n \n') + s.append(' \n \n') else: - s.write( fmt % (next_id[i],next_href[i],fromlist[i], + s.append( fmt % (next_id[i],next_href[i],fromlist[i], next_href[i],tolist[i])) if fromdesc or todesc: header_row = '%s%s%s%s' % ( @@ -1968,7 +1967,7 @@ header_row = '' table = self._table_template % dict( - data_rows=s.getvalue(), + data_rows=''.join(s), header_row=header_row, prefix=self._prefix[1]) From buildbot at python.org Thu Mar 8 22:48:04 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 21:48:04 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 2.5 Message-ID: <20070308214804.AB1CD1E4002@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%25202.5/builds/195 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket ====================================================================== FAIL: testInterruptedTimeout (test.test_socket.TCPTimeoutTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/net/ringneck/scratch1/nnorwitz/python/2.5.norwitz-tru64/build/Lib/test/test_socket.py", line 872, in testInterruptedTimeout self.fail("got Alarm in wrong place") AssertionError: got Alarm in wrong place sincerely, -The Buildbot From buildbot at python.org Thu Mar 8 23:11:12 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 22:11:12 +0000 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk Message-ID: <20070308221112.944C51E4002@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%2520trunk/builds/1806 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Thu Mar 8 23:14:31 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 22:14:31 +0000 Subject: [Python-checkins] buildbot warnings in x86 mvlgcc trunk Message-ID: <20070308221431.3932B1E4002@bag.python.org> The Buildbot has detected a new failure of x86 mvlgcc trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520mvlgcc%2520trunk/builds/314 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: raymond.hettinger Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Thu Mar 8 23:15:43 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 22:15:43 +0000 Subject: [Python-checkins] buildbot warnings in S-390 Debian 2.5 Message-ID: <20070308221544.160851E4011@bag.python.org> The Buildbot has detected a new failure of S-390 Debian 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/S-390%2520Debian%25202.5/builds/203 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 557, in runtest_inner indirect_test() File "/home/pybot/buildarea/2.5.klose-debian-s390/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/pybot/buildarea/2.5.klose-debian-s390/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/pybot/buildarea/2.5.klose-debian-s390/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/pybot/buildarea/2.5.klose-debian-s390/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/pybot/buildarea/2.5.klose-debian-s390/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/pybot/buildarea/2.5.klose-debian-s390/build/Lib/httplib.py", line 856, in endheaders self._send_output() File "/home/pybot/buildarea/2.5.klose-debian-s390/build/Lib/httplib.py", line 728, in _send_output self.send(msg) File "/home/pybot/buildarea/2.5.klose-debian-s390/build/Lib/httplib.py", line 695, in send self.connect() File "/home/pybot/buildarea/2.5.klose-debian-s390/build/Lib/httplib.py", line 1130, in connect sock.connect((self.host, self.port)) File "", line 1, in connect IOError: [Errno socket error] (110, 'Connection timed out') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Thu Mar 8 23:16:28 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 8 Mar 2007 23:16:28 +0100 (CET) Subject: [Python-checkins] r54232 - python/trunk/Lib/tempfile.py Message-ID: <20070308221628.711B51E4015@bag.python.org> Author: collin.winter Date: Thu Mar 8 23:16:25 2007 New Revision: 54232 Modified: python/trunk/Lib/tempfile.py Log: Patch #1668482: don't use '-' in mkstemp Modified: python/trunk/Lib/tempfile.py ============================================================================== --- python/trunk/Lib/tempfile.py (original) +++ python/trunk/Lib/tempfile.py Thu Mar 8 23:16:25 2007 @@ -114,7 +114,7 @@ characters = ("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + - "0123456789-_") + "0123456789_") def __init__(self): self.mutex = _allocate_lock() From buildbot at python.org Thu Mar 8 23:43:17 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 22:43:17 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable trunk Message-ID: <20070308224317.D99681E4002@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%2520trunk/builds/140 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: raymond.hettinger Build had warnings: warnings test Excerpt from the test logfile: 2 tests failed: test_posixpath test_socket_ssl make: *** [buildbottest] Error 1 sincerely, -The Buildbot From nnorwitz at gmail.com Thu Mar 8 23:44:37 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Thu, 8 Mar 2007 17:44:37 -0500 Subject: [Python-checkins] Python Regression Test Failures all (1) Message-ID: <20070308224437.GA4446@python.psfb.org> test_grammar test_opcodes test_operations test_builtin test_exceptions test_types test_unittest test_doctest test_doctest2 test_MimeWriter test_StringIO test___all__ test___future__ test__locale test_aepack test_aepack skipped -- No module named aepack test_al test_al skipped -- No module named al test_anydbm test_applesingle test_applesingle skipped -- No module named macostools test_array test_ast test_asynchat WARNING: failed to listen on port 54322, trying another WARNING: failed to listen on port 9907, trying another test_atexit test_audioop test_augassign test_base64 test_bastion test_bigaddrspace test_bigmem test_binascii test_binhex test_binop test_bisect test_bool test_bsddb test_bsddb185 test_bsddb185 skipped -- No module named bsddb185 test_bsddb3 test_bufio test_bz2 test_cProfile test_calendar test_call test_capi test_cd test_cd skipped -- No module named cd test_cfgparser test_cgi test_charmapcodec test_cl test_cl skipped -- No module named cl test_class test_cmath test_cmd_line test_code test_codeccallbacks test_codecencodings_cn test_codecencodings_hk test_codecencodings_jp test_codecencodings_kr test_codecencodings_tw test_codecmaps_cn test_codecmaps_hk test_codecmaps_jp test_codecmaps_kr test_codecmaps_tw test_codecs test_codeop test_coding test_coercion test_collections test_colorsys test_commands test_compare test_compile test_compiler testCompileLibrary still working, be patient... test_complex test_complex_args test_contains test_contextlib test_cookie test_cookielib test_copy test_copy_reg test_cpickle test_crypt test_csv test_ctypes test_datetime test_dbm test_decimal test_decorators test_defaultdict test_deque test_descr test_descrtut test_dict test_difflib test_dircache test_dis test_distutils test_dl test_dumbdbm test_dummy_thread test_dummy_threading test_email test_email_codecs test_email_renamed test_enumerate test_eof test_errno test_exception_variations test_extcall test_fcntl test_file test_filecmp test_fileinput test_float test_fnmatch test_fork1 test_format test_fpformat test_frozen test_funcattrs test_functools test_future test_gc test_gdbm test_generators test_genericpath test_genexps test_getargs test_getargs2 test_getopt test_gettext test_gl test_gl skipped -- No module named gl test_glob test_global test_grp test_gzip test_hash test_hashlib test_heapq test_hexoct test_hmac test_hotshot test_htmllib test_htmlparser test_httplib test_imageop test_imaplib test_imgfile test_imgfile skipped -- No module named imgfile test_imp test_import test_importhooks test_index test_inspect test_ioctl test_ioctl skipped -- Unable to open /dev/tty test_isinstance test_iter test_iterlen test_itertools test_largefile test_list test_locale test_logging test_long test_long_future test_longexp test_macfs test_macfs skipped -- No module named macfs test_macostools test_macostools skipped -- No module named macostools test_macpath test_mailbox test_marshal test_math test_md5 test_mhlib test_mimetools test_mimetypes test_minidom test_mmap test_module test_modulefinder test_multibytecodec test_multibytecodec_support test_multifile test_mutants test_netrc test_new test_nis test_normalization test_ntpath test_old_mailbox test_openpty test_operator test_optparse test_os test_parser test_peepholer test_pep247 test_pep263 test_pep277 test_pep277 skipped -- test works only on NT+ test_pep292 test_pep352 test_pickle test_pickletools test_pkg test_pkgimport test_platform test_plistlib test_plistlib skipped -- No module named plistlib test_poll test_popen [7321 refs] [7321 refs] [7321 refs] test_popen2 test_posix test_posixpath test_pow test_pprint test_profile test_profilehooks test_pty test_pwd test_pyclbr test_pyexpat test_queue test_quopri [7696 refs] [7696 refs] test_random test_re test_repr test_resource test_rfc822 test_rgbimg test_richcmp test_robotparser test_runpy test_sax test_scope test_scriptpackages test_scriptpackages skipped -- No module named aetools test_select test_set test_sets test_sgmllib test_sha test_shelve test_shlex test_shutil test_signal test_site test_slice test_socket test_socket_ssl test test_socket_ssl crashed -- : [Errno socket error] (110, 'Connection timed out') test_socketserver test_softspace test_sort test_sqlite test_startfile test_startfile skipped -- cannot import name startfile test_str test_strftime test_string test_stringprep test_strop test_strptime test_struct test_structmembers test_structseq test_subprocess [7316 refs] [7317 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7317 refs] [8865 refs] [7532 refs] [7317 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] . [7316 refs] [7316 refs] this bit of output is from a test of stdout in a different process ... [7316 refs] [7316 refs] [7532 refs] test_sunaudiodev test_sunaudiodev skipped -- No module named sunaudiodev test_sundry test_symtable test_syntax test_sys [7316 refs] [7316 refs] test_tarfile test_tcl test_tcl skipped -- No module named _tkinter test_tempfile [7323 refs] test_textwrap test_thread test_threaded_import test_threadedtempfile test_threading test_threading_local test_threadsignals test_time test_timeout test_tokenize test_trace test_traceback test_transformer test_tuple test_ucn test_unary test_unicode test_unicode_file test_unicode_file skipped -- No Unicode filesystem semantics on this platform. test_unicodedata test_univnewlines test_unpack test_urllib test_urllib2 test_urllib2net test_urllibnet test_urlparse test_userdict test_userlist test_userstring test_uu test_uuid WARNING: uuid.getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. WARNING: uuid._ifconfig_getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. WARNING: uuid._unixdll_getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. test_wait3 test_wait4 test_warnings test_wave test_weakref test_whichdb test_winreg test_winreg skipped -- No module named _winreg test_winsound test_winsound skipped -- No module named winsound test_with test_wsgiref test_xdrlib test_xml_etree test_xml_etree_c test_xmllib test_xmlrpc test_xpickle test_xrange test_zipfile test_zipfile64 test_zipfile64 skipped -- test requires loads of disk-space bytes and a long time to run test_zipimport test_zlib 299 tests OK. 1 test failed: test_socket_ssl 21 tests skipped: test_aepack test_al test_applesingle test_bsddb185 test_cd test_cl test_gl test_imgfile test_ioctl test_macfs test_macostools test_pep277 test_plistlib test_scriptpackages test_startfile test_sunaudiodev test_tcl test_unicode_file test_winreg test_winsound test_zipfile64 1 skip unexpected on linux2: test_ioctl [473993 refs] From buildbot at python.org Thu Mar 8 23:51:06 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 22:51:06 +0000 Subject: [Python-checkins] buildbot warnings in x86 gentoo trunk Message-ID: <20070308225106.273E91E4002@bag.python.org> The Buildbot has detected a new failure of x86 gentoo trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%2520trunk/builds/1991 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl Traceback (most recent call last): File "./Lib/test/regrtest.py", line 557, in runtest_inner indirect_test() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 124, in test_main test_basic() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/test/test_socket_ssl.py", line 30, in test_basic f = urllib.urlopen('https://sf.net') File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/urllib.py", line 82, in urlopen return opener.open(url) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/urllib.py", line 190, in open return getattr(self, name)(url) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/urllib.py", line 412, in open_https h.endheaders() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 864, in endheaders self._send_output() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 736, in _send_output self.send(msg) File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 695, in send self.connect() File "/home/buildslave/python-trunk/trunk.norwitz-x86/build/Lib/httplib.py", line 1152, in connect sock.connect((self.host, self.port)) File "", line 1, in connect IOError: [Errno socket error] (110, 'Connection timed out') make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Fri Mar 9 00:07:24 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 08 Mar 2007 23:07:24 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP 2.5 Message-ID: <20070308230725.241071E4002@bag.python.org> The Buildbot has detected a new failure of x86 XP 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%25202.5/builds/151 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: raymond.hettinger Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl sincerely, -The Buildbot From python-checkins at python.org Fri Mar 9 00:58:19 2007 From: python-checkins at python.org (brett.cannon) Date: Fri, 9 Mar 2007 00:58:19 +0100 (CET) Subject: [Python-checkins] r54233 - in python/trunk: Doc/lib/libtest.tex Lib/test/test_socket_ssl.py Lib/test/test_support.py Misc/NEWS Message-ID: <20070308235819.E7BD11E4002@bag.python.org> Author: brett.cannon Date: Fri Mar 9 00:58:11 2007 New Revision: 54233 Modified: python/trunk/Doc/lib/libtest.tex python/trunk/Lib/test/test_socket_ssl.py python/trunk/Lib/test/test_support.py python/trunk/Misc/NEWS Log: Introduce test.test_support.TransientResource. It's a context manager to surround calls to resources that may or may not be available. Specifying the expected exception and attributes to be raised if the resource is not available prevents overly broad catching of exceptions. This is meant to help suppress spurious failures by raising test.test_support.ResourceDenied if the exception matches. It would probably be good to go through the various network tests and surround the calls to catch connection timeouts (as done with test_socket_ssl in this commit). Modified: python/trunk/Doc/lib/libtest.tex ============================================================================== --- python/trunk/Doc/lib/libtest.tex (original) +++ python/trunk/Doc/lib/libtest.tex Fri Mar 9 00:58:11 2007 @@ -285,6 +285,14 @@ The \module{test.test_support} module defines the following classes: +\begin{classdesc}{TransientResource}{exc\optional{, **kwargs}} +Create a context manager that raises \class{ResourceDenied} if the specified +exception type is raised. Any keyword arguments are treated as name/value +pairs to be compared against any exception raised with the \code{with} +statement. Only if all pairs match is \class{ResourceDenied} raised. +\versionadded{2.6} +\end{classdesc} + \begin{classdesc}{EnvironmentVarGuard}{} Class used to temporarily set or unset environment variables. Instances can be used as a context manager. Modified: python/trunk/Lib/test/test_socket_ssl.py ============================================================================== --- python/trunk/Lib/test/test_socket_ssl.py (original) +++ python/trunk/Lib/test/test_socket_ssl.py Fri Mar 9 00:58:11 2007 @@ -27,7 +27,8 @@ print "didn't raise TypeError" socket.RAND_add("this is a random string", 75.0) - f = urllib.urlopen('https://sf.net') + with test_support.TransientResource(IOError, errno=errno.ETIMEDOUT): + f = urllib.urlopen('https://sf.net') buf = f.read() f.close() Modified: python/trunk/Lib/test/test_support.py ============================================================================== --- python/trunk/Lib/test/test_support.py (original) +++ python/trunk/Lib/test/test_support.py Fri Mar 9 00:58:11 2007 @@ -312,6 +312,31 @@ for unset in self._unset: del self._environ[unset] +class TransientResource(object): + + """Raise ResourceDenied if an exception is raised while the context manager + is in effect that matches the specified exception and attributes.""" + + def __init__(self, exc, **kwargs): + self.exc = exc + self.attrs = kwargs + + def __enter__(self): + return self + + def __exit__(self, type_=None, value=None, traceback=None): + """If type_ is a subclass of self.exc and value has attributes matching + self.attrs, raise ResourceDenied. Otherwise let the exception + propagate (if any).""" + if type_ is not None and issubclass(self.exc, type_): + for attr, attr_value in self.attrs.iteritems(): + if not hasattr(value, attr): + break + if getattr(value, attr) != attr_value: + break + else: + raise ResourceDenied("an optional resource is not available") + #======================================================================= # Decorator for running a function in a different locale, correctly resetting Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 9 00:58:11 2007 @@ -516,6 +516,10 @@ Tests ----- +- Added test.test_support.TransientResource which is a context manager to + surround calls to resources that are not guaranteed to work even if + test.test_support.requires says that the resource should exist. + - Added a test for slicing of an exception. - Added test.test_support.EnvironmentVarGuard. It's a class that provides a From python-checkins at python.org Fri Mar 9 04:15:59 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 9 Mar 2007 04:15:59 +0100 (CET) Subject: [Python-checkins] r54234 - python/trunk/Lib/CGIHTTPServer.py Message-ID: <20070309031559.E76451E4002@bag.python.org> Author: collin.winter Date: Fri Mar 9 04:15:56 2007 New Revision: 54234 Modified: python/trunk/Lib/CGIHTTPServer.py Log: Patch #1481079: Support of HTTP_REFERER in CGIHTTPServer.py Modified: python/trunk/Lib/CGIHTTPServer.py ============================================================================== --- python/trunk/Lib/CGIHTTPServer.py (original) +++ python/trunk/Lib/CGIHTTPServer.py Fri Mar 9 04:15:56 2007 @@ -197,6 +197,9 @@ length = self.headers.getheader('content-length') if length: env['CONTENT_LENGTH'] = length + referer = self.headers.getheader('referer') + if referer: + env['HTTP_REFERER'] = referer accept = [] for line in self.headers.getallmatchingheaders('accept'): if line[:1] in "\t\n\r ": @@ -214,7 +217,7 @@ # Since we're setting the env in the parent, provide empty # values to override previously set values for k in ('QUERY_STRING', 'REMOTE_HOST', 'CONTENT_LENGTH', - 'HTTP_USER_AGENT', 'HTTP_COOKIE'): + 'HTTP_USER_AGENT', 'HTTP_COOKIE', 'HTTP_REFERER'): env.setdefault(k, "") os.environ.update(env) From python-checkins at python.org Fri Mar 9 04:26:33 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 9 Mar 2007 04:26:33 +0100 (CET) Subject: [Python-checkins] r54235 - python/trunk/Misc/NEWS Message-ID: <20070309032633.3C3DC1E4002@bag.python.org> Author: collin.winter Date: Fri Mar 9 04:26:32 2007 New Revision: 54235 Modified: python/trunk/Misc/NEWS Log: Add NEWS item for patch #1481079 (r54234). Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 9 04:26:32 2007 @@ -152,6 +152,8 @@ Library ------- +- Patch #1481079: add support for HTTP_REFERER to CGIHTTPServer. + - Bug #1115886: os.path.splitext('.cshrc') gives now ('.cshrc', ''). - unittest now verifies more of its assumptions. In particular, TestCase From python-checkins at python.org Fri Mar 9 05:57:05 2007 From: python-checkins at python.org (brett.cannon) Date: Fri, 9 Mar 2007 05:57:05 +0100 (CET) Subject: [Python-checkins] r54236 - in python/branches/release25-maint: Lib/test/test_socket_ssl.py Misc/NEWS Message-ID: <20070309045705.EED6A1E4004@bag.python.org> Author: brett.cannon Date: Fri Mar 9 05:57:00 2007 New Revision: 54236 Modified: python/branches/release25-maint/Lib/test/test_socket_ssl.py python/branches/release25-maint/Misc/NEWS Log: Manual backport of r54233. This will help prevent spurious Buildbot failures by HTTPS connections that time out. Modified: python/branches/release25-maint/Lib/test/test_socket_ssl.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_socket_ssl.py (original) +++ python/branches/release25-maint/Lib/test/test_socket_ssl.py Fri Mar 9 05:57:00 2007 @@ -27,7 +27,13 @@ print "didn't raise TypeError" socket.RAND_add("this is a random string", 75.0) - f = urllib.urlopen('https://sf.net') + try: + f = urllib.urlopen('https://sf.net') + except IOError, exc: + if exc.errno == errno.ETIMEDOUT: + raise test_support.ResourceDenied('HTTPS connection is timing out') + else: + raise buf = f.read() f.close() Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Fri Mar 9 05:57:00 2007 @@ -356,6 +356,9 @@ Tests ----- +- Cause test.test_socket_ssl:test_basic to raise + test.test_support.ResourceDenied when an HTTPS connection times out. + - Remove passwd.adjunct.byname from list of maps for test_nis. From python-checkins at python.org Fri Mar 9 07:00:36 2007 From: python-checkins at python.org (neal.norwitz) Date: Fri, 9 Mar 2007 07:00:36 +0100 (CET) Subject: [Python-checkins] r54237 - python/trunk/Objects/complexobject.c Message-ID: <20070309060036.9455F1E4015@bag.python.org> Author: neal.norwitz Date: Fri Mar 9 06:59:01 2007 New Revision: 54237 Modified: python/trunk/Objects/complexobject.c Log: Fix SF #1676971, Complex OverflowError has a typo Modified: python/trunk/Objects/complexobject.c ============================================================================== --- python/trunk/Objects/complexobject.c (original) +++ python/trunk/Objects/complexobject.c Fri Mar 9 06:59:01 2007 @@ -481,7 +481,7 @@ } else if (errno == ERANGE) { PyErr_SetString(PyExc_OverflowError, - "complex exponentiaion"); + "complex exponentiation"); return NULL; } return PyComplex_FromCComplex(p); From python-checkins at python.org Fri Mar 9 07:01:33 2007 From: python-checkins at python.org (neal.norwitz) Date: Fri, 9 Mar 2007 07:01:33 +0100 (CET) Subject: [Python-checkins] r54238 - python/branches/release25-maint/Objects/complexobject.c Message-ID: <20070309060133.D3BB71E4004@bag.python.org> Author: neal.norwitz Date: Fri Mar 9 07:01:28 2007 New Revision: 54238 Modified: python/branches/release25-maint/Objects/complexobject.c Log: Fix SF #1676971, Complex OverflowError has a typo Modified: python/branches/release25-maint/Objects/complexobject.c ============================================================================== --- python/branches/release25-maint/Objects/complexobject.c (original) +++ python/branches/release25-maint/Objects/complexobject.c Fri Mar 9 07:01:28 2007 @@ -481,7 +481,7 @@ } else if (errno == ERANGE) { PyErr_SetString(PyExc_OverflowError, - "complex exponentiaion"); + "complex exponentiation"); return NULL; } return PyComplex_FromCComplex(p); From buildbot at python.org Fri Mar 9 08:08:05 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 07:08:05 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable 2.5 Message-ID: <20070309070805.5748A1E4017@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%25202.5/builds/57 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: neal.norwitz Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_timeout make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Fri Mar 9 13:58:43 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 9 Mar 2007 13:58:43 +0100 (CET) Subject: [Python-checkins] r54239 - python/trunk/Tools/pybench/pybench.py Message-ID: <20070309125843.D56321E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 9 13:58:41 2007 New Revision: 54239 Modified: python/trunk/Tools/pybench/pybench.py Log: Typo. Modified: python/trunk/Tools/pybench/pybench.py ============================================================================== --- python/trunk/Tools/pybench/pybench.py (original) +++ python/trunk/Tools/pybench/pybench.py Fri Mar 9 13:58:41 2007 @@ -167,7 +167,7 @@ call of .run(). If you change a test in some way, don't forget to increase - it's version number. + its version number. """ From python-checkins at python.org Fri Mar 9 16:36:02 2007 From: python-checkins at python.org (martin.v.loewis) Date: Fri, 9 Mar 2007 16:36:02 +0100 (CET) Subject: [Python-checkins] r54240 - in python/trunk: Doc/lib/libsmtplib.tex Lib/smtplib.py Misc/NEWS Message-ID: <20070309153602.0EAA51E4017@bag.python.org> Author: martin.v.loewis Date: Fri Mar 9 16:35:55 2007 New Revision: 54240 Modified: python/trunk/Doc/lib/libsmtplib.tex python/trunk/Lib/smtplib.py python/trunk/Misc/NEWS Log: Patch #957003: Implement smtplib.LMTP. Modified: python/trunk/Doc/lib/libsmtplib.tex ============================================================================== --- python/trunk/Doc/lib/libsmtplib.tex (original) +++ python/trunk/Doc/lib/libsmtplib.tex Fri Mar 9 16:35:55 2007 @@ -41,6 +41,23 @@ certificate chain file for the SSL connection. \end{classdesc} +\begin{classdesc}{LMTP}{\optional{host\optional{, port\optional{, + local_hostname}}}} + +The LMTP protocol, which is very similar to ESMTP, is heavily based +on the standard SMTP client. It's common to use Unix sockets for LMTP, +so our connect() method must support that as well as a regular +host:port server. To specify a Unix socket, you must use an absolute +path for \var{host}, starting with a '/'. + +Authentication is supported, using the regular SMTP mechanism. When +using a Unix socket, LMTP generally don't support or require any +authentication, but your mileage might vary. + +\versionadded{2.6} + +\end{classdesc} + A nice selection of exceptions is defined as well: \begin{excdesc}{SMTPException} Modified: python/trunk/Lib/smtplib.py ============================================================================== --- python/trunk/Lib/smtplib.py (original) +++ python/trunk/Lib/smtplib.py Fri Mar 9 16:35:55 2007 @@ -226,6 +226,7 @@ debuglevel = 0 file = None helo_resp = None + ehlo_msg = "ehlo" ehlo_resp = None does_esmtp = 0 @@ -401,7 +402,7 @@ host. """ self.esmtp_features = {} - self.putcmd("ehlo", name or self.local_hostname) + self.putcmd(self.ehlo_msg, name or self.local_hostname) (code,msg)=self.getreply() # According to RFC1869 some (badly written) # MTA's will disconnect on an ehlo. Toss an exception if @@ -746,6 +747,50 @@ self.sock = SSLFakeSocket(self.sock, sslobj) self.file = SSLFakeFile(sslobj) +# +# LMTP extension +# +LMTP_PORT = 2003 + +class LMTP(SMTP): + """LMTP - Local Mail Transfer Protocol + + The LMTP protocol, which is very similar to ESMTP, is heavily based + on the standard SMTP client. It's common to use Unix sockets for LMTP, + so our connect() method must support that as well as a regular + host:port server. To specify a Unix socket, you must use an absolute + path as the host, starting with a '/'. + + Authentication is supported, using the regular SMTP mechanism. When + using a Unix socket, LMTP generally don't support or require any + authentication, but your mileage might vary.""" + + ehlo_msg = "lhlo" + + def __init__(self, host = '', port = LMTP_PORT, local_hostname = None): + """Initialize a new instance.""" + SMTP.__init__(self, host, port, local_hostname) + + def connect(self, host='localhost', port = 0): + """Connect to the LMTP daemon, on either a Unix or a TCP socket.""" + if host[0] == '/': + try: + self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.sock.connect(host) + except socket.error, msg: + if self.debuglevel > 0: print 'connect fail:', host + if self.sock: + self.sock.close() + self.sock = None + if not self.sock: + raise socket.error, msg + (code, msg) = self.getreply() + if self.debuglevel > 0: print "connect:", msg + return (code, msg) + else: + return SMTP.connect(self, host, port) + + # Test the sendmail method, which tests most of the others. # Note: This always sends to localhost. if __name__ == '__main__': Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 9 16:35:55 2007 @@ -152,6 +152,8 @@ Library ------- +- Patch #957003: Implement smtplib.LMTP. + - Patch #1481079: add support for HTTP_REFERER to CGIHTTPServer. - Bug #1115886: os.path.splitext('.cshrc') gives now ('.cshrc', ''). From buildbot at python.org Fri Mar 9 16:37:05 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 15:37:05 +0000 Subject: [Python-checkins] buildbot warnings in MIPS Debian trunk Message-ID: <20070309153705.4B5F91E400F@bag.python.org> The Buildbot has detected a new failure of MIPS Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/MIPS%2520Debian%2520trunk/builds/662 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter,neal.norwitz Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Fri Mar 9 16:56:52 2007 From: python-checkins at python.org (jim.fulton) Date: Fri, 9 Mar 2007 16:56:52 +0100 (CET) Subject: [Python-checkins] r54241 - in sandbox/branches/setuptools-0.6/setuptools: package_index.py tests/test_packageindex.py Message-ID: <20070309155652.5308C1E4002@bag.python.org> Author: jim.fulton Date: Fri Mar 9 16:56:51 2007 New Revision: 54241 Added: sandbox/branches/setuptools-0.6/setuptools/tests/test_packageindex.py (contents, props changed) Modified: sandbox/branches/setuptools-0.6/setuptools/package_index.py Log: Changed setuptools.package_index.PackageIndex.open_url to include the url in the exception. Modified: sandbox/branches/setuptools-0.6/setuptools/package_index.py ============================================================================== --- sandbox/branches/setuptools-0.6/setuptools/package_index.py (original) +++ sandbox/branches/setuptools-0.6/setuptools/package_index.py Fri Mar 9 16:56:51 2007 @@ -581,7 +581,9 @@ return v except urllib2.URLError, v: if warning: self.warn(warning, v.reason) - else: raise DistutilsError("Download error: %s" % v.reason) + else: + raise DistutilsError("Download error for %s: %s" + % (url, v.reason)) def _download_url(self, scheme, url, tmpdir): # Determine download filename Added: sandbox/branches/setuptools-0.6/setuptools/tests/test_packageindex.py ============================================================================== --- (empty file) +++ sandbox/branches/setuptools-0.6/setuptools/tests/test_packageindex.py Fri Mar 9 16:56:51 2007 @@ -0,0 +1,19 @@ +"""Package Index Tests +""" +# More would be better! + +import os, shutil, tempfile, unittest +import pkg_resources +import setuptools.package_index + +class TestPackageIndex(unittest.TestCase): + + def test_bad_urls(self): + index = setuptools.package_index.PackageIndex() + url = 'http://127.0.0.1/nonesuch/test_package_index' + try: + index.open_url(url) + except Exception, v: + self.assert_(url in str(v)) + else: + self.assert_(False) From buildbot at python.org Fri Mar 9 17:01:40 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 16:01:40 +0000 Subject: [Python-checkins] buildbot failure in x86 gentoo 2.5 Message-ID: <20070309160140.71BAD1E4002@bag.python.org> The Buildbot has detected a new failure of x86 gentoo 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%25202.5/builds/271 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Mackenzie': Osvaldo Build Source Stamp: [branch Tom] Alfredo Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From buildbot at python.org Fri Mar 9 17:12:34 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 16:12:34 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable trunk Message-ID: <20070309161234.695211E4016@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%2520trunk/builds/146 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: Traceback (most recent call last): File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/test/test_thread.py", line 281, in readerThread rec = dbutils.DeadlockWrap(c.next, max_retries=10) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/dbutils.py", line 62, in DeadlockWrap return function(*_args, **_kwargs) DBLockDeadlockError: (-30995, 'DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock') Traceback (most recent call last): File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/test/test_thread.py", line 281, in readerThread rec = dbutils.DeadlockWrap(c.next, max_retries=10) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/dbutils.py", line 62, in DeadlockWrap return function(*_args, **_kwargs) DBLockDeadlockError: (-30995, 'DB_LOCK_DEADLOCK: Locker killed to resolve a deadlock') Traceback (most recent call last): File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/test/test_thread.py", line 260, in writerThread self.assertEqual(data, self.makeData(key)) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/unittest.py", line 343, in failUnlessEqual (msg or '%r != %r' % (first, second)) AssertionError: None != '2000-2000-2000-2000-2000' Traceback (most recent call last): File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/test/test_thread.py", line 260, in writerThread self.assertEqual(data, self.makeData(key)) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/unittest.py", line 343, in failUnlessEqual (msg or '%r != %r' % (first, second)) AssertionError: None != '1001-1001-1001-1001-1001' Traceback (most recent call last): File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 460, in __bootstrap self.run() File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/bsddb/test/test_thread.py", line 260, in writerThread self.assertEqual(data, self.makeData(key)) File "/home/pybot/buildarea/trunk.klose-debian-ppc/build/Lib/unittest.py", line 343, in failUnlessEqual (msg or '%r != %r' % (first, second)) AssertionError: None != '0002-0002-0002-0002-0002' 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Fri Mar 9 17:12:41 2007 From: python-checkins at python.org (jim.fulton) Date: Fri, 9 Mar 2007 17:12:41 +0100 (CET) Subject: [Python-checkins] r54242 - in sandbox/trunk/setuptools/setuptools: package_index.py tests/test_packageindex.py Message-ID: <20070309161241.A64741E4015@bag.python.org> Author: jim.fulton Date: Fri Mar 9 17:12:41 2007 New Revision: 54242 Added: sandbox/trunk/setuptools/setuptools/tests/test_packageindex.py - copied unchanged from r54241, sandbox/branches/setuptools-0.6/setuptools/tests/test_packageindex.py Modified: sandbox/trunk/setuptools/setuptools/package_index.py Log: Changed setuptools.package_index.PackageIndex.open_url to include the url in the exception. Modified: sandbox/trunk/setuptools/setuptools/package_index.py ============================================================================== --- sandbox/trunk/setuptools/setuptools/package_index.py (original) +++ sandbox/trunk/setuptools/setuptools/package_index.py Fri Mar 9 17:12:41 2007 @@ -581,7 +581,9 @@ return v except urllib2.URLError, v: if warning: self.warn(warning, v.reason) - else: raise DistutilsError("Download error: %s" % v.reason) + else: + raise DistutilsError("Download error for %s: %s" + % (url, v.reason)) def _download_url(self, scheme, url, tmpdir): # Determine download filename From buildbot at python.org Fri Mar 9 17:19:05 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 16:19:05 +0000 Subject: [Python-checkins] buildbot failure in x86 XP 2.5 Message-ID: <20070309161905.3D23F1E4025@bag.python.org> The Buildbot has detected a new failure of x86 XP 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%25202.5/builds/154 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Shannon': Sterling Build Source Stamp: [branch Brandyn] Dontae Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From buildbot at python.org Fri Mar 9 17:20:52 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 16:20:52 +0000 Subject: [Python-checkins] buildbot failure in g4 osx.4 2.5 Message-ID: <20070309162052.EB6471E400D@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%25202.5/builds/257 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Shemar': Clifford Build Source Stamp: [branch Shelton] Dexter Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From buildbot at python.org Fri Mar 9 17:34:20 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 16:34:20 +0000 Subject: [Python-checkins] buildbot warnings in S-390 Debian trunk Message-ID: <20070309163420.880871E4002@bag.python.org> The Buildbot has detected a new failure of S-390 Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/S-390%2520Debian%2520trunk/builds/738 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Fri Mar 9 19:09:12 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 9 Mar 2007 19:09:12 +0100 (CET) Subject: [Python-checkins] r54243 - in python/trunk: Doc/lib/emailutil.tex Doc/lib/librfc822.tex Misc/NEWS Message-ID: <20070309180912.40D091E4017@bag.python.org> Author: collin.winter Date: Fri Mar 9 19:09:10 2007 New Revision: 54243 Modified: python/trunk/Doc/lib/emailutil.tex python/trunk/Doc/lib/librfc822.tex python/trunk/Misc/NEWS Log: Bug #1629566: clarify the docs on the return values of parsedate() and parsedate_tz() in email.utils and rfc822. Modified: python/trunk/Doc/lib/emailutil.tex ============================================================================== --- python/trunk/Doc/lib/emailutil.tex (original) +++ python/trunk/Doc/lib/emailutil.tex Fri Mar 9 19:09:10 2007 @@ -56,7 +56,7 @@ \code{"Mon, 20 Nov 1995 19:12:08 -0500"}. If it succeeds in parsing the date, \function{parsedate()} returns a 9-tuple that can be passed directly to \function{time.mktime()}; otherwise \code{None} will be -returned. Note that fields 6, 7, and 8 of the result tuple are not +returned. Note that indexes 6, 7, and 8 of the result tuple are not usable. \end{funcdesc} @@ -70,7 +70,7 @@ variable for the same timezone; the latter variable follows the \POSIX{} standard while this module follows \rfc{2822}.}. If the input string has no timezone, the last element of the tuple returned is -\code{None}. Note that fields 6, 7, and 8 of the result tuple are not +\code{None}. Note that indexes 6, 7, and 8 of the result tuple are not usable. \end{funcdesc} Modified: python/trunk/Doc/lib/librfc822.tex ============================================================================== --- python/trunk/Doc/lib/librfc822.tex (original) +++ python/trunk/Doc/lib/librfc822.tex Fri Mar 9 19:09:10 2007 @@ -100,7 +100,7 @@ \code{'Mon, 20 Nov 1995 19:12:08 -0500'}. If it succeeds in parsing the date, \function{parsedate()} returns a 9-tuple that can be passed directly to \function{time.mktime()}; otherwise \code{None} will be -returned. Note that fields 6, 7, and 8 of the result tuple are not +returned. Note that indexes 6, 7, and 8 of the result tuple are not usable. \end{funcdesc} @@ -114,7 +114,7 @@ variable for the same timezone; the latter variable follows the \POSIX{} standard while this module follows \rfc{2822}.) If the input string has no timezone, the last element of the tuple returned is -\code{None}. Note that fields 6, 7, and 8 of the result tuple are not +\code{None}. Note that indexes 6, 7, and 8 of the result tuple are not usable. \end{funcdesc} Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 9 19:09:10 2007 @@ -559,6 +559,9 @@ Documentation ------------- +- Bug #1629566: clarify the docs on the return values of parsedate() + and parsedate_tz() in email.utils and rfc822. + - Patch #1671450: add a section about subclassing builtin types to the "extending and embedding" tutorial. From python-checkins at python.org Fri Mar 9 20:21:34 2007 From: python-checkins at python.org (thomas.heller) Date: Fri, 9 Mar 2007 20:21:34 +0100 (CET) Subject: [Python-checkins] r54244 - in python/trunk: Lib/ctypes/__init__.py Lib/ctypes/test/test_memfunctions.py Misc/NEWS Modules/_ctypes/_ctypes.c Message-ID: <20070309192134.5A95A1E4004@bag.python.org> Author: thomas.heller Date: Fri Mar 9 20:21:28 2007 New Revision: 54244 Modified: python/trunk/Lib/ctypes/__init__.py python/trunk/Lib/ctypes/test/test_memfunctions.py python/trunk/Misc/NEWS python/trunk/Modules/_ctypes/_ctypes.c Log: Fix bug #1646630: ctypes.string_at(buf, 0) and ctypes.wstring_at(buf, 0) returned string up to the first NUL character. Modified: python/trunk/Lib/ctypes/__init__.py ============================================================================== --- python/trunk/Lib/ctypes/__init__.py (original) +++ python/trunk/Lib/ctypes/__init__.py Fri Mar 9 20:21:28 2007 @@ -480,7 +480,7 @@ return _cast(obj, obj, typ) _string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) -def string_at(ptr, size=0): +def string_at(ptr, size=-1): """string_at(addr[, size]) -> string Return the string at addr.""" @@ -492,7 +492,7 @@ pass else: _wstring_at = CFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr) - def wstring_at(ptr, size=0): + def wstring_at(ptr, size=-1): """wstring_at(addr[, size]) -> string Return the string at addr.""" Modified: python/trunk/Lib/ctypes/test/test_memfunctions.py ============================================================================== --- python/trunk/Lib/ctypes/test/test_memfunctions.py (original) +++ python/trunk/Lib/ctypes/test/test_memfunctions.py Fri Mar 9 20:21:28 2007 @@ -14,6 +14,7 @@ self.failUnlessEqual(string_at(result), "Hello, World") self.failUnlessEqual(string_at(result, 5), "Hello") self.failUnlessEqual(string_at(result, 16), "Hello, World\0\0\0\0") + self.failUnlessEqual(string_at(result, 0), "") def test_memset(self): a = create_string_buffer(1000000) @@ -54,6 +55,7 @@ self.failUnlessEqual(wstring_at(a), "Hello, World") self.failUnlessEqual(wstring_at(a, 5), "Hello") self.failUnlessEqual(wstring_at(a, 16), "Hello, World\0\0\0\0") + self.failUnlessEqual(wstring_at(a, 0), "") if __name__ == "__main__": unittest.main() Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 9 20:21:28 2007 @@ -152,6 +152,9 @@ Library ------- +- Bug #1646630: ctypes.string_at(buf, 0) and ctypes.wstring_at(buf, 0) + returned string up to the first NUL character. + - Patch #957003: Implement smtplib.LMTP. - Patch #1481079: add support for HTTP_REFERER to CGIHTTPServer. Modified: python/trunk/Modules/_ctypes/_ctypes.c ============================================================================== --- python/trunk/Modules/_ctypes/_ctypes.c (original) +++ python/trunk/Modules/_ctypes/_ctypes.c Fri Mar 9 20:21:28 2007 @@ -4537,9 +4537,9 @@ #endif static PyObject * -string_at(const char *ptr, Py_ssize_t size) +string_at(const char *ptr, int size) { - if (size == 0) + if (size == -1) return PyString_FromString(ptr); return PyString_FromStringAndSize(ptr, size); } @@ -4624,7 +4624,7 @@ static PyObject * wstring_at(const wchar_t *ptr, int size) { - if (size == 0) + if (size == -1) size = wcslen(ptr); return PyUnicode_FromWideChar(ptr, size); } From python-checkins at python.org Fri Mar 9 20:36:06 2007 From: python-checkins at python.org (martin.v.loewis) Date: Fri, 9 Mar 2007 20:36:06 +0100 (CET) Subject: [Python-checkins] r54245 - python/trunk/Misc/developers.txt Message-ID: <20070309193606.F1CD01E4017@bag.python.org> Author: martin.v.loewis Date: Fri Mar 9 20:36:01 2007 New Revision: 54245 Modified: python/trunk/Misc/developers.txt Log: Add Ziga Seilnacht. Modified: python/trunk/Misc/developers.txt ============================================================================== --- python/trunk/Misc/developers.txt (original) +++ python/trunk/Misc/developers.txt Fri Mar 9 20:36:01 2007 @@ -17,6 +17,9 @@ Permissions History ------------------- +- Ziga Seilnacht was given SVN occess on 09 Mar 2007 by MvL, + for general maintenance. + - Pete Shinners was given SVN access on 04 Mar 2007 by NCN, for PEP 3101 work in the sandbox. @@ -157,3 +160,4 @@ RDH: Raymond Hettinger TGP: Tim Peters DJG: David Goodger +MvL: Martin v. Loewis From buildbot at python.org Fri Mar 9 21:06:06 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 20:06:06 +0000 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk Message-ID: <20070309200606.3C25E1E4002@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%2520trunk/builds/1814 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter,thomas.heller Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Fri Mar 9 21:21:20 2007 From: python-checkins at python.org (thomas.heller) Date: Fri, 9 Mar 2007 21:21:20 +0100 (CET) Subject: [Python-checkins] r54246 - in python/branches/release25-maint: Lib/ctypes Lib/ctypes/__init__.py Lib/ctypes/test/test_memfunctions.py Misc/NEWS Modules/_ctypes Modules/_ctypes/_ctypes.c Message-ID: <20070309202120.759D91E4002@bag.python.org> Author: thomas.heller Date: Fri Mar 9 21:21:16 2007 New Revision: 54246 Modified: python/branches/release25-maint/Lib/ctypes/ (props changed) python/branches/release25-maint/Lib/ctypes/__init__.py python/branches/release25-maint/Lib/ctypes/test/test_memfunctions.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Modules/_ctypes/ (props changed) python/branches/release25-maint/Modules/_ctypes/_ctypes.c Log: Merged revisions 54244 via svnmerge from svn+ssh://pythondev at svn.python.org/python/trunk/Lib/ctypes ........ r54244 | thomas.heller | 2007-03-09 20:21:28 +0100 (Fr, 09 M?r 2007) | 3 lines Fix bug #1646630: ctypes.string_at(buf, 0) and ctypes.wstring_at(buf, 0) returned string up to the first NUL character. ........ Modified: python/branches/release25-maint/Lib/ctypes/__init__.py ============================================================================== --- python/branches/release25-maint/Lib/ctypes/__init__.py (original) +++ python/branches/release25-maint/Lib/ctypes/__init__.py Fri Mar 9 21:21:16 2007 @@ -478,7 +478,7 @@ return _cast(obj, obj, typ) _string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) -def string_at(ptr, size=0): +def string_at(ptr, size=-1): """string_at(addr[, size]) -> string Return the string at addr.""" @@ -490,7 +490,7 @@ pass else: _wstring_at = CFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr) - def wstring_at(ptr, size=0): + def wstring_at(ptr, size=-1): """wstring_at(addr[, size]) -> string Return the string at addr.""" Modified: python/branches/release25-maint/Lib/ctypes/test/test_memfunctions.py ============================================================================== --- python/branches/release25-maint/Lib/ctypes/test/test_memfunctions.py (original) +++ python/branches/release25-maint/Lib/ctypes/test/test_memfunctions.py Fri Mar 9 21:21:16 2007 @@ -14,6 +14,7 @@ self.failUnlessEqual(string_at(result), "Hello, World") self.failUnlessEqual(string_at(result, 5), "Hello") self.failUnlessEqual(string_at(result, 16), "Hello, World\0\0\0\0") + self.failUnlessEqual(string_at(result, 0), "") def test_memset(self): a = create_string_buffer(1000000) @@ -54,6 +55,7 @@ self.failUnlessEqual(wstring_at(a), "Hello, World") self.failUnlessEqual(wstring_at(a, 5), "Hello") self.failUnlessEqual(wstring_at(a, 16), "Hello, World\0\0\0\0") + self.failUnlessEqual(wstring_at(a, 0), "") if __name__ == "__main__": unittest.main() Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Fri Mar 9 21:21:16 2007 @@ -197,6 +197,9 @@ Library ------- +- Fix bug #1646630: ctypes.string_at(buf, 0) and ctypes.wstring_at(buf, 0) + returned string up to the first NUL character. + - Bug #1637850: make_table in difflib did not work with unicode - Bugs #1676321: the empty() function in sched.py returned the wrong result Modified: python/branches/release25-maint/Modules/_ctypes/_ctypes.c ============================================================================== --- python/branches/release25-maint/Modules/_ctypes/_ctypes.c (original) +++ python/branches/release25-maint/Modules/_ctypes/_ctypes.c Fri Mar 9 21:21:16 2007 @@ -4531,9 +4531,9 @@ #endif static PyObject * -string_at(const char *ptr, Py_ssize_t size) +string_at(const char *ptr, int size) { - if (size == 0) + if (size == -1) return PyString_FromString(ptr); return PyString_FromStringAndSize(ptr, size); } @@ -4618,7 +4618,7 @@ static PyObject * wstring_at(const wchar_t *ptr, int size) { - if (size == 0) + if (size == -1) size = wcslen(ptr); return PyUnicode_FromWideChar(ptr, size); } From python-checkins at python.org Fri Mar 9 21:33:17 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 9 Mar 2007 21:33:17 +0100 (CET) Subject: [Python-checkins] r54247 - in python/trunk: Lib/test/test_complex.py Misc/NEWS Objects/complexobject.c Message-ID: <20070309203317.3BC301E4004@bag.python.org> Author: collin.winter Date: Fri Mar 9 21:33:07 2007 New Revision: 54247 Modified: python/trunk/Lib/test/test_complex.py python/trunk/Misc/NEWS python/trunk/Objects/complexobject.c Log: Patch #1491866: change the complex() constructor to allow parthensized forms. This means complex(repr(x)) now works instead of raising a ValueError. Modified: python/trunk/Lib/test/test_complex.py ============================================================================== --- python/trunk/Lib/test/test_complex.py (original) +++ python/trunk/Lib/test/test_complex.py Fri Mar 9 21:33:07 2007 @@ -215,6 +215,8 @@ self.assertAlmostEqual(complex(), 0) self.assertAlmostEqual(complex("-1"), -1) self.assertAlmostEqual(complex("+1"), +1) + self.assertAlmostEqual(complex("(1+2j)"), 1+2j) + self.assertAlmostEqual(complex("(1.3+2.2j)"), 1.3+2.2j) class complex2(complex): pass self.assertAlmostEqual(complex(complex2(1+1j)), 1+1j) @@ -244,12 +246,17 @@ self.assertRaises(ValueError, complex, "") self.assertRaises(TypeError, complex, None) self.assertRaises(ValueError, complex, "\0") + self.assertRaises(ValueError, complex, "3\09") self.assertRaises(TypeError, complex, "1", "2") self.assertRaises(TypeError, complex, "1", 42) self.assertRaises(TypeError, complex, 1, "2") self.assertRaises(ValueError, complex, "1+") self.assertRaises(ValueError, complex, "1+1j+1j") self.assertRaises(ValueError, complex, "--") + self.assertRaises(ValueError, complex, "(1+2j") + self.assertRaises(ValueError, complex, "1+2j)") + self.assertRaises(ValueError, complex, "1+(2j)") + self.assertRaises(ValueError, complex, "(1+2j)123") if test_support.have_unicode: self.assertRaises(ValueError, complex, unicode("1"*500)) self.assertRaises(ValueError, complex, unicode("x")) @@ -312,6 +319,11 @@ self.assertNotEqual(repr(-(1+0j)), '(-1+-0j)') + self.assertEqual(1-6j,complex(repr(1-6j))) + self.assertEqual(1+6j,complex(repr(1+6j))) + self.assertEqual(-6j,complex(repr(-6j))) + self.assertEqual(6j,complex(repr(6j))) + def test_neg(self): self.assertEqual(-(1+6j), -1-6j) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 9 21:33:07 2007 @@ -12,6 +12,10 @@ Core and builtins ----------------- +- Patch #1491866: change the complex() constructor to allow parthensized + forms. This means complex(repr(x)) now works instead of raising a + ValueError. + - Patch #703779: unset __file__ in __main__ after running a file. This makes the filenames the warning module prints much more sensible when a PYTHONSTARTUP file is used. Modified: python/trunk/Objects/complexobject.c ============================================================================== --- python/trunk/Objects/complexobject.c (original) +++ python/trunk/Objects/complexobject.c Fri Mar 9 21:33:07 2007 @@ -672,7 +672,7 @@ const char *s, *start; char *end; double x=0.0, y=0.0, z; - int got_re=0, got_im=0, done=0; + int got_re=0, got_im=0, got_bracket=0, done=0; int digit_or_dot; int sw_error=0; int sign; @@ -712,10 +712,17 @@ start = s; while (*s && isspace(Py_CHARMASK(*s))) s++; - if (s[0] == '\0') { + if (s[0] == '\0') { PyErr_SetString(PyExc_ValueError, "complex() arg is an empty string"); return NULL; + } + if (s[0] == '(') { + /* Skip over possible bracket from repr(). */ + got_bracket = 1; + s++; + while (*s && isspace(Py_CHARMASK(*s))) + s++; } z = -1.0; @@ -734,13 +741,26 @@ if(!done) sw_error=1; break; + case ')': + if (!got_bracket || !(got_re || got_im)) { + sw_error=1; + break; + } + got_bracket=0; + done=1; + s++; + while (*s && isspace(Py_CHARMASK(*s))) + s++; + if (*s) sw_error=1; + break; + case '-': sign = -1; /* Fallthrough */ case '+': if (done) sw_error=1; s++; - if ( *s=='\0'||*s=='+'||*s=='-' || + if ( *s=='\0'||*s=='+'||*s=='-'||*s==')'|| isspace(Py_CHARMASK(*s)) ) sw_error=1; break; @@ -766,7 +786,7 @@ if (isspace(Py_CHARMASK(*s))) { while (*s && isspace(Py_CHARMASK(*s))) s++; - if (s[0] != '\0') + if (*s && *s != ')') sw_error=1; else done = 1; @@ -812,7 +832,7 @@ } while (s - start < len && !sw_error); - if (sw_error) { + if (sw_error || got_bracket) { PyErr_SetString(PyExc_ValueError, "complex() arg is a malformed string"); return NULL; From python-checkins at python.org Fri Mar 9 21:39:25 2007 From: python-checkins at python.org (thomas.heller) Date: Fri, 9 Mar 2007 21:39:25 +0100 (CET) Subject: [Python-checkins] r54248 - in python/trunk: Lib/ctypes/test/test_functions.py Misc/NEWS Modules/_ctypes/_ctypes.c Message-ID: <20070309203925.7211F1E4002@bag.python.org> Author: thomas.heller Date: Fri Mar 9 21:39:22 2007 New Revision: 54248 Modified: python/trunk/Lib/ctypes/test/test_functions.py python/trunk/Misc/NEWS python/trunk/Modules/_ctypes/_ctypes.c Log: Bug #1651235: When a tuple was passed to a ctypes function call, Python would crash instead of raising an error. The crash was caused by a section of code that should have been removed long ago, at that time ctypes had other ways to pass parameters to function calls. Modified: python/trunk/Lib/ctypes/test/test_functions.py ============================================================================== --- python/trunk/Lib/ctypes/test/test_functions.py (original) +++ python/trunk/Lib/ctypes/test/test_functions.py Fri Mar 9 21:39:22 2007 @@ -21,7 +21,9 @@ class POINT(Structure): _fields_ = [("x", c_int), ("y", c_int)] - +class RECT(Structure): + _fields_ = [("left", c_int), ("top", c_int), + ("right", c_int), ("bottom", c_int)] class FunctionTestCase(unittest.TestCase): def test_mro(self): @@ -379,5 +381,15 @@ self.failUnlessEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h), (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) + def test_sf1651235(self): + # see http://www.python.org/sf/1651235 + + proto = CFUNCTYPE(c_int, RECT, POINT) + def callback(*args): + return 0 + + callback = proto(callback) + self.failUnlessRaises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT())) + if __name__ == '__main__': unittest.main() Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 9 21:39:22 2007 @@ -156,6 +156,9 @@ Library ------- +- Bug #1651235: When a tuple was passed to a ctypes function call, + Python would crash instead of raising an error. + - Bug #1646630: ctypes.string_at(buf, 0) and ctypes.wstring_at(buf, 0) returned string up to the first NUL character. Modified: python/trunk/Modules/_ctypes/_ctypes.c ============================================================================== --- python/trunk/Modules/_ctypes/_ctypes.c (original) +++ python/trunk/Modules/_ctypes/_ctypes.c Fri Mar 9 21:39:22 2007 @@ -339,24 +339,6 @@ ((PyTypeObject *)type)->tp_name, ob_name); return NULL; } -#if 1 -/* XXX Remove this section ??? */ - /* tuple returned by byref: */ - /* ('i', addr, obj) */ - if (PyTuple_Check(value)) { - PyObject *ob; - StgDictObject *dict; - - dict = PyType_stgdict(type); - ob = PyTuple_GetItem(value, 2); - if (dict && ob && - 0 == PyObject_IsInstance(value, dict->proto)) { - Py_INCREF(value); - return value; - } - } -/* ... and leave the rest */ -#endif as_parameter = PyObject_GetAttrString(value, "_as_parameter_"); if (as_parameter) { From python-checkins at python.org Fri Mar 9 21:49:04 2007 From: python-checkins at python.org (thomas.heller) Date: Fri, 9 Mar 2007 21:49:04 +0100 (CET) Subject: [Python-checkins] r54249 - in python/branches/release25-maint: Lib/ctypes Lib/ctypes/test/test_functions.py Misc/NEWS Modules/_ctypes Modules/_ctypes/_ctypes.c Message-ID: <20070309204904.4E3AD1E4002@bag.python.org> Author: thomas.heller Date: Fri Mar 9 21:48:57 2007 New Revision: 54249 Modified: python/branches/release25-maint/Lib/ctypes/ (props changed) python/branches/release25-maint/Lib/ctypes/test/test_functions.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Modules/_ctypes/ (props changed) python/branches/release25-maint/Modules/_ctypes/_ctypes.c Log: Merged revisions 54248 via svnmerge from svn+ssh://pythondev at svn.python.org/python/trunk/Lib/ctypes ........ r54248 | thomas.heller | 2007-03-09 21:39:22 +0100 (Fr, 09 M?r 2007) | 7 lines Bug #1651235: When a tuple was passed to a ctypes function call, Python would crash instead of raising an error. The crash was caused by a section of code that should have been removed long ago, at that time ctypes had other ways to pass parameters to function calls. ........ Modified: python/branches/release25-maint/Lib/ctypes/test/test_functions.py ============================================================================== --- python/branches/release25-maint/Lib/ctypes/test/test_functions.py (original) +++ python/branches/release25-maint/Lib/ctypes/test/test_functions.py Fri Mar 9 21:48:57 2007 @@ -21,7 +21,9 @@ class POINT(Structure): _fields_ = [("x", c_int), ("y", c_int)] - +class RECT(Structure): + _fields_ = [("left", c_int), ("top", c_int), + ("right", c_int), ("bottom", c_int)] class FunctionTestCase(unittest.TestCase): def test_mro(self): @@ -379,5 +381,15 @@ self.failUnlessEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h), (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) + def test_sf1651235(self): + # see http://www.python.org/sf/1651235 + + proto = CFUNCTYPE(c_int, RECT, POINT) + def callback(*args): + return 0 + + callback = proto(callback) + self.failUnlessRaises(ArgumentError, lambda: callback((1, 2, 3, 4), POINT())) + if __name__ == '__main__': unittest.main() Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Fri Mar 9 21:48:57 2007 @@ -196,6 +196,8 @@ Library ------- +- Bug #1651235: When a tuple was passed to a ctypes function call, + Python would crash instead of raising an error. - Fix bug #1646630: ctypes.string_at(buf, 0) and ctypes.wstring_at(buf, 0) returned string up to the first NUL character. Modified: python/branches/release25-maint/Modules/_ctypes/_ctypes.c ============================================================================== --- python/branches/release25-maint/Modules/_ctypes/_ctypes.c (original) +++ python/branches/release25-maint/Modules/_ctypes/_ctypes.c Fri Mar 9 21:48:57 2007 @@ -339,24 +339,6 @@ ((PyTypeObject *)type)->tp_name, ob_name); return NULL; } -#if 1 -/* XXX Remove this section ??? */ - /* tuple returned by byref: */ - /* ('i', addr, obj) */ - if (PyTuple_Check(value)) { - PyObject *ob; - StgDictObject *dict; - - dict = PyType_stgdict(type); - ob = PyTuple_GetItem(value, 2); - if (dict && ob && - 0 == PyObject_IsInstance(value, dict->proto)) { - Py_INCREF(value); - return value; - } - } -/* ... and leave the rest */ -#endif as_parameter = PyObject_GetAttrString(value, "_as_parameter_"); if (as_parameter) { From collinw at gmail.com Fri Mar 9 21:53:00 2007 From: collinw at gmail.com (Collin Winter) Date: Fri, 9 Mar 2007 14:53:00 -0600 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk In-Reply-To: <20070309200606.3C25E1E4002@bag.python.org> References: <20070309200606.3C25E1E4002@bag.python.org> Message-ID: <43aa6ff70703091253j7a7159e2l3c42d2a135c92268@mail.gmail.com> Any objections to applying something like the following to address the recent spate of failures in test_posixpath:test_islink? Index: Lib/test/test_posixpath.py --- Lib/test/test_posixpath.py (revision 54248) +++ Lib/test/test_posixpath.py (working copy) @@ -150,6 +150,11 @@ os.remove(test_support.TESTFN) def test_islink(self): + try: + os.remove(test_support.TESTFN + "2") + except os.error: + pass + self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False) f = open(test_support.TESTFN + "1", "wb") try: On 3/9/07, buildbot at python.org wrote: > The Buildbot has detected a new failure of g4 osx.4 trunk. > Full details are available at: > http://www.python.org/dev/buildbot/all/g4%2520osx.4%2520trunk/builds/1814 > > Buildbot URL: http://www.python.org/dev/buildbot/all/ > > Build Reason: > Build Source Stamp: [branch trunk] HEAD > Blamelist: collin.winter,thomas.heller > > Build had warnings: warnings test > > Excerpt from the test logfile: > 1 test failed: > test_posixpath > > make: *** [buildbottest] Error 1 > > sincerely, > -The Buildbot > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > From buildbot at python.org Fri Mar 9 21:57:48 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 20:57:48 +0000 Subject: [Python-checkins] buildbot warnings in x86 mvlgcc trunk Message-ID: <20070309205748.DA3CF1E4002@bag.python.org> The Buildbot has detected a new failure of x86 mvlgcc trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520mvlgcc%2520trunk/builds/322 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter,martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From martin at v.loewis.de Fri Mar 9 23:21:18 2007 From: martin at v.loewis.de (=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=) Date: Fri, 09 Mar 2007 23:21:18 +0100 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk In-Reply-To: <43aa6ff70703091253j7a7159e2l3c42d2a135c92268@mail.gmail.com> References: <20070309200606.3C25E1E4002@bag.python.org> <43aa6ff70703091253j7a7159e2l3c42d2a135c92268@mail.gmail.com> Message-ID: <45F1DDDE.7080401@v.loewis.de> Collin Winter schrieb: > Any objections to applying something like the following to address the > recent spate of failures in test_posixpath:test_islink? In principle, this kind of stuff belongs into setUp/tearDown (i.e. tearDown should make sure no files are left over; setUp may do the same just to be safe). Regards, Martin From buildbot at python.org Fri Mar 9 23:24:30 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 22:24:30 +0000 Subject: [Python-checkins] buildbot warnings in S-390 Debian trunk Message-ID: <20070309222430.E7F0C1E4002@bag.python.org> The Buildbot has detected a new failure of S-390 Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/S-390%2520Debian%2520trunk/builds/741 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: thomas.heller Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_posixpath make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Fri Mar 9 23:37:25 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 09 Mar 2007 22:37:25 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070309223725.9A1A21E401A@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/98 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: thomas.heller Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From collinw at gmail.com Fri Mar 9 23:53:24 2007 From: collinw at gmail.com (Collin Winter) Date: Fri, 9 Mar 2007 16:53:24 -0600 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk In-Reply-To: <45F1DDDE.7080401@v.loewis.de> References: <20070309200606.3C25E1E4002@bag.python.org> <43aa6ff70703091253j7a7159e2l3c42d2a135c92268@mail.gmail.com> <45F1DDDE.7080401@v.loewis.de> Message-ID: <43aa6ff70703091453n375a28bcy46f4d21ad3cd5099@mail.gmail.com> On 3/9/07, "Martin v. L?wis" wrote: > Collin Winter schrieb: > > Any objections to applying something like the following to address the > > recent spate of failures in test_posixpath:test_islink? > > In principle, this kind of stuff belongs into setUp/tearDown > (i.e. tearDown should make sure no files are left over; setUp > may do the same just to be safe). Right. I initially put the os.remove() call in the test method itself because only three tests use 'test_support.TESTFN + "2"' as filenames. I've consolidated the boilerplate teardown code from several other test methods into a single tearDown method. The attached patch also moves pass_os_error(), safe_remove() and safe_rmdir() out from under an "if hasattr(os, "symlink"):", since they don't depend on symlink. test_samefile() also now runs; it was previously over-indented and so wasn't executed. What do you think? Collin Winter From collinw at gmail.com Fri Mar 9 23:55:07 2007 From: collinw at gmail.com (Collin Winter) Date: Fri, 9 Mar 2007 16:55:07 -0600 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk In-Reply-To: <43aa6ff70703091453n375a28bcy46f4d21ad3cd5099@mail.gmail.com> References: <20070309200606.3C25E1E4002@bag.python.org> <43aa6ff70703091253j7a7159e2l3c42d2a135c92268@mail.gmail.com> <45F1DDDE.7080401@v.loewis.de> <43aa6ff70703091453n375a28bcy46f4d21ad3cd5099@mail.gmail.com> Message-ID: <43aa6ff70703091455i78e41c62g59959c4eb479dd32@mail.gmail.com> On 3/9/07, Collin Winter wrote: > On 3/9/07, "Martin v. L?wis" wrote: > > Collin Winter schrieb: > > > Any objections to applying something like the following to address the > > > recent spate of failures in test_posixpath:test_islink? > > > > In principle, this kind of stuff belongs into setUp/tearDown > > (i.e. tearDown should make sure no files are left over; setUp > > may do the same just to be safe). > > Right. I initially put the os.remove() call in the test method itself > because only three tests use 'test_support.TESTFN + "2"' as filenames. > I've consolidated the boilerplate teardown code from several other > test methods into a single tearDown method. > > The attached patch also moves pass_os_error(), safe_remove() and > safe_rmdir() out from under an "if hasattr(os, "symlink"):", since > they don't depend on symlink. test_samefile() also now runs; it was > previously over-indented and so wasn't executed. > > What do you think? Ack, forgot to attach the patch! Collin Winter -------------- next part -------------- A non-text attachment was scrubbed... Name: test_posixpath.py.diff Type: application/octet-stream Size: 6880 bytes Desc: not available Url : http://mail.python.org/pipermail/python-checkins/attachments/20070309/1a0e03e7/attachment.obj From thomas at python.org Sat Mar 10 00:15:14 2007 From: thomas at python.org (Thomas Wouters) Date: Sat, 10 Mar 2007 00:15:14 +0100 Subject: [Python-checkins] r54199 - in python/trunk: Lib/test/test_unittest.py Lib/unittest.py Misc/NEWS In-Reply-To: <20070307090949.BF7081E4003@bag.python.org> References: <20070307090949.BF7081E4003@bag.python.org> Message-ID: <9e804ac0703091515v15003647i8b353d9e73a92ccd@mail.gmail.com> On 3/7/07, georg.brandl wrote: > + def __hash__(self): > + return hash(str(hash(type(self))) + > str(hash(self._testMethodName))) Any particular reason not to use 'return hash((type(self), self._testMethodName))' instead? + def __hash__(self): > + return hash(''.join(str(hash(x)) for x in [ > + type(self), self.__setUpFunc, self.__tearDownFunc, > self.__testFunc, > + self.__description])) And 'hash((type(self), self.__setUpFunc, self.__tearDownFunc, self.__testFunc, self.__description))' here. -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20070310/6edd0682/attachment.htm From collinw at gmail.com Sat Mar 10 00:21:47 2007 From: collinw at gmail.com (Collin Winter) Date: Fri, 9 Mar 2007 17:21:47 -0600 Subject: [Python-checkins] r54199 - in python/trunk: Lib/test/test_unittest.py Lib/unittest.py Misc/NEWS In-Reply-To: <9e804ac0703091515v15003647i8b353d9e73a92ccd@mail.gmail.com> References: <20070307090949.BF7081E4003@bag.python.org> <9e804ac0703091515v15003647i8b353d9e73a92ccd@mail.gmail.com> Message-ID: <43aa6ff70703091521j54ce4b9as8ef0b9f2cf52dfea@mail.gmail.com> On 3/9/07, Thomas Wouters wrote: > > On 3/7/07, georg.brandl wrote: > > + def __hash__(self): > > + return hash(str(hash(type(self))) + > str(hash(self._testMethodName))) > > Any particular reason not to use 'return hash((type(self), > self._testMethodName))' instead? > > > + def __hash__(self): > > + return hash(''.join(str(hash(x)) for x in [ > > + type(self), self.__setUpFunc, self.__tearDownFunc, > self.__testFunc, > > + self.__description])) > > And 'hash((type(self), self.__setUpFunc, self.__tearDownFunc, > self.__testFunc, self.__description))' here. Just that I didn't think of it : ) I'll make the change. Thanks, Collin Winter From python-checkins at python.org Sat Mar 10 00:30:40 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 10 Mar 2007 00:30:40 +0100 (CET) Subject: [Python-checkins] r54250 - python/trunk/Lib/unittest.py Message-ID: <20070309233040.D3D4A1E4013@bag.python.org> Author: collin.winter Date: Sat Mar 10 00:30:39 2007 New Revision: 54250 Modified: python/trunk/Lib/unittest.py Log: Hashing simplification pointed out by Thomas Wouters. Modified: python/trunk/Lib/unittest.py ============================================================================== --- python/trunk/Lib/unittest.py (original) +++ python/trunk/Lib/unittest.py Sat Mar 10 00:30:39 2007 @@ -245,7 +245,7 @@ return not self == other def __hash__(self): - return hash(str(hash(type(self))) + str(hash(self._testMethodName))) + return hash((type(self), self._testMethodName)) def __str__(self): return "%s (%s)" % (self._testMethodName, _strclass(self.__class__)) @@ -502,9 +502,8 @@ return not self == other def __hash__(self): - return hash(''.join(str(hash(x)) for x in [ - type(self), self.__setUpFunc, self.__tearDownFunc, self.__testFunc, - self.__description])) + return hash((type(self), self.__setUpFunc, self.__tearDownFunc, + self.__testFunc, self.__description)) def __str__(self): return "%s (%s)" % (_strclass(self.__class__), self.__testFunc.__name__) From thomas at python.org Sat Mar 10 00:36:21 2007 From: thomas at python.org (Thomas Wouters) Date: Sat, 10 Mar 2007 00:36:21 +0100 Subject: [Python-checkins] r54198 - in python/branches/release25-maint: Lib/glob.py Lib/test/test_glob.py Misc/NEWS In-Reply-To: <20070307083226.905111E4003@bag.python.org> References: <20070307083226.905111E4003@bag.python.org> Message-ID: <9e804ac0703091536wd538256r2945c775239f9020@mail.gmail.com> On 3/7/07, georg.brandl wrote: > > Author: georg.brandl > Date: Wed Mar 7 09:32:24 2007 > New Revision: 54198 > > Modified: > python/branches/release25-maint/Lib/glob.py > python/branches/release25-maint/Lib/test/test_glob.py > python/branches/release25-maint/Misc/NEWS > Log: > Patch #1001604: glob.glob() now returns unicode filenames if it was > given a unicode argument and os.listdir() returns unicode filenames. > (backport from rev. 54197) This change should not be backported, IMHO. (It changes functioning code, as far as I can tell -- but feel free to correct me :) -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20070310/dc430b01/attachment.html From python-checkins at python.org Sat Mar 10 01:10:37 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 10 Mar 2007 01:10:37 +0100 (CET) Subject: [Python-checkins] r54251 - in sandbox/trunk/2to3: README play.py tests/pytree_idempotency.py Message-ID: <20070310001037.D88C01E4002@bag.python.org> Author: collin.winter Date: Sat Mar 10 01:10:36 2007 New Revision: 54251 Added: sandbox/trunk/2to3/tests/pytree_idempotency.py - copied unchanged from r54250, sandbox/trunk/2to3/play.py Removed: sandbox/trunk/2to3/play.py Modified: sandbox/trunk/2to3/README Log: Move play.py to tests/pytree_idempotency.py. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Sat Mar 10 01:10:36 2007 @@ -6,7 +6,6 @@ README - this file test.py - runs all unittests for 2to3 -play.py - program to exercise the idempotency of pytree nodes patcomp.py - pattern compiler pytree.py - parse tree nodes (not specific to Python, despite the name!) pygram.py - code specific to the Python grammar Deleted: /sandbox/trunk/2to3/play.py ============================================================================== --- /sandbox/trunk/2to3/play.py Sat Mar 10 01:10:36 2007 +++ (empty file) @@ -1,89 +0,0 @@ -#!/usr/bin/env python2.5 -# Copyright 2006 Google, Inc. All Rights Reserved. -# Licensed to PSF under a Contributor Agreement. - -"""Main program for testing the infrastructure.""" - -__author__ = "Guido van Rossum " - -# Python imports -import os -import sys -import logging - -import pgen2 -from pgen2 import driver - -import pytree - -logging.basicConfig(level=logging.WARN) - -def main(): - gr = driver.load_grammar("Grammar.txt") - dr = driver.Driver(gr, convert=pytree.convert) - - fn = "example.py" - tree = dr.parse_file(fn, debug=True) - if not diff(fn, tree): - print "No diffs." - if not sys.argv[1:]: - return # Pass a dummy argument to run the complete test suite below - - problems = [] - - # Process every imported module - for name in sys.modules: - mod = sys.modules[name] - if mod is None or not hasattr(mod, "__file__"): - continue - fn = mod.__file__ - if fn.endswith(".pyc"): - fn = fn[:-1] - if not fn.endswith(".py"): - continue - print >>sys.stderr, "Parsing", fn - tree = dr.parse_file(fn, debug=True) - if diff(fn, tree): - problems.append(fn) - - # Process every single module on sys.path (but not in packages) - for dir in sys.path: - try: - names = os.listdir(dir) - except os.error: - continue - print >>sys.stderr, "Scanning", dir, "..." - for name in names: - if not name.endswith(".py"): - continue - print >>sys.stderr, "Parsing", name - fn = os.path.join(dir, name) - try: - tree = dr.parse_file(fn, debug=True) - except pgen2.parse.ParseError, err: - print "ParseError:", err - else: - if diff(fn, tree): - problems.append(fn) - - # Show summary of problem files - if not problems: - print "No problems. Congratulations!" - else: - print "Problems in following files:" - for fn in problems: - print "***", fn - -def diff(fn, tree): - f = open("@", "w") - try: - f.write(str(tree)) - finally: - f.close() - try: - return os.system("diff -u %s @" % fn) - finally: - os.remove("@") - -if __name__ == "__main__": - main() From nnorwitz at gmail.com Sat Mar 10 03:01:00 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Fri, 9 Mar 2007 18:01:00 -0800 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk In-Reply-To: <43aa6ff70703091455i78e41c62g59959c4eb479dd32@mail.gmail.com> References: <20070309200606.3C25E1E4002@bag.python.org> <43aa6ff70703091253j7a7159e2l3c42d2a135c92268@mail.gmail.com> <45F1DDDE.7080401@v.loewis.de> <43aa6ff70703091453n375a28bcy46f4d21ad3cd5099@mail.gmail.com> <43aa6ff70703091455i78e41c62g59959c4eb479dd32@mail.gmail.com> Message-ID: What about using test_support.unlink? Otherwise I'm fine with it. -- n On 3/9/07, Collin Winter wrote: > On 3/9/07, Collin Winter wrote: > > On 3/9/07, "Martin v. L?wis" wrote: > > > Collin Winter schrieb: > > > > Any objections to applying something like the following to address the > > > > recent spate of failures in test_posixpath:test_islink? > > > > > > In principle, this kind of stuff belongs into setUp/tearDown > > > (i.e. tearDown should make sure no files are left over; setUp > > > may do the same just to be safe). > > > > Right. I initially put the os.remove() call in the test method itself > > because only three tests use 'test_support.TESTFN + "2"' as filenames. > > I've consolidated the boilerplate teardown code from several other > > test methods into a single tearDown method. > > > > The attached patch also moves pass_os_error(), safe_remove() and > > safe_rmdir() out from under an "if hasattr(os, "symlink"):", since > > they don't depend on symlink. test_samefile() also now runs; it was > > previously over-indented and so wasn't executed. > > > > What do you think? > > Ack, forgot to attach the patch! > > Collin Winter > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > > > From python-checkins at python.org Sat Mar 10 03:23:49 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 10 Mar 2007 03:23:49 +0100 (CET) Subject: [Python-checkins] r54252 - python/trunk/Lib/test/test_posixpath.py Message-ID: <20070310022349.5F6FD1E4002@bag.python.org> Author: collin.winter Date: Sat Mar 10 03:23:40 2007 New Revision: 54252 Modified: python/trunk/Lib/test/test_posixpath.py Log: * Unlink test files before and after each test; hopefully this will cut down on recent buildbot failures in test_islink. * Drop safe_remove() in favor of test_support.unlink(). * Fix the indentation of test_samefile so that it runs. Modified: python/trunk/Lib/test/test_posixpath.py ============================================================================== --- python/trunk/Lib/test/test_posixpath.py (original) +++ python/trunk/Lib/test/test_posixpath.py Sat Mar 10 03:23:40 2007 @@ -9,8 +9,22 @@ ABSTFN = abspath(test_support.TESTFN) +def safe_rmdir(dirname): + try: + os.rmdir(dirname) + except OSError: + pass + class PosixPathTest(unittest.TestCase): + def setUp(self): + self.tearDown() + + def tearDown(self): + for suffix in ["", "1", "2"]: + test_support.unlink(test_support.TESTFN + suffix) + safe_rmdir(test_support.TESTFN + suffix) + def assertIs(self, a, b): self.assert_(a is b) @@ -125,7 +139,6 @@ finally: if not f.closed: f.close() - os.remove(test_support.TESTFN) def test_time(self): f = open(test_support.TESTFN, "wb") @@ -147,9 +160,8 @@ finally: if not f.closed: f.close() - os.remove(test_support.TESTFN) - def test_islink(self): + def test_islink(self): self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False) f = open(test_support.TESTFN + "1", "wb") try: @@ -166,14 +178,6 @@ finally: if not f.close(): f.close() - try: - os.remove(test_support.TESTFN + "1") - except os.error: - pass - try: - os.remove(test_support.TESTFN + "2") - except os.error: - pass self.assertRaises(TypeError, posixpath.islink) @@ -188,10 +192,6 @@ finally: if not f.close(): f.close() - try: - os.remove(test_support.TESTFN) - except os.error: - pass self.assertRaises(TypeError, posixpath.exists) @@ -209,14 +209,6 @@ finally: if not f.close(): f.close() - try: - os.remove(test_support.TESTFN) - except os.error: - pass - try: - os.rmdir(test_support.TESTFN) - except os.error: - pass self.assertRaises(TypeError, posixpath.isdir) @@ -234,67 +226,51 @@ finally: if not f.close(): f.close() - try: - os.remove(test_support.TESTFN) - except os.error: - pass - try: - os.rmdir(test_support.TESTFN) - except os.error: - pass self.assertRaises(TypeError, posixpath.isdir) - def test_samefile(self): - f = open(test_support.TESTFN + "1", "wb") - try: - f.write("foo") - f.close() + def test_samefile(self): + f = open(test_support.TESTFN + "1", "wb") + try: + f.write("foo") + f.close() + self.assertIs( + posixpath.samefile( + test_support.TESTFN + "1", + test_support.TESTFN + "1" + ), + True + ) + # If we don't have links, assume that os.stat doesn't return resonable + # inode information and thus, that samefile() doesn't work + if hasattr(os, "symlink"): + os.symlink( + test_support.TESTFN + "1", + test_support.TESTFN + "2" + ) self.assertIs( posixpath.samefile( test_support.TESTFN + "1", - test_support.TESTFN + "1" + test_support.TESTFN + "2" ), True ) - # If we don't have links, assume that os.stat doesn't return resonable - # inode information and thus, that samefile() doesn't work - if hasattr(os, "symlink"): - os.symlink( + os.remove(test_support.TESTFN + "2") + f = open(test_support.TESTFN + "2", "wb") + f.write("bar") + f.close() + self.assertIs( + posixpath.samefile( test_support.TESTFN + "1", test_support.TESTFN + "2" - ) - self.assertIs( - posixpath.samefile( - test_support.TESTFN + "1", - test_support.TESTFN + "2" - ), - True - ) - os.remove(test_support.TESTFN + "2") - f = open(test_support.TESTFN + "2", "wb") - f.write("bar") - f.close() - self.assertIs( - posixpath.samefile( - test_support.TESTFN + "1", - test_support.TESTFN + "2" - ), - False - ) - finally: - if not f.close(): - f.close() - try: - os.remove(test_support.TESTFN + "1") - except os.error: - pass - try: - os.remove(test_support.TESTFN + "2") - except os.error: - pass + ), + False + ) + finally: + if not f.close(): + f.close() - self.assertRaises(TypeError, posixpath.samefile) + self.assertRaises(TypeError, posixpath.samefile) def test_samestat(self): f = open(test_support.TESTFN + "1", "wb") @@ -334,14 +310,6 @@ finally: if not f.close(): f.close() - try: - os.remove(test_support.TESTFN + "1") - except os.error: - pass - try: - os.remove(test_support.TESTFN + "2") - except os.error: - pass self.assertRaises(TypeError, posixpath.samestat) @@ -421,7 +389,7 @@ os.symlink(ABSTFN+"1", ABSTFN) self.assertEqual(realpath(ABSTFN), ABSTFN+"1") finally: - self.safe_remove(ABSTFN) + test_support.unlink(ABSTFN) def test_realpath_symlink_loops(self): # Bug #930024, return the path unchanged if we get into an infinite @@ -441,9 +409,9 @@ self.assertEqual(realpath(basename(ABSTFN)), ABSTFN) finally: os.chdir(old_path) - self.safe_remove(ABSTFN) - self.safe_remove(ABSTFN+"1") - self.safe_remove(ABSTFN+"2") + test_support.unlink(ABSTFN) + test_support.unlink(ABSTFN+"1") + test_support.unlink(ABSTFN+"2") def test_realpath_resolve_parents(self): # We also need to resolve any symlinks in the parents of a relative @@ -460,9 +428,9 @@ self.assertEqual(realpath("a"), ABSTFN + "/y/a") finally: os.chdir(old_path) - self.safe_remove(ABSTFN + "/k") - self.safe_rmdir(ABSTFN + "/y") - self.safe_rmdir(ABSTFN) + test_support.unlink(ABSTFN + "/k") + safe_rmdir(ABSTFN + "/y") + safe_rmdir(ABSTFN) def test_realpath_resolve_before_normalizing(self): # Bug #990669: Symbolic links should be resolved before we @@ -486,10 +454,10 @@ self.assertEqual(realpath(basename(ABSTFN) + "/link-y/.."), ABSTFN + "/k") finally: os.chdir(old_path) - self.safe_remove(ABSTFN + "/link-y") - self.safe_rmdir(ABSTFN + "/k/y") - self.safe_rmdir(ABSTFN + "/k") - self.safe_rmdir(ABSTFN) + test_support.unlink(ABSTFN + "/link-y") + safe_rmdir(ABSTFN + "/k/y") + safe_rmdir(ABSTFN + "/k") + safe_rmdir(ABSTFN) def test_realpath_resolve_first(self): # Bug #1213894: The first component of the path, if not absolute, @@ -507,20 +475,9 @@ self.assertEqual(realpath(base + "link/k"), ABSTFN + "/k") finally: os.chdir(old_path) - self.safe_remove(ABSTFN + "link") - self.safe_rmdir(ABSTFN + "/k") - self.safe_rmdir(ABSTFN) - - # Convenience functions for removing temporary files. - def pass_os_error(self, func, filename): - try: func(filename) - except OSError: pass - - def safe_remove(self, filename): - self.pass_os_error(os.remove, filename) - - def safe_rmdir(self, dirname): - self.pass_os_error(os.rmdir, dirname) + test_support.unlink(ABSTFN + "link") + safe_rmdir(ABSTFN + "/k") + safe_rmdir(ABSTFN) def test_main(): test_support.run_unittest(PosixPathTest) From collinw at gmail.com Sat Mar 10 03:24:17 2007 From: collinw at gmail.com (Collin Winter) Date: Fri, 9 Mar 2007 20:24:17 -0600 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk In-Reply-To: References: <20070309200606.3C25E1E4002@bag.python.org> <43aa6ff70703091253j7a7159e2l3c42d2a135c92268@mail.gmail.com> <45F1DDDE.7080401@v.loewis.de> <43aa6ff70703091453n375a28bcy46f4d21ad3cd5099@mail.gmail.com> <43aa6ff70703091455i78e41c62g59959c4eb479dd32@mail.gmail.com> Message-ID: <43aa6ff70703091824j5c69b856t5987750aaebb4a53@mail.gmail.com> On 3/9/07, Neal Norwitz wrote: > What about using test_support.unlink? Otherwise I'm fine with it. -- n Removed safe_remove() in favor of test_support.unlink() and changed safe_rmdir() to be a function, not a method. Committed as r54252. Collin Winter > On 3/9/07, Collin Winter wrote: > > On 3/9/07, Collin Winter wrote: > > > On 3/9/07, "Martin v. L?wis" wrote: > > > > Collin Winter schrieb: > > > > > Any objections to applying something like the following to address the > > > > > recent spate of failures in test_posixpath:test_islink? > > > > > > > > In principle, this kind of stuff belongs into setUp/tearDown > > > > (i.e. tearDown should make sure no files are left over; setUp > > > > may do the same just to be safe). > > > > > > Right. I initially put the os.remove() call in the test method itself > > > because only three tests use 'test_support.TESTFN + "2"' as filenames. > > > I've consolidated the boilerplate teardown code from several other > > > test methods into a single tearDown method. > > > > > > The attached patch also moves pass_os_error(), safe_remove() and > > > safe_rmdir() out from under an "if hasattr(os, "symlink"):", since > > > they don't depend on symlink. test_samefile() also now runs; it was > > > previously over-indented and so wasn't executed. > > > > > > What do you think? > > > > Ack, forgot to attach the patch! > > > > Collin Winter > > > > _______________________________________________ > > Python-checkins mailing list > > Python-checkins at python.org > > http://mail.python.org/mailman/listinfo/python-checkins > > > > > > > From python-checkins at python.org Sat Mar 10 03:51:27 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 10 Mar 2007 03:51:27 +0100 (CET) Subject: [Python-checkins] r54253 - in python/trunk: Lib/SocketServer.py Lib/test/test_socketserver.py Misc/NEWS Message-ID: <20070310025127.C4A311E4002@bag.python.org> Author: collin.winter Date: Sat Mar 10 03:51:26 2007 New Revision: 54253 Modified: python/trunk/Lib/SocketServer.py python/trunk/Lib/test/test_socketserver.py python/trunk/Misc/NEWS Log: Bug #1531963: Make SocketServer.TCPServer's server_address always be equal to calling getsockname() on the server's socket. Will backport. Modified: python/trunk/Lib/SocketServer.py ============================================================================== --- python/trunk/Lib/SocketServer.py (original) +++ python/trunk/Lib/SocketServer.py Sat Mar 10 03:51:26 2007 @@ -339,6 +339,7 @@ if self.allow_reuse_address: self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind(self.server_address) + self.server_address = self.socket.getsockname() def server_activate(self): """Called by constructor to activate the server. Modified: python/trunk/Lib/test/test_socketserver.py ============================================================================== --- python/trunk/Lib/test/test_socketserver.py (original) +++ python/trunk/Lib/test/test_socketserver.py Sat Mar 10 03:51:26 2007 @@ -84,6 +84,7 @@ addr = getattr(svr, 'server_address') if addr: self.__addr = addr + assert self.__addr == svr.socket.getsockname() if verbose: print "thread: serving three times" svr.serve_a_few() if verbose: print "thread: done" Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sat Mar 10 03:51:26 2007 @@ -156,6 +156,9 @@ Library ------- +- Bug #1531963: Make SocketServer.TCPServer's server_address always + be equal to calling getsockname() on the server's socket. + - Bug #1651235: When a tuple was passed to a ctypes function call, Python would crash instead of raising an error. From python-checkins at python.org Sat Mar 10 04:19:19 2007 From: python-checkins at python.org (neal.norwitz) Date: Sat, 10 Mar 2007 04:19:19 +0100 (CET) Subject: [Python-checkins] r54254 - python/trunk/Lib/smtplib.py Message-ID: <20070310031919.923051E4002@bag.python.org> Author: neal.norwitz Date: Sat Mar 10 04:19:18 2007 New Revision: 54254 Modified: python/trunk/Lib/smtplib.py Log: Simplify a little by handling the TCP case first. Update to use predominant style of spaces around = in args list and print to stderr if debugging. Modified: python/trunk/Lib/smtplib.py ============================================================================== --- python/trunk/Lib/smtplib.py (original) +++ python/trunk/Lib/smtplib.py Sat Mar 10 04:19:18 2007 @@ -771,25 +771,25 @@ """Initialize a new instance.""" SMTP.__init__(self, host, port, local_hostname) - def connect(self, host='localhost', port = 0): + def connect(self, host = 'localhost', port = 0): """Connect to the LMTP daemon, on either a Unix or a TCP socket.""" - if host[0] == '/': - try: - self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.sock.connect(host) - except socket.error, msg: - if self.debuglevel > 0: print 'connect fail:', host - if self.sock: - self.sock.close() - self.sock = None - if not self.sock: - raise socket.error, msg - (code, msg) = self.getreply() - if self.debuglevel > 0: print "connect:", msg - return (code, msg) - else: + if host[0] != '/': return SMTP.connect(self, host, port) + # Handle Unix-domain sockets. + try: + self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + self.sock.connect(host) + except socket.error, msg: + if self.debuglevel > 0: print>>stderr, 'connect fail:', host + if self.sock: + self.sock.close() + self.sock = None + raise socket.error, msg + (code, msg) = self.getreply() + if self.debuglevel > 0: print>>stderr, "connect:", msg + return (code, msg) + # Test the sendmail method, which tests most of the others. # Note: This always sends to localhost. From python-checkins at python.org Sat Mar 10 04:31:59 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 10 Mar 2007 04:31:59 +0100 (CET) Subject: [Python-checkins] r54255 - in python/branches/release25-maint: Lib/SocketServer.py Lib/test/test_socketserver.py Misc/NEWS Message-ID: <20070310033159.DAFAD1E4002@bag.python.org> Author: collin.winter Date: Sat Mar 10 04:31:44 2007 New Revision: 54255 Modified: python/branches/release25-maint/Lib/SocketServer.py python/branches/release25-maint/Lib/test/test_socketserver.py python/branches/release25-maint/Misc/NEWS Log: Bug #1531963: Make SocketServer.TCPServer's server_address always be equal to calling getsockname() on the server's socket. Fixed by patch #1545011. Backported from r54253. Modified: python/branches/release25-maint/Lib/SocketServer.py ============================================================================== --- python/branches/release25-maint/Lib/SocketServer.py (original) +++ python/branches/release25-maint/Lib/SocketServer.py Sat Mar 10 04:31:44 2007 @@ -339,6 +339,7 @@ if self.allow_reuse_address: self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind(self.server_address) + self.server_address = self.socket.getsockname() def server_activate(self): """Called by constructor to activate the server. Modified: python/branches/release25-maint/Lib/test/test_socketserver.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_socketserver.py (original) +++ python/branches/release25-maint/Lib/test/test_socketserver.py Sat Mar 10 04:31:44 2007 @@ -84,6 +84,7 @@ addr = getattr(svr, 'server_address') if addr: self.__addr = addr + assert self.__addr == svr.socket.getsockname() if verbose: print "thread: serving three times" svr.serve_a_few() if verbose: print "thread: done" Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sat Mar 10 04:31:44 2007 @@ -196,6 +196,11 @@ Library ------- + +- Bug #1531963: Make SocketServer.TCPServer's server_address always + be equal to calling getsockname() on the server's socket. Fixed by patch + #1545011. + - Bug #1651235: When a tuple was passed to a ctypes function call, Python would crash instead of raising an error. From python-checkins at python.org Sat Mar 10 04:35:35 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 10 Mar 2007 04:35:35 +0100 (CET) Subject: [Python-checkins] r54256 - python/trunk/Misc/NEWS Message-ID: <20070310033535.A2E011E4002@bag.python.org> Author: collin.winter Date: Sat Mar 10 04:35:34 2007 New Revision: 54256 Modified: python/trunk/Misc/NEWS Log: Add proper attribution for a bug fix. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sat Mar 10 04:35:34 2007 @@ -157,7 +157,8 @@ ------- - Bug #1531963: Make SocketServer.TCPServer's server_address always - be equal to calling getsockname() on the server's socket. + be equal to calling getsockname() on the server's socket. Fixed by + patch #1545011. - Bug #1651235: When a tuple was passed to a ctypes function call, Python would crash instead of raising an error. From nnorwitz at gmail.com Sat Mar 10 04:45:38 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Fri, 9 Mar 2007 19:45:38 -0800 Subject: [Python-checkins] r54255 - in python/branches/release25-maint: Lib/SocketServer.py Lib/test/test_socketserver.py Misc/NEWS In-Reply-To: <20070310033159.DAFAD1E4002@bag.python.org> References: <20070310033159.DAFAD1E4002@bag.python.org> Message-ID: On 3/9/07, collin.winter wrote: > > Modified: python/branches/release25-maint/Lib/test/test_socketserver.py > ============================================================================== > --- python/branches/release25-maint/Lib/test/test_socketserver.py (original) > +++ python/branches/release25-maint/Lib/test/test_socketserver.py Sat Mar 10 04:31:44 2007 > @@ -84,6 +84,7 @@ > addr = getattr(svr, 'server_address') > if addr: > self.__addr = addr > + assert self.__addr == svr.socket.getsockname() > if verbose: print "thread: serving three times" > svr.serve_a_few() > if verbose: print "thread: done" It would be better to do something like: if self.__addr != svr.socket.getsockname(): raise RuntimeError, 'getsockname returns %s, expected %s' % (svr.socket.getsockname(), self.__addr) That way when running the tests with -O, errors won't pass silently. n From collinw at gmail.com Sat Mar 10 04:56:18 2007 From: collinw at gmail.com (Collin Winter) Date: Fri, 9 Mar 2007 21:56:18 -0600 Subject: [Python-checkins] r54255 - in python/branches/release25-maint: Lib/SocketServer.py Lib/test/test_socketserver.py Misc/NEWS In-Reply-To: References: <20070310033159.DAFAD1E4002@bag.python.org> Message-ID: <43aa6ff70703091956r6b9b5a1bu6635813ca94e61d8@mail.gmail.com> On 3/9/07, Neal Norwitz wrote: > On 3/9/07, collin.winter wrote: > > > > Modified: python/branches/release25-maint/Lib/test/test_socketserver.py > > ============================================================================== > > --- python/branches/release25-maint/Lib/test/test_socketserver.py (original) > > +++ python/branches/release25-maint/Lib/test/test_socketserver.py Sat Mar 10 04:31:44 2007 > > @@ -84,6 +84,7 @@ > > addr = getattr(svr, 'server_address') > > if addr: > > self.__addr = addr > > + assert self.__addr == svr.socket.getsockname() > > if verbose: print "thread: serving three times" > > svr.serve_a_few() > > if verbose: print "thread: done" > > It would be better to do something like: > > if self.__addr != svr.socket.getsockname(): > raise RuntimeError, 'getsockname returns %s, expected %s' % > (svr.socket.getsockname(), self.__addr) > > That way when running the tests with -O, errors won't pass silently. I think the error message is more like raise RuntimeError('server_address was %s, expected %s' % (self.__addr, svr.socket.getsockname())) but I take your point. I'll make the changes. Collin Winter From buildbot at python.org Sat Mar 10 06:10:59 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 10 Mar 2007 05:10:59 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 Message-ID: <20070310051059.C3F381E4002@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/49 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_urllibnet make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Sat Mar 10 06:39:02 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 10 Mar 2007 05:39:02 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070310053903.199E11E4002@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/271 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: neal.norwitz Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_urllibnet sincerely, -The Buildbot From python-checkins at python.org Sat Mar 10 08:38:18 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 10 Mar 2007 08:38:18 +0100 (CET) Subject: [Python-checkins] r54257 - in python/trunk: Modules/getpath.c Python/import.c Message-ID: <20070310073818.351F81E4002@bag.python.org> Author: georg.brandl Date: Sat Mar 10 08:38:14 2007 New Revision: 54257 Modified: python/trunk/Modules/getpath.c python/trunk/Python/import.c Log: Typos. Modified: python/trunk/Modules/getpath.c ============================================================================== --- python/trunk/Modules/getpath.c (original) +++ python/trunk/Modules/getpath.c Sat Mar 10 08:38:14 2007 @@ -26,7 +26,7 @@ * as best as is possible, but most imports will fail. * * Before any searches are done, the location of the executable is - * determined. If argv[0] has one or more slashs in it, it is used + * determined. If argv[0] has one or more slashes in it, it is used * unchanged. Otherwise, it must have been invoked from the shell's path, * so we search $PATH for the named executable and use that. If the * executable was not found on $PATH (or there was no $PATH environment Modified: python/trunk/Python/import.c ============================================================================== --- python/trunk/Python/import.c (original) +++ python/trunk/Python/import.c Sat Mar 10 08:38:14 2007 @@ -2536,7 +2536,7 @@ if (import == NULL) goto err; - /* Call the _import__ function with the proper argument list */ + /* Call the __import__ function with the proper argument list */ r = PyObject_CallFunctionObjArgs(import, module_name, globals, globals, silly_list, NULL); From martin at v.loewis.de Sat Mar 10 08:59:17 2007 From: martin at v.loewis.de (=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=) Date: Sat, 10 Mar 2007 08:59:17 +0100 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk In-Reply-To: <43aa6ff70703091455i78e41c62g59959c4eb479dd32@mail.gmail.com> References: <20070309200606.3C25E1E4002@bag.python.org> <43aa6ff70703091253j7a7159e2l3c42d2a135c92268@mail.gmail.com> <45F1DDDE.7080401@v.loewis.de> <43aa6ff70703091453n375a28bcy46f4d21ad3cd5099@mail.gmail.com> <43aa6ff70703091455i78e41c62g59959c4eb479dd32@mail.gmail.com> Message-ID: <45F26555.2060905@v.loewis.de> Collin Winter schrieb: >> What do you think? Looks fine! Martin From martin at v.loewis.de Sat Mar 10 09:00:46 2007 From: martin at v.loewis.de (=?UTF-8?B?Ik1hcnRpbiB2LiBMw7Z3aXMi?=) Date: Sat, 10 Mar 2007 09:00:46 +0100 Subject: [Python-checkins] r54198 - in python/branches/release25-maint: Lib/glob.py Lib/test/test_glob.py Misc/NEWS In-Reply-To: <9e804ac0703091536wd538256r2945c775239f9020@mail.gmail.com> References: <20070307083226.905111E4003@bag.python.org> <9e804ac0703091536wd538256r2945c775239f9020@mail.gmail.com> Message-ID: <45F265AE.7050203@v.loewis.de> Thomas Wouters schrieb: > > This change should not be backported, IMHO. (It changes functioning > code, as far as I can tell -- but feel free to correct me :) That's both true. Martin From python-checkins at python.org Sat Mar 10 09:06:15 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 10 Mar 2007 09:06:15 +0100 (CET) Subject: [Python-checkins] r54258 - in python/branches/release25-maint: Lib/glob.py Lib/test/test_glob.py Misc/NEWS Message-ID: <20070310080615.8BFCB1E4002@bag.python.org> Author: georg.brandl Date: Sat Mar 10 09:06:14 2007 New Revision: 54258 Modified: python/branches/release25-maint/Lib/glob.py python/branches/release25-maint/Lib/test/test_glob.py python/branches/release25-maint/Misc/NEWS Log: Revert rev. 54198, it's not really backwards compatible. Modified: python/branches/release25-maint/Lib/glob.py ============================================================================== --- python/branches/release25-maint/Lib/glob.py (original) +++ python/branches/release25-maint/Lib/glob.py Sat Mar 10 09:06:14 2007 @@ -1,9 +1,8 @@ """Filename globbing utility.""" -import sys import os -import re import fnmatch +import re __all__ = ["glob", "iglob"] @@ -49,15 +48,13 @@ def glob1(dirname, pattern): if not dirname: dirname = os.curdir - if isinstance(pattern, unicode) and not isinstance(dirname, unicode): - dirname = unicode(dirname, sys.getfilesystemencoding()) try: names = os.listdir(dirname) except os.error: return [] - if pattern[0] != '.': - names = filter(lambda x: x[0] != '.', names) - return fnmatch.filter(names, pattern) + if pattern[0]!='.': + names=filter(lambda x: x[0]!='.',names) + return fnmatch.filter(names,pattern) def glob0(dirname, basename): if basename == '': Modified: python/branches/release25-maint/Lib/test/test_glob.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_glob.py (original) +++ python/branches/release25-maint/Lib/test/test_glob.py Sat Mar 10 09:06:14 2007 @@ -52,16 +52,6 @@ eq(self.glob('aab'), [self.norm('aab')]) eq(self.glob('zymurgy'), []) - # test return types are unicode, but only if os.listdir - # returns unicode filenames - uniset = set([unicode]) - tmp = os.listdir(u'.') - if set(type(x) for x in tmp) == uniset: - u1 = glob.glob(u'*') - u2 = glob.glob(u'./*') - self.assertEquals(set(type(r) for r in u1), uniset) - self.assertEquals(set(type(r) for r in u2), uniset) - def test_glob_one_directory(self): eq = self.assertSequencesEqual_noorder eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa'])) Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sat Mar 10 09:06:14 2007 @@ -217,9 +217,6 @@ never made sense with ordinary subclasses -- the failure just occurred later, with a more cumbersome exception. -- Patch #1001604: glob.glob() now returns unicode filenames if it was - given a unicode argument and os.listdir() returns unicode filenames. - - Patch #685268: Consider a package's __path__ in imputil. - Patch 1463026: Support default namespace in XMLGenerator. From buildbot at python.org Sat Mar 10 09:44:31 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 10 Mar 2007 08:44:31 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP 2.5 Message-ID: <20070310084431.784041E4002@bag.python.org> The Buildbot has detected a new failure of x86 XP 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%25202.5/builds/156 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings failed slave lost sincerely, -The Buildbot From buildbot at python.org Sat Mar 10 10:01:53 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 10 Mar 2007 09:01:53 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 2.5 Message-ID: <20070310090153.DF1901E4002@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%25202.5/builds/200 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket sincerely, -The Buildbot From python-checkins at python.org Sat Mar 10 13:38:48 2007 From: python-checkins at python.org (eric.smith) Date: Sat, 10 Mar 2007 13:38:48 +0100 (CET) Subject: [Python-checkins] r54259 - sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070310123848.6655C1E4002@bag.python.org> Author: eric.smith Date: Sat Mar 10 13:38:46 2007 New Revision: 54259 Modified: sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Added test cases for 2's compliment algorithm in binary converter. Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Sat Mar 10 13:38:46 2007 @@ -308,6 +308,32 @@ # error in writing the digits might write over the parens self.formatEqualsWithUnicode("(" + s + ")", "{0:()b}", -i) + def test_from_str(s): + n = int(s, 2) + self.formatEqualsWithUnicode(s, "{0:b}", n) + self.formatEqualsWithUnicode("-" + s, "{0:b}", -n) + self.formatEqualsWithUnicode("(" + s + ")", "{0:()b}", -n) + + # test the 2's compliment algorithm + # it has a special test for all ones inside a byte, so test + # byte aligned strings of ones + test_from_str("1" * 8) + test_from_str("1" + "1" * 8) + test_from_str("10" + "1" * 8) + test_from_str("1" * 8 + "0" * 8) + test_from_str("1" + "1" * 8 + "0" * 8) + test_from_str("10" + "1" * 8 + "0" * 8) + test_from_str("1" * 8 + "0" * 8 + "1" * 8) + test_from_str("1" + "1" * 8 + "0" * 8 + "1" * 8) + test_from_str("10" + "1" * 8 + "0" * 8 + "1" * 8) + test_from_str("1" * 16) + test_from_str("1" + "1" * 16) + test_from_str("10" + "1" * 16) + test_from_str("1" * 16 + "0" * 8) + test_from_str("1" + "1" * 16 + "0" * 8) + test_from_str("10" + "1" * 16 + "0" * 8) + + def test_number_specifier(self): def test(value): self.formatEqualsWithUnicode(locale.format("%f", value), "{0:n}", value) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Sat Mar 10 13:38:46 2007 @@ -52,6 +52,10 @@ #if PYTHON_API_VERSION < 1013 typedef int Py_ssize_t; #define Py_LOCAL_INLINE(x) static x + +#define PySet_Discard PyDict_DelItem +#define PySet_New PyDict_Copy +#define PySet_GET_SIZE PyDict_Size #endif /* Defines for more efficiently reallocating the string buffer */ @@ -59,12 +63,6 @@ #define SIZE_MULTIPLIER 2 #define MAX_SIZE_INCREMENT 3200 -#if PYTHON_API_VERSION < 1013 -#define PySet_Discard PyDict_DelItem -#define PySet_New PyDict_Copy -#define PySet_GET_SIZE PyDict_Size -#endif - /* MAXLEN_INT_STRING is the maximum length of an integer represented * as a string, in base 10. The analysis in stringobject.c shows that @@ -1333,7 +1331,8 @@ } else if (PyUnicode_Check(fieldobj)) { CH_TYPE *ubuf; int len; - if (!PyArg_Parse(fieldobj, "u#;\"c\" format requires int or char", &ubuf, &len)) + if (!PyArg_Parse(fieldobj, "u#;\"c\" format requires int or char", + &ubuf, &len)) return 0; if (len != 1) { From python-checkins at python.org Sat Mar 10 15:33:36 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 10 Mar 2007 15:33:36 +0100 (CET) Subject: [Python-checkins] r54260 - python/trunk/Lib/test/test_socketserver.py Message-ID: <20070310143336.0B4661E4002@bag.python.org> Author: collin.winter Date: Sat Mar 10 15:33:32 2007 New Revision: 54260 Modified: python/trunk/Lib/test/test_socketserver.py Log: Convert an assert to a raise so it works even in the presence of -O. Modified: python/trunk/Lib/test/test_socketserver.py ============================================================================== --- python/trunk/Lib/test/test_socketserver.py (original) +++ python/trunk/Lib/test/test_socketserver.py Sat Mar 10 15:33:32 2007 @@ -81,10 +81,12 @@ svr = svrcls(self.__addr, self.__hdlrcls) # pull the address out of the server in case it changed # this can happen if another process is using the port - addr = getattr(svr, 'server_address') + addr = svr.server_address if addr: self.__addr = addr - assert self.__addr == svr.socket.getsockname() + if self.__addr != svr.socket.getsockname(): + raise RuntimeError('server_address was %s, expected %s' % + (self.__addr, svr.socket.getsockname())) if verbose: print "thread: serving three times" svr.serve_a_few() if verbose: print "thread: done" From python-checkins at python.org Sat Mar 10 15:35:23 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 10 Mar 2007 15:35:23 +0100 (CET) Subject: [Python-checkins] r54261 - python/branches/release25-maint/Lib/test/test_socketserver.py Message-ID: <20070310143523.AC7151E4002@bag.python.org> Author: collin.winter Date: Sat Mar 10 15:35:22 2007 New Revision: 54261 Modified: python/branches/release25-maint/Lib/test/test_socketserver.py Log: Convert an assert to a raise so it works even in the presence of -O. Modified: python/branches/release25-maint/Lib/test/test_socketserver.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_socketserver.py (original) +++ python/branches/release25-maint/Lib/test/test_socketserver.py Sat Mar 10 15:35:22 2007 @@ -81,10 +81,12 @@ svr = svrcls(self.__addr, self.__hdlrcls) # pull the address out of the server in case it changed # this can happen if another process is using the port - addr = getattr(svr, 'server_address') + addr = svr.server_address if addr: self.__addr = addr - assert self.__addr == svr.socket.getsockname() + if self.__addr != svr.socket.getsockname(): + raise RuntimeError('server_address was %s, expected %s' % + (self.__addr, svr.socket.getsockname())) if verbose: print "thread: serving three times" svr.serve_a_few() if verbose: print "thread: done" From python-checkins at python.org Sat Mar 10 15:41:51 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 10 Mar 2007 15:41:51 +0100 (CET) Subject: [Python-checkins] r54262 - in python/trunk: Doc/lib/libdocxmlrpc.tex Doc/lib/libsimplexmlrpc.tex Lib/DocXMLRPCServer.py Lib/SimpleXMLRPCServer.py Lib/SocketServer.py Misc/NEWS Message-ID: <20070310144151.5478F1E4007@bag.python.org> Author: collin.winter Date: Sat Mar 10 15:41:48 2007 New Revision: 54262 Modified: python/trunk/Doc/lib/libdocxmlrpc.tex python/trunk/Doc/lib/libsimplexmlrpc.tex python/trunk/Lib/DocXMLRPCServer.py python/trunk/Lib/SimpleXMLRPCServer.py python/trunk/Lib/SocketServer.py python/trunk/Misc/NEWS Log: Patch #1599845: Add an option to disable the implicit calls to server_bind() and server_activate() in the constructors for TCPServer, SimpleXMLRPCServer and DocXMLRPCServer. Modified: python/trunk/Doc/lib/libdocxmlrpc.tex ============================================================================== --- python/trunk/Doc/lib/libdocxmlrpc.tex (original) +++ python/trunk/Doc/lib/libdocxmlrpc.tex Sat Mar 10 15:41:48 2007 @@ -14,8 +14,12 @@ \class{DocXMLRPCServer}, or embedded in a CGI environment, using \class{DocCGIXMLRPCRequestHandler}. -\begin{classdesc}{DocXMLRPCServer}{addr\optional{, - requestHandler\optional{, logRequests}}} +\begin{classdesc}{DocXMLRPCServer}{addr\optional{, + requestHandler\optional{, + logRequests\optional{, + allow_none\optional{, + encoding\optional{, + bind_and_activate}}}}}} Create a new server instance. All parameters have the same meaning as for \class{SimpleXMLRPCServer.SimpleXMLRPCServer}; Modified: python/trunk/Doc/lib/libsimplexmlrpc.tex ============================================================================== --- python/trunk/Doc/lib/libsimplexmlrpc.tex (original) +++ python/trunk/Doc/lib/libsimplexmlrpc.tex Sat Mar 10 15:41:48 2007 @@ -15,7 +15,9 @@ \begin{classdesc}{SimpleXMLRPCServer}{addr\optional{, requestHandler\optional{, - logRequests\optional{, allow_none\optional{, encoding}}}}} + logRequests\optional{, + allow_none\optional{, + encoding}}}}} Create a new server instance. This class provides methods for registration of functions that can be called by @@ -28,8 +30,13 @@ setting this parameter to false will turn off logging. The \var{allow_none} and \var{encoding} parameters are passed on to \module{xmlrpclib} and control the XML-RPC responses that will be returned - from the server. + from the server. The \var{bind_and_activate} parameter controls whether + \method{server_bind()} and \method{server_activate()} are called immediately + by the constructor; it defaults to true. Setting it to false allows code to + manipulate the \var{allow_reuse_address} class variable before the address + is bound. \versionchanged[The \var{allow_none} and \var{encoding} parameters were added]{2.5} + \versionchanged[The \var{bind_and_activate} parameter was added]{2.6} \end{classdesc} \begin{classdesc}{CGIXMLRPCRequestHandler}{\optional{allow_none\optional{, encoding}}} Modified: python/trunk/Lib/DocXMLRPCServer.py ============================================================================== --- python/trunk/Lib/DocXMLRPCServer.py (original) +++ python/trunk/Lib/DocXMLRPCServer.py Sat Mar 10 15:41:48 2007 @@ -252,8 +252,10 @@ """ def __init__(self, addr, requestHandler=DocXMLRPCRequestHandler, - logRequests=1): - SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests) + logRequests=1, allow_none=False, encoding=None, + bind_and_activate=True): + SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests, + allow_none, encoding, bind_and_activate) XMLRPCDocGenerator.__init__(self) class DocCGIXMLRPCRequestHandler( CGIXMLRPCRequestHandler, Modified: python/trunk/Lib/SimpleXMLRPCServer.py ============================================================================== --- python/trunk/Lib/SimpleXMLRPCServer.py (original) +++ python/trunk/Lib/SimpleXMLRPCServer.py Sat Mar 10 15:41:48 2007 @@ -518,11 +518,11 @@ allow_reuse_address = True def __init__(self, addr, requestHandler=SimpleXMLRPCRequestHandler, - logRequests=True, allow_none=False, encoding=None): + logRequests=True, allow_none=False, encoding=None, bind_and_activate=True): self.logRequests = logRequests SimpleXMLRPCDispatcher.__init__(self, allow_none, encoding) - SocketServer.TCPServer.__init__(self, addr, requestHandler) + SocketServer.TCPServer.__init__(self, addr, requestHandler, bind_and_activate) # [Bug #1222790] If possible, set close-on-exec flag; if a # method spawns a subprocess, the subprocess shouldn't have Modified: python/trunk/Lib/SocketServer.py ============================================================================== --- python/trunk/Lib/SocketServer.py (original) +++ python/trunk/Lib/SocketServer.py Sat Mar 10 15:41:48 2007 @@ -279,7 +279,7 @@ Methods for the caller: - - __init__(server_address, RequestHandlerClass) + - __init__(server_address, RequestHandlerClass, bind_and_activate=True) - serve_forever() - handle_request() # if you don't use serve_forever() - fileno() -> int # for select() @@ -322,13 +322,14 @@ allow_reuse_address = False - def __init__(self, server_address, RequestHandlerClass): + def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True): """Constructor. May be extended, do not override.""" BaseServer.__init__(self, server_address, RequestHandlerClass) self.socket = socket.socket(self.address_family, self.socket_type) - self.server_bind() - self.server_activate() + if bind_and_activate: + self.server_bind() + self.server_activate() def server_bind(self): """Called by constructor to bind the socket. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sat Mar 10 15:41:48 2007 @@ -156,6 +156,10 @@ Library ------- +- Patch #1599845: Add an option to disable the implicit calls to server_bind() + and server_activate() in the constructors for TCPServer, SimpleXMLRPCServer + and DocXMLRPCServer. + - Bug #1531963: Make SocketServer.TCPServer's server_address always be equal to calling getsockname() on the server's socket. Fixed by patch #1545011. From buildbot at python.org Sat Mar 10 16:11:21 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 10 Mar 2007 15:11:21 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable trunk Message-ID: <20070310151121.91E291E4002@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%2520trunk/builds/155 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_bsddb3 make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Sat Mar 10 16:48:30 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 10 Mar 2007 15:48:30 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070310154830.9C2591E4002@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/103 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Sat Mar 10 19:31:50 2007 From: python-checkins at python.org (patrick.maupin) Date: Sat, 10 Mar 2007 19:31:50 +0100 (CET) Subject: [Python-checkins] r54263 - in sandbox/trunk/pep3101: doctests doctests/README.txt doctests/basic_errors.txt doctests/basic_examples.txt doctests/basic_torture.txt doctests/test.py loadpep.py unicodeformat.c Message-ID: <20070310183150.32E351E4002@bag.python.org> Author: patrick.maupin Date: Sat Mar 10 19:31:44 2007 New Revision: 54263 Added: sandbox/trunk/pep3101/doctests/ sandbox/trunk/pep3101/doctests/README.txt sandbox/trunk/pep3101/doctests/basic_errors.txt sandbox/trunk/pep3101/doctests/basic_examples.txt sandbox/trunk/pep3101/doctests/basic_torture.txt sandbox/trunk/pep3101/doctests/test.py (contents, props changed) Modified: sandbox/trunk/pep3101/loadpep.py sandbox/trunk/pep3101/unicodeformat.c Log: Started work on better exception handling, and added doctest directory with combination test/tutorial files. Added: sandbox/trunk/pep3101/doctests/README.txt ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/doctests/README.txt Sat Mar 10 19:31:44 2007 @@ -0,0 +1,10 @@ +The examples in this directory are runnable against doctest. (run.py will do this) + +The files are: + + basic_examples.txt -- non-specifier examples + basic_errors.txt -- non-specifier exception testion + basic_torture.txt -- non-specifier corner-case testing + +XXX -- should probably add different files for specifier_examples and specifier_errors + Added: sandbox/trunk/pep3101/doctests/basic_errors.txt ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/doctests/basic_errors.txt Sat Mar 10 19:31:44 2007 @@ -0,0 +1,25 @@ + +This file tries to check that all errors above the +field-specifier code in unicodeformat.c and pep3101.c +can be generated. + +XXX -- This is definitely still a work in progress! + +>>> from pep3101 import format as f + +>>> f() +Traceback (most recent call last): +TypeError: Function expects at least one argument + +>>> f(1) +Traceback (most recent call last): +TypeError: First parameter must be string or unicode object + +>>> f('{0} {abc', 1) +Traceback (most recent call last): +ValueError: Unterminated replacement field at format_string[5] + + +>>> f('{') +Traceback (most recent call last): +ValueError: Unexpected escape to markup at end of format_string Added: sandbox/trunk/pep3101/doctests/basic_examples.txt ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/doctests/basic_examples.txt Sat Mar 10 19:31:44 2007 @@ -0,0 +1,299 @@ + + Examples of how to use the PEP3101 sandbox implementation. + This does not show the nuances of using different specifiers. + We should add another file for those. For now, you can see the + unittests in ../test_simpleformat.py for comprehensive yet + terse examples. + +>>> from pep3101 import format as f + + A null string is OK. + +>>> print f('') + + + A string with no parameters is OK. + +>>> print f('Hi there') +Hi there + + A string with parameters is OK, even if it doesn't use them. + +>>> print f('Hi there', 1, name='Joe') +Hi there + + Unless the string declares that it needs to use all of them. + +>>> print f('{!useall}Hi there', 1, name='Joe') +Traceback (most recent call last): +ValueError: Not all arguments consumed at end of format_string + + Positional parameters are accessed by number, and the escaping + mechanism is {}. For literal { or }, use {{ or }}. + +>>> print f('{{{0}}}: My name is {0}. Are you {1}?', 'Fred', 'George') +{Fred}: My name is Fred. Are you George? + + Keyword parameters can also be used. + +>>> print f('{{{actor2}}}: My name is {actor2}. Are you {actor1}?', +... actor2='Fred', actor1='George') +{Fred}: My name is Fred. Are you George? + + Locals() and globals() can be used if no parameters are given. We + may change this if it isn't a big enough convenience win, because + EIBTI. + +>>> actor1, actor2 = 'George', 'Fred' +>>> print f('{{{actor2}}}: My name is {actor2}. Are you {actor1}?') +{Fred}: My name is Fred. Are you George? + + We also have the capability to explicitly specify the dictionary. + +>>> print f('{{{actor2}}}: My name is {actor2}. Are you {actor1}?', +... _dict=locals()) +{Fred}: My name is Fred. Are you George? + + If you have a real need, you could even specify multiple dictionaries. + +>>> print f('{{{actor2}}}: My name is {actor2}. Are you {actor1}?', +... _dict=(dict(actor1=actor1), dict(whatever=3), dict(), dict(actor2=actor2))) +{Fred}: My name is Fred. Are you George? + + Attempt to use a non-existent argument causes an exception. + +>>> print f("There is no {4} arg", 42, 24) +Traceback (most recent call last): +ValueError: Not enough positional arguments at format_string[13] + +>>> print f("There is no {foo} arg", 42, 24) +Traceback (most recent call last): +ValueError: Keyword argument not found at format_string[13] + + For multi-line strings, the error message tries to help you out + a bit more, by figuring out the line and column. + +>>> print f("Test\nTest\nTest\nThere is no {4} arg\nTest", 42, 24) +Traceback (most recent call last): +ValueError: Not enough positional arguments in format_string at line 4, column 14 + + Arbitrarily complex attributes and indices can be accessed. + +>>> class Foo(object): +... pass +... +>>> x, y, z = Foo(), Foo(), Foo() +>>> x.a = [3, 4, 5, 42, 7, 2, 9, 6] +>>> y.b = [1, x, 5] +>>> z.c = [10, 11, 12, 13, 14, y, 16, 17, 1, 9] +>>> print f("{z.c[5].b[1].a[3]}") +42 + + Attributes and indices can even be retrieved from other variables. + NB: Unless somebody has a really good use case, this capability + is probably going away. It was added to try to satisfy Ian's + requests that dictionary lookup capabilities of the % operator + still be supported, but that was before the _dict parameter was + added, so it's probably not that necessary any more. + +>>> print f("{y.b[{z.c[8]}].a[3]}") +42 + + Indices don't have to be numbers. + +>>> m = dict(foo='Sam') +>>> print f("{0[foo]} went to the fair.", m) +Sam went to the fair. + + Actually, the current rule (which is subject to debate), is + that indices and attributes can contain anything which won't confuse + the basic format string lexer. For example, they can't contain "{", + "}", "[", "]", or ".", but pretty much anything else is fair game. + (Note, however, that if we beef up the lexer for any reason, the + list of disallowed characters could grow. For example, whitespace + could easily be added to this list.) + +>>> m['-a?#$% 03'] = 4 +>>> setattr(x, '27', 2) +>>> print f("{m[-a?#$% 03]}{x.27}") +42 + + The only processing performed is that an index (but not an attribute) + with a leading digit is converted to an integer. + +>>> m[0] = 4 +>>> setattr(x, '0', 2) +>>> print f("{m[0]}{x.0}") +42 + + The reason this behavior might be reasonable is that, in general, + objects will protect themselves from "unauthorized" access by + the simple fact that an exception will be thrown when the bad + attribute or index is tried. In other words, we rely on the + underlying object to throw an exception. + +>>> print f("{m[1]}") +Traceback (most recent call last): +KeyError: 1 + +>>> print f("{x.1}") +Traceback (most recent call last): +AttributeError: 'Foo' object has no attribute '1' + + + I lied a teensy bit about all that. Objects won't protect + themselves from unauthorized access to "private" attributes, + so the parser disallows leading underscores; it assumes you're + trying to pull a fast one if you use one of these. + +>>> x._evil_access = "Don't try this at home" +>>> print f("{x._evil_access}") +Traceback (most recent call last): +ValueError: Leading underscores not allowed in attribute/index strings at format_string[3] + + The programmer (but not the format string itself) + can override this security behavior. + +>>> _allow_leading_underscores = 1 +>>> print f("{x._evil_access}") +Don't try this at home + + Any object can provide a custom __format__ method to control + its own formatting. In 3.0, some of the builtin types will + probably have this method added to them and we can reduce + the code in unicodeformat.c. + +>>> class Custom(object): +... def __format__(self, specifiers): +... return specifiers.upper() +>>> custom = Custom() +>>> print f("{0: Almost any specifier text you want}", custom) + ALMOST ANY SPECIFIER TEXT YOU WANT + + Since the specifier can be wholly or partially retrieved from + a variable, this can give great flexibility in what is printed + out. + +>>> print f("The{0: answer is {1}{2}, or} so I hear", custom, 4, 2) +The ANSWER IS 42, OR so I hear + + The custom format hook is similar to the custom __format__ + method, in that the format function will call out to external + Python code to help with the formatting. + + If you use the {!hook} directive in the format string, you + can call out to the hook function on every single format call. + +>>> def hook(obj, specifier): +... print "Hook received", obj, specifier +... if obj == 42: +... return "the answer" +... if obj == 66: +... return None # returning None lets the default specifier handle it +... return '%s %s' % (obj, specifier) +... +>>> _hook = hook +>>> print f("{!hook}Call out to a {0:function} to print {1}.", "hook", 42) +Hook received hook function +Hook received 42 +Call out to a hook function to print the answer. + + If the hook function decides it doesn't want to perform the + formatting, it can defer back to the internal formatter by + returning None. + +>>> print f("{!hook}I think {0} is {1:x}.", 42, 66) +Hook received 42 +Hook received 66 x +I think the answer is 42. + + Using the hook function in this fashion gives great flexibility + about how things are displayed. However, in many applications, + the hook function is only required for a few fields, so you + can explicitly request the hook function by placing a "p" (for + python) in the field specifier type. + +>>> print f("In fact, I'm sure {0:p} is {0}!", 42) +Hook received 42 p +In fact, I'm sure the answer is 42! + + The hook function could still decide to defer execution to the + internal formatter, but no good can come of this, since the + internal formatter doesn't know anything about the "p" type. + XXX -- I don't like the error message here -- need to debug and fix. + +>>> print f("{0:p} trombones led the big parade.", 66) +Traceback (most recent call last): +ValueError: Invalid conversion character at end of format_string + + Format strings may contain comments (which are not inserted + into the output string). Comments are specified in a fairly + intuitive way. One of the best uses for comments is to + break up source lines which are too long. + +>>> print f("""The product of {z.c[5].b[1].a[7]} and {z.c[5].b[1].a[4]}{# +... +... Don't really need any text here, but it's in a comment so it +... doesn't matter. The point is that we can wrap a line before +... it gets to 80 characters if we wish to do so. +... +... } is {z.c[5].b[1].a[3]}.""") +The product of 6 and 7 is 42. + + The implementation currently has the ability to support a few + variations on the characters used to transition from text to + markup. It might be unwieldy (and require inefficient code) + to support too many different markup syntaxes, but the currently + supported ones are similar enough to be parsed by the same C loop + quite easily. It may seem that the choice of syntax comes down + to personal taste (and there is undoubtedly a lot of that), but + different problem domains arguably lend themselves to different + syntaxes. + + One thing that is certain is that, if different syntaxes are + to be supported, the template itself should announce if it + is not using the default syntax, both so that automated tools + can be used to analyze templates, and also because the syntax + chosen is definitely a part of the template coding itself, rather + than a part of the underlying Python objects to be displayed. + + The default syntax, as we have seen, uses {} to delineate markup + from normal text. + +>>> print f("""{!syntax0} +... In syntax 0, literal {{ and }} characters are inserted by doubling them.""") +In syntax 0, literal { and } characters are inserted by doubling them. + + It was pointed out to me that XML, for instance, requires a literal + < to be escaped, but not a literal >. Obviously, for some sorts of + text, it will be useful to see {{ balance }}, but perhaps for other + sorts of text it is useful to not need to escape }. I don't know, + but it's easy enough to do. + +>>> print f("""{!syntax1} +... Syntax 1 is the same as syntax 0, except } characters are not doubled.""") +Syntax 1 is the same as syntax 0, except } characters are not doubled. + + In some text with a lot of braces, but few markup substitutions, + it might be difficult to visually find the markup inside the text. + Syntax 2 handles these situations handily by requiring a more + traditional ${} approach to markup. + +>>> print f("""{!syntax2} +... Syntax ${0} requires $${} for markup. Use $$$${ for a literal $${.""", 2) +Syntax 2 requires ${} for markup. Use $${ for a literal ${. + + This brings us to the last syntax supported by the sandbox + implementation. Syntax 3 would send any non-Python programmer + running, because it depends on significant whitespace. It works + great for things like C templates where most left braces are + followed by a newline. + +>>> print f("""{!syntax3} +... Syntax {0} requires { } for markup. Use "{ " for a literal "{ ", +... or use { by itself followed by a newline: { +... The trailing space will be "eaten" but the trailing newline will not.""", +... 3) +Syntax 3 requires {} for markup. Use "{ " for a literal "{", +or use { by itself followed by a newline: { +The trailing space will be "eaten" but the trailing newline will not. Added: sandbox/trunk/pep3101/doctests/basic_torture.txt ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/doctests/basic_torture.txt Sat Mar 10 19:31:44 2007 @@ -0,0 +1,117 @@ + +This file contains corner case testing for non-field-specifier code, +to augment the test cases in the unittests. + +XXX - This is definitely still a work in progress! + +>>> from pep3101 import format as f + +######################################################### +Make sure useall works correctly under lots of conditions + +>>> print f('{!useall}Hi there', 1, 2, 3, 4, 5) +Traceback (most recent call last): +ValueError: Not all arguments consumed at end of format_string + +>>> print f('{!useall}Hi there', name='Joe') +Traceback (most recent call last): +ValueError: Not all arguments consumed at end of format_string + +>>> print f('{!useall}Hi there', _dict=()) +Hi there + +>>> print f('{!useall}Hi {there}', _dict=dict(there='there')) +Hi there + +>>> print f('{!useall}Hi {there}', 1, _dict=dict(there='there')) +Traceback (most recent call last): +ValueError: Not all arguments consumed at end of format_string + +>>> print f('{!useall}Hi {there}', _dict=dict(there='there'), foo=3) +Traceback (most recent call last): +ValueError: Not all arguments consumed at end of format_string + + + +Custom __format__ objects + + + def test_name_mapper(self): + mydict = dict(foo=1, bar=2) + dict2 = mydict, dict(foobar=3) + foo = 27 + global3 = 50 + self.formatRaises(ValueError, "{foo}") + self.formatRaises(ValueError, "{foo} {foobar}", _dict=mydict) + self.formatEquals("1", "{foo}", _dict=mydict) + self.formatEquals("1 2", "{foo} {bar}", _dict=mydict) + self.formatRaises(ValueError, "{foo} {bar} {global3}", _dict=mydict) + self.formatEquals("1 2 3", "{foo} {bar} {foobar}", _dict=dict2) + self.formatEquals("27 2", "{foo} {bar}", _dict=mydict, foo=foo) + self.assertEquals( + pep3101.format("{foo} {global3} {global1}"), + "27 50 10") + + + def test_check_unused(self): + mydict = dict(foo=1, foo2=1) + bar = 3 + bar2 = 4 + result = ' a b 1 3' + s = ' {0} {1} {foo} {bar}' + s2 = '{!useall}' + s + s3 = '{!useall}\r\n' + s + s4 = '{!useall}\n' + s + s5 = '{!useall}\r\n' + s + self.formatEquals(result, s, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s2, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s3, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s4, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s5, 'a', 'b', bar=bar, _dict=mydict) + self.formatEquals(result, s, 'a', 'b', 3, bar=bar, _dict=mydict) + self.formatRaises(ValueError, s2, 'a', 'b', 3, bar=bar, _dict=mydict) + self.formatEquals(result, s, 'a', 'b', bar=bar, _dict=mydict, sam=27) + self.formatRaises(ValueError, s2, 'a', 'b', bar=bar, _dict=mydict, sam=27) + self.formatEquals(result, s, 'a', 'b', bar=bar, foo=1) + self.formatEquals(result, s, 'a', 'b', bar=bar, foo=1) + self.formatEquals(result, s, 'a', 'b', bar=bar, foo=1, sam=27) + self.formatRaises(ValueError, s2, 'a', 'b', bar=bar, foo=1, sam=27) + self.formatRaises(ValueError, '{!useall}', 1) + self.formatRaises(ValueError, '{!useall}', foo=1) + + + def test_format_hook(self): + def hookfunc(obj, spec): + if obj > 100: + return None + return '_%s_' % (obj, spec)[obj==3] + self.formatEquals('_a_ _4_ 123', + '{!hook}{0:a} {1:b}{2:>10d}', + 3, 4, 123, _hook=hookfunc) + self.formatEquals('_ap_ _4_ 123', + '{0:ap} {1:bp}{2:>10d}', + 3, 4, 123, _hook=hookfunc) + self.formatRaises(ValueError, '{0:ap}') + self.formatEquals('_ap_', '{0:ap}', 3, _hook=hookfunc) + self.formatRaises(ValueError, '{0:ap}', 123, _hook=hookfunc) + + def test_alt_syntax(self): + self.formatEquals('{}1', '{!syntax1}{{}{0}', 1) + self.formatEquals('{ ${ 1 $1 $${0} ${', + '{!syntax2}{ $${ ${0} $$${0} $$$${0} $${', + 1) + self.formatEquals('1 {0} {\n0}', + '{!syntax3}{0} { 0} {\n0}', 1) + self.formatRaises(ValueError, '}') + self.formatRaises(ValueError, '{') + self.formatEquals('}', '{!syntax1}}') + self.formatRaises(ValueError, '{!syntax1}{') + self.formatEquals('}', '{!syntax2}}') + self.formatEquals('{', '{!syntax2}{') + self.formatRaises(ValueError, '{!syntax1}${') + self.formatEquals('${', '{!syntax2}$${') + self.formatEquals('}', '{!syntax3}}') + self.formatRaises(ValueError, '{!syntax3}{') + self.formatEquals('{', '{!syntax3}{ ') + + \ No newline at end of file Added: sandbox/trunk/pep3101/doctests/test.py ============================================================================== --- (empty file) +++ sandbox/trunk/pep3101/doctests/test.py Sat Mar 10 19:31:44 2007 @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +''' +I'm sure this is not-at-all the best way to test. I haven't kept up to date +on the testing methods du jour at all. + +OTOH, since the files containing the testcases are all text, I'm also sure +that it shouldn't be TOO hard to integrate them into the "right" test framework. +''' +import sys +import glob +sys.path.append('..') +import doctest +import loadpep + +files = sorted(glob.glob('*.txt')) +print "Testing", ', '.join(files) + +for f in files: + doctest.testfile(f, 0) Modified: sandbox/trunk/pep3101/loadpep.py ============================================================================== --- sandbox/trunk/pep3101/loadpep.py (original) +++ sandbox/trunk/pep3101/loadpep.py Sat Mar 10 19:31:44 2007 @@ -1,5 +1,6 @@ import sys +import os platdict = dict( linux2='build/lib.linux-i686-%s.%s', @@ -10,7 +11,9 @@ if platstr is None: raise ValueError("Unknown platform") -sys.path.append(platstr % sys.version_info[:2]) +platstr %= sys.version_info[:2] +moddir = os.path.dirname(__file__) +sys.path.append(os.path.join(moddir, platstr)) if __name__ == '__main__': import test_simpleformat Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Sat Mar 10 19:31:44 2007 @@ -127,7 +127,7 @@ /* current position and end of the 'self' string passed to FormatMethod */ SubString fmtstr; /* Used for error reporting */ - CH_TYPE *fmtstart, *fieldstart; + CH_TYPE *fieldstart; /* Output string we are constructing, including current and end pointers*/ SubString outstr; /* Field Specifier, after the colon in {1:{2}} @@ -162,6 +162,9 @@ on every single field, false to just call it on fields with a specifier ending in 'p' */ int hookalways; + /* err_info_reported is used to determine whether to report + a traceback object or not */ + int err_info_reported; } FmtState; /* Some forward declarations for recursion */ @@ -175,12 +178,49 @@ /************************** Utility functions ************************/ /************************************************************************/ +/* Fill in a SubString from a Python string */ +Py_LOCAL_INLINE(SubString) +make_substr(PyObject *obj) +{ + SubString s; + s.obj = obj; + s.ptr = STROBJ_AS_PTR(obj); + s.end = STROBJ_GET_SIZE(obj) + s.ptr; + return s; +} /************************************************************************/ /*********** Error handling and exception generation **************/ /************************************************************************/ /* + Get information about the current position in the string. +*/ +static int fmt_line_info(FmtState *fs, int * chpos) +{ + CH_TYPE *ptr, *end; + ptr = STROBJ_AS_PTR(fs->fmtstr.obj); + end = fs->fmtstr.ptr; + int cr, lf, ch; + for (cr=1, lf=1, ch=1; ptr < end; ptr++) { + switch (*ptr) { + case '\n': + lf += 1; + ch = 1; + break; + case '\r': + cr += 1; + ch = 1; + break; + default: + ch += 1; + break; + } + } + *chpos = ch; + return ((cr > lf) ? cr : lf); +} +/* Most of our errors are value errors, because to Python, the format string is a "value". Also, it's convenient to return a NULL when we are erroring out. @@ -190,10 +230,17 @@ { if (fs->fmtstr.ptr == fs->fmtstr.end) PyErr_Format(PyExc_ValueError, "%s at end of format_string", s); - else if ((fs->fmtstr.ptr >= fs->fmtstart) && - (fs->fmtstr.ptr < fs->fmtstr.end)) - PyErr_Format(PyExc_ValueError, "%s at format_string[%d]", - s, fs->fmtstr.ptr - fs->fmtstart); + else if ((fs->fmtstr.ptr >= STROBJ_AS_PTR(fs->fmtstr.obj)) && + (fs->fmtstr.ptr < fs->fmtstr.end)) { + int linenum, col; + linenum = fmt_line_info(fs, &col); + if (linenum <= 1) + PyErr_Format(PyExc_ValueError, "%s at format_string[%d]", + s, col-1); + else + PyErr_Format(PyExc_ValueError, "%s in format_string at line %d, column %d", + s, linenum, col); + } else PyErr_Format(PyExc_ValueError, "%s (apparently in computed format specifier)", s); @@ -418,17 +465,6 @@ /*********** Output string management functions ****************/ /************************************************************************/ -/* Fill in a SubString from a Python string */ -Py_LOCAL_INLINE(SubString) -make_substr(PyObject *obj) -{ - SubString s; - s.obj = obj; - s.ptr = STROBJ_AS_PTR(obj); - s.end = STROBJ_GET_SIZE(obj) + s.ptr; - return s; -} - /* output_extend reallocates the output string buffer. It returns a status: 0 for a failed reallocation, From python-checkins at python.org Sat Mar 10 19:51:11 2007 From: python-checkins at python.org (patrick.maupin) Date: Sat, 10 Mar 2007 19:51:11 +0100 (CET) Subject: [Python-checkins] r54264 - sandbox/trunk/pep3101/doctests/basic_examples.txt Message-ID: <20070310185111.5F52E1E4002@bag.python.org> Author: patrick.maupin Date: Sat Mar 10 19:51:06 2007 New Revision: 54264 Modified: sandbox/trunk/pep3101/doctests/basic_examples.txt Log: Added comment example Modified: sandbox/trunk/pep3101/doctests/basic_examples.txt ============================================================================== --- sandbox/trunk/pep3101/doctests/basic_examples.txt (original) +++ sandbox/trunk/pep3101/doctests/basic_examples.txt Sat Mar 10 19:51:06 2007 @@ -89,6 +89,20 @@ >>> print f("{z.c[5].b[1].a[3]}") 42 + + As any Python programmer knows, access to deeply embedded + attributes can create lengthy source lines. The best way + to keep format string source lines to a reasonable length + (while still allowing arbitrary-length output lines) is + to embed non-printing comments inside the format string. + +>>> print f("""The product of {z.c[5].b[1].a[7]} and {z.c[5].b[1].a[4]} {# +... This is a comment. It starts with {# and ends with the next }. +... As you can see, I have nested { and }, which only works if each +... nested { has a corresponding } somewhere after it in the comment. +... }is {z.c[5].b[1].a[3]}.""") +The product of 6 and 7 is 42. + Attributes and indices can even be retrieved from other variables. NB: Unless somebody has a really good use case, this capability is probably going away. It was added to try to satisfy Ian's From brett at python.org Sat Mar 10 21:39:42 2007 From: brett at python.org (Brett Cannon) Date: Sat, 10 Mar 2007 12:39:42 -0800 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 In-Reply-To: <20070310051059.C3F381E4002@bag.python.org> References: <20070310051059.C3F381E4002@bag.python.org> Message-ID: Another failure because a connection timed out. There was also a failure because the connection was reset. Would it be worth it to have a function in test_support just for network calls that suppresses both timed out connection exceptinos and connection resets by chaining calls to test.test_support.TransientResource() using contextlib.nested? -Brett` On 3/9/07, buildbot at python.org wrote: > The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. > Full details are available at: > http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/49 > > Buildbot URL: http://www.python.org/dev/buildbot/all/ > > Build Reason: > Build Source Stamp: [branch branches/release25-maint] HEAD > Blamelist: collin.winter > > Build had warnings: warnings test > > Excerpt from the test logfile: > 1 test failed: > test_urllibnet > > make: *** [buildbottest] Error 1 > > sincerely, > -The Buildbot > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > From python-checkins at python.org Sun Mar 11 00:00:52 2007 From: python-checkins at python.org (patrick.maupin) Date: Sun, 11 Mar 2007 00:00:52 +0100 (CET) Subject: [Python-checkins] r54266 - in sandbox/trunk/pep3101: doctests/basic_examples.txt pep_differences.txt test_simpleformat.py unicodeformat.c Message-ID: <20070310230052.08FC91E4002@bag.python.org> Author: patrick.maupin Date: Sun Mar 11 00:00:50 2007 New Revision: 54266 Modified: sandbox/trunk/pep3101/doctests/basic_examples.txt sandbox/trunk/pep3101/pep_differences.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Prettied up documentation, and modifed per-field hook character to match documentation Modified: sandbox/trunk/pep3101/doctests/basic_examples.txt ============================================================================== --- sandbox/trunk/pep3101/doctests/basic_examples.txt (original) +++ sandbox/trunk/pep3101/doctests/basic_examples.txt Sun Mar 11 00:00:50 2007 @@ -60,7 +60,7 @@ ... _dict=(dict(actor1=actor1), dict(whatever=3), dict(), dict(actor2=actor2))) {Fred}: My name is Fred. Are you George? - Attempt to use a non-existent argument causes an exception. + An attempt to use a non-existent argument will cause an exception. >>> print f("There is no {4} arg", 42, 24) Traceback (most recent call last): @@ -227,8 +227,8 @@ can explicitly request the hook function by placing a "p" (for python) in the field specifier type. ->>> print f("In fact, I'm sure {0:p} is {0}!", 42) -Hook received 42 p +>>> print f("In fact, I'm sure {0:h} is {0}!", 42) +Hook received 42 h In fact, I'm sure the answer is 42! The hook function could still decide to defer execution to the @@ -236,7 +236,7 @@ internal formatter doesn't know anything about the "p" type. XXX -- I don't like the error message here -- need to debug and fix. ->>> print f("{0:p} trombones led the big parade.", 66) +>>> print f("{0:h} trombones led the big parade.", 66) Traceback (most recent call last): ValueError: Invalid conversion character at end of format_string Modified: sandbox/trunk/pep3101/pep_differences.txt ============================================================================== --- sandbox/trunk/pep3101/pep_differences.txt (original) +++ sandbox/trunk/pep3101/pep_differences.txt Sun Mar 11 00:00:50 2007 @@ -16,7 +16,7 @@ This nice schedule has made at least one of the implementers bold enough to consider the first cut of the implementation "experimental" in the sense that, since there is time to correct any problems, the implementation can -diverge from the PEP (in documented ways!) both for perceived flaws in +diverge from the PEP (in well-documented ways!) both for perceived flaws in the PEP, and also to add minor enhancements. The code is being structured so that it should be easy to subsequently modify the operation to conform to consensus opinion. @@ -35,12 +35,12 @@ The PEP explicitly disclaims any attempt to replace string.Template, concentrating exclusively on the % operator. While this narrow focus -is very useful in removing things like conditionals and looping from -the discussion about the PEP, it ignores the reality that it might -be useful to REUSE some of the C implementation code (particularly -the per-field formatting) in templating systems. So the design of -the implementation adds the goal of being able to expose some lower- -level functions. +is very useful in removing things like compiling/caching and arbitrary +expressions from the discussion about the PEP, if the PEP is successful, +there is a good chance the syntax provided will become the "de facto" +syntax for Python string templates, so the design of the implementation +adds the goal of being able to expose the lower-level field formatting +functionality for subsequent reuse in compatible templating systems. Efficiency @@ -50,6 +50,10 @@ a fashion that an efficient implementation IS possible. Since the goal is to replace the % operator, it is particularly important that the formatting of small strings is not prohibitively expensive. +(The primary divergence between the PEP and the implementation +due to this goal is that the implementation, by default, does not +perform any sort of dictionary lookups other than those explicitly +requested by the format string.) Security @@ -57,7 +61,8 @@ Security is a stated goal of the PEP, with an apparent goal of being able to accept a string from J. Random User and format it without potential adverse consequences. This may or may not be an achievable -goal; the PEP certainly has some features that should help with this +goal (this author is by no means a security expert so cannot know); +the PEP certainly has some features that should help with this, such as the restricted number of operators, and the implemetation has some additional features, such as not allowing leading underscores on attributes by default, but these may be attempts to solve an @@ -76,7 +81,8 @@ Some of the implementers have very strong desires to use this formatting on older Python versions, and Guido has mentioned that any 3.0 features which do not break backward compatibility are potential candidates for -inclusion in 2.6. +inclusion in 2.6. This could almost certainly include additional string +and unicode methods. No global state @@ -88,9 +94,9 @@ One component might deliberately throw and catch exceptions in the string processing, and disabling this on a global basis might cause this component to stop working properly. If the ability to control this on a global -basis is desirable, it is easy enough to add in later, but if it is not -desirable, then deciding that after the fact and changing the code could -break code which has grown to rely on the feature. +basis is truly desirable, it is easy enough to add in later, but if it is +not desirable, then deciding that after the fact and removing the capability +from the method could break user code which has grown to rely on the feature. FORMATTING METADATA @@ -148,6 +154,10 @@ {#This is a comment} +Actually, one of the best uses for comments is not as comments, +per se, but as delimiters to be able to break up long source +lines in the format string (whitespace including newlines is +allowed inside comments). errors and exceptions @@ -155,7 +165,7 @@ implementation eschews the use of a global flag (see more information in the goals section, above), and splits out the various error features discussed by the PEP into different options. It also adds -an option. +an option for disallowing identifiers with leading underscores. The first error option is controlled by the optional _allow_leading_underscores keyword argument. If this is present and evaluates non-zero, then leading @@ -169,13 +179,16 @@ string can certainly be changed later; the reasons for doing it this way in the initial implementation are as follows: - 1) In the original % operator, the error reporting that an - extra argument is present is orthogonal to the error reporting + 1) In the original % operator, the exception reporting that an + extra argument is present is orthogonal to the exception reporting that not enough arguments are present. Both these errors are - easy to commit, because it is hard to count arguments and %s, - etc. In theory, the new string formatting should make it easier + easy to commit, because it is hard to count the number of arguments + and the number of % specifiers in your string and make sure they + match. In theory, the new string formatting should make it easier to get the arguments right, because all arguments in the format - string are numbered or even named. + string are numbered or even named, and with the new string + formatting, the corresponding error is that a _specific_ + argument is missing, not just "you didn't supply enough." 2) It is arguably not Pythonic to check that all arguments to a function are actually used by the execution of the function, @@ -188,13 +201,43 @@ view. 3) Assuming that the normal case is to not check all arguments, - it is much cheaper (especially for small strings) to notice - the {! and process the metadata in the strings that want it - than it is to look for a keyword argument for every string. - -XXX -- need to add info on displaying exceptions in string vs. passing -them up for looked-up errors. Also adding or not of string position -information. + it is computationally much cheaper (especially for small + strings) to notice the {! and process the metadata in the + strings that want it than it is to look for a keyword argument + for every string. + +The final error option concerns the ability to handle exceptions by +catching them and embedding the exception information in the resultant +output string rather than by passing them up to the caller. The original +PEP distinguishes between references to missing or invalid arguments, +and exceptions "raised by the underlying formatter." This is a difficult +distinction. An attribute lookup can cause any arbitrary Python machinery +to be invoked, so an exception could occur deep in the bowels of some +nested function. "Lenient" handling according to the PEP would report +this as a simple "TypeError" in the output string, rather than pass the +exception through to the calling function, which might be counterproductive +in debugging the problem. Conversely, a simple editing error in the +specifier portion of a string which produces an invalid specifier would +cause an exception "raised by the underlying formatter" and would always +be an exception passed back to the calling function, rather than displayed +to the user, even in "lenient" mode. + +The error handling proposed by one of the implementers (but not yet quite +implemented) is as follows: + + 1) Hard-to-recover-from errors (memory allocation and or errors where + it would be hard to know how to display useful information in the + string) will always raise exceptions up to the caller. + 2) Other error conditions are controlled by the _exception_display + keyword argument. The value of this argument should either be: + 0 - always raise exceptions up to caller + 1 - dump simple exception information in the string where + the field would have been displayed + 2 - dump more comprehensive exception information in the + string at exactly the location where the error was + noticed (e.g. display the portion of the format field + preceding the error, and also display traceback information, + if any. Getattr and getindex rely on underlying object exceptions @@ -250,7 +293,8 @@ Since we need a name mapper to look up items in the keywords dictionary, then in the passed-in dictionary, it is only a small feature creep to -allow _dict itself to be a tuple of dictionaries. +allow _dict itself to be a tuple of dictionaries. This is particularly +useful for passing both locals() and globals() in to the format function. Automatic locals/globals lookup @@ -265,6 +309,13 @@ assert x < 3, "x has the value of {x} (should be < 3)".format() +The argument against doing this is EIBTI, but if it is truly believed +that format() should not have automatic locals()/globals() lookup, then +for Python 3000 (where many features of the language are being perfected), +this feature should be reevaluated for eval() as well, because it seems +that the arguments for or against automatic locals()/globals() lookups for +eval and ''.format() are identical. + Syntax modes Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Sun Mar 11 00:00:50 2007 @@ -452,12 +452,12 @@ self.formatEquals('_a_ _4_ 123', '{!hook}{0:a} {1:b}{2:>10d}', 3, 4, 123, _hook=hookfunc) - self.formatEquals('_ap_ _4_ 123', - '{0:ap} {1:bp}{2:>10d}', + self.formatEquals('_ah_ _4_ 123', + '{0:ah} {1:bh}{2:>10d}', 3, 4, 123, _hook=hookfunc) - self.formatRaises(ValueError, '{0:ap}') - self.formatEquals('_ap_', '{0:ap}', 3, _hook=hookfunc) - self.formatRaises(ValueError, '{0:ap}', 123, _hook=hookfunc) + self.formatRaises(ValueError, '{0:ah}') + self.formatEquals('_ah_', '{0:ah}', 3, _hook=hookfunc) + self.formatRaises(ValueError, '{0:ah}', 123, _hook=hookfunc) def test_alt_syntax(self): self.formatEquals('{}1', '{!syntax1}{{}{0}', 1) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Sun Mar 11 00:00:50 2007 @@ -160,7 +160,7 @@ PyObject *hookfunc; /* hookalways is true if we should call the hook function on every single field, false to just call it on fields - with a specifier ending in 'p' */ + with a specifier ending in 'h' */ int hookalways; /* err_info_reported is used to determine whether to report a traceback object or not */ @@ -1933,7 +1933,7 @@ if (fs->hookalways || ((fs->fieldspec.ptr < fs->fieldspec.end) && - fs->fieldspec.end[-1] == 'p')) { + fs->fieldspec.end[-1] == 'h')) { result = hook_render(fs, fieldobj); if (result != 0) return result == 1; From python-checkins at python.org Sun Mar 11 01:07:49 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 11 Mar 2007 01:07:49 +0100 (CET) Subject: [Python-checkins] r54267 - sandbox/trunk/pep0/TODO sandbox/trunk/pep0/pep0.py Message-ID: <20070311000749.F0FAA1E4006@bag.python.org> Author: brett.cannon Date: Sun Mar 11 01:07:49 2007 New Revision: 54267 Modified: sandbox/trunk/pep0/TODO sandbox/trunk/pep0/pep0.py Log: Initial attempt at outputting a PEP's line. Modified: sandbox/trunk/pep0/TODO ============================================================================== --- sandbox/trunk/pep0/TODO (original) +++ sandbox/trunk/pep0/TODO Sun Mar 11 01:07:49 2007 @@ -1,4 +1,19 @@ In script: +* Author issues + + Missing an author + - 207 + - 208 + - 209 + - 218 + - 228 + - 234 + - 238 + - 246 + - 251 + - 263 + - 312 + - 314 + + How to handle suffixes (Jr., etc.)? * Read PEPs as UTF-8, not ASCII. * Output static text for PEP 0. + Store Owners list in a data structure. @@ -23,3 +38,5 @@ + Add a "Meta" option for "Type"? * Fix inconsistent usage of Status field. + Some PEPs just say "Standard"; missing "Track". +* Informational, meta, and process PEPs inconsistently have status listed in + index. Modified: sandbox/trunk/pep0/pep0.py ============================================================================== --- sandbox/trunk/pep0/pep0.py (original) +++ sandbox/trunk/pep0/pep0.py Sun Mar 11 01:07:49 2007 @@ -108,8 +108,35 @@ dead.append(pep) return meta, info, accepted, open_, finished, empty, dead +def write_pep(pep, output): + """Write PEP info to 'output'.""" + type_abbr = pep['Type'][0].upper() + status = pep['Status'] + if status == 'Draft' or type_abbr in ('I', 'P'): + status_abbr = ' ' + else: + status_abbr = status[0].upper() + number = str(pep['PEP']).rjust(4) + title = pep['Title'] + authors_list = [] + for author in pep['Author']: + name_parts = author.split() + last_name = name_parts.pop() + try: + last_name_leader = name_parts.pop() + except IndexError: + pass + else: + if last_name_leader[0].islower(): + last_name = '%s %s' % (last_name_leader, last_name) + authors_list.append(last_name) + authors = ', '.join(authors_list) + output.write(" %s%s %s %s %s\n" % + (type_abbr, status_abbr, number, title.ljust(44), authors)) + + if __name__ == '__main__': - from sys import argv + from sys import argv, stdout if not argv[1:]: directory = '.' @@ -117,9 +144,8 @@ directory = argv[1] peps = consume_headers(directory) - status = set() - type_ = set() + output = stdout for pep in peps: - status.add(pep['Status']) - type_.add(pep['Type']) - meta, info, accepted, open_, done, empty, dead = sort_peps(peps) + write_pep(pep, output) + + #meta, info, accepted, open_, done, empty, dead = sort_peps(peps) From martin at v.loewis.de Sun Mar 11 01:37:15 2007 From: martin at v.loewis.de (=?ISO-8859-1?Q?=22Martin_v=2E_L=F6wis=22?=) Date: Sun, 11 Mar 2007 01:37:15 +0100 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 In-Reply-To: References: <20070310051059.C3F381E4002@bag.python.org> Message-ID: <45F34F3B.2080808@v.loewis.de> Brett Cannon schrieb: > Another failure because a connection timed out. There was also a > failure because the connection was reset. > > Would it be worth it to have a function in test_support just for > network calls that suppresses both timed out connection exceptinos and > connection resets by chaining calls to > test.test_support.TransientResource() using contextlib.nested? It would certainly be valuable to filter out false positives. Newer buildbot versions apparently have support for filtering log files, but there are multiple obstacles to using them: - new versions of buildbot and twisted are needed, essentially making a switch only reasonable with the next Debian release (which should arrive soon) - the code to do the filtering and to compute build step results from that would have to be written So I think it is more reasonable to put this filtering into regrtest. If you are shy of turning it on globally, turning it on only under buildbot might be helpful - it should be easy to give regrtest an option "running under buildbot". Regards, Martin From brett at python.org Sun Mar 11 02:54:17 2007 From: brett at python.org (Brett Cannon) Date: Sat, 10 Mar 2007 17:54:17 -0800 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 In-Reply-To: <45F34F3B.2080808@v.loewis.de> References: <20070310051059.C3F381E4002@bag.python.org> <45F34F3B.2080808@v.loewis.de> Message-ID: On 3/10/07, "Martin v. L?wis" wrote: > Brett Cannon schrieb: > > Another failure because a connection timed out. There was also a > > failure because the connection was reset. > > > > Would it be worth it to have a function in test_support just for > > network calls that suppresses both timed out connection exceptinos and > > connection resets by chaining calls to > > test.test_support.TransientResource() using contextlib.nested? > > It would certainly be valuable to filter out false positives. > > Newer buildbot versions apparently have support for filtering > log files, but there are multiple obstacles to using them: > - new versions of buildbot and twisted are needed, essentially > making a switch only reasonable with the next Debian release > (which should arrive soon) > - the code to do the filtering and to compute build step results > from that would have to be written > > So I think it is more reasonable to put this filtering into regrtest. I was thinking of putting into the actual tests like I did with test_socket_ssl and its constant timeout issues. -Brett From martin at v.loewis.de Sun Mar 11 09:08:39 2007 From: martin at v.loewis.de (=?UTF-8?B?Ik1hcnRpbiB2LiBMw7Z3aXMi?=) Date: Sun, 11 Mar 2007 09:08:39 +0100 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 In-Reply-To: References: <20070310051059.C3F381E4002@bag.python.org> <45F34F3B.2080808@v.loewis.de> Message-ID: <45F3B907.9020407@v.loewis.de> Brett Cannon schrieb: - the code to do the filtering and to compute build step results >> from that would have to be written >> >> So I think it is more reasonable to put this filtering into regrtest. > > I was thinking of putting into the actual tests like I did with > test_socket_ssl and its constant timeout issues. Right, that's what I meant - filter it out in the actual test cases. Regards, Martin From python-checkins at python.org Sun Mar 11 09:28:47 2007 From: python-checkins at python.org (georg.brandl) Date: Sun, 11 Mar 2007 09:28:47 +0100 (CET) Subject: [Python-checkins] r54268 - python/trunk/Lib/pdb.py Message-ID: <20070311082847.334231E4004@bag.python.org> Author: georg.brandl Date: Sun Mar 11 09:28:46 2007 New Revision: 54268 Modified: python/trunk/Lib/pdb.py Log: Add missing "return" statements in exception handler. Modified: python/trunk/Lib/pdb.py ============================================================================== --- python/trunk/Lib/pdb.py (original) +++ python/trunk/Lib/pdb.py Sun Mar 11 09:28:46 2007 @@ -480,6 +480,7 @@ # something went wrong print >>self.stdout, \ 'Breakpoint index %r is not a number' % args[0] + return try: cond = args[1] except: @@ -500,6 +501,7 @@ # something went wrong print >>self.stdout, \ 'Breakpoint index %r is not a number' % args[0] + return try: count = int(args[1].strip()) except: From python-checkins at python.org Sun Mar 11 09:28:51 2007 From: python-checkins at python.org (georg.brandl) Date: Sun, 11 Mar 2007 09:28:51 +0100 (CET) Subject: [Python-checkins] r54269 - python/branches/release25-maint/Lib/pdb.py Message-ID: <20070311082851.3F3B91E4009@bag.python.org> Author: georg.brandl Date: Sun Mar 11 09:28:50 2007 New Revision: 54269 Modified: python/branches/release25-maint/Lib/pdb.py Log: Add missing "return" statements in exception handler. (backport from rev. 54268) Modified: python/branches/release25-maint/Lib/pdb.py ============================================================================== --- python/branches/release25-maint/Lib/pdb.py (original) +++ python/branches/release25-maint/Lib/pdb.py Sun Mar 11 09:28:50 2007 @@ -480,6 +480,7 @@ # something went wrong print >>self.stdout, \ 'Breakpoint index %r is not a number' % args[0] + return try: cond = args[1] except: @@ -500,6 +501,7 @@ # something went wrong print >>self.stdout, \ 'Breakpoint index %r is not a number' % args[0] + return try: count = int(args[1].strip()) except: From buildbot at python.org Sun Mar 11 10:21:01 2007 From: buildbot at python.org (buildbot at python.org) Date: Sun, 11 Mar 2007 09:21:01 +0000 Subject: [Python-checkins] buildbot warnings in ppc Debian unstable 2.5 Message-ID: <20070311092101.C2F7D1E4004@bag.python.org> The Buildbot has detected a new failure of ppc Debian unstable 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/ppc%2520Debian%2520unstable%25202.5/builds/61 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings failed slave lost sincerely, -The Buildbot From buildbot at python.org Sun Mar 11 10:21:02 2007 From: buildbot at python.org (buildbot at python.org) Date: Sun, 11 Mar 2007 09:21:02 +0000 Subject: [Python-checkins] buildbot warnings in PPC64 Debian 2.5 Message-ID: <20070311092103.184371E4009@bag.python.org> The Buildbot has detected a new failure of PPC64 Debian 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/PPC64%2520Debian%25202.5/builds/61 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings failed slave lost sincerely, -The Buildbot From python-checkins at python.org Sun Mar 11 16:54:59 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Sun, 11 Mar 2007 16:54:59 +0100 (CET) Subject: [Python-checkins] r54270 - in python/trunk: Misc/NEWS Objects/typeobject.c Message-ID: <20070311155459.BD89D1E4005@bag.python.org> Author: ziga.seilnacht Date: Sun Mar 11 16:54:54 2007 New Revision: 54270 Modified: python/trunk/Misc/NEWS python/trunk/Objects/typeobject.c Log: Patch #1675981: remove unreachable code from type.__new__() method. __dict__ and __weakref__ are removed from the slots tuple earlier in the code, in the loop that mangles slot names. Will backport. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sun Mar 11 16:54:54 2007 @@ -12,6 +12,8 @@ Core and builtins ----------------- +- Patch #1675981: remove unreachable code from ``type.__new__()`` method. + - Patch #1491866: change the complex() constructor to allow parthensized forms. This means complex(repr(x)) now works instead of raising a ValueError. Modified: python/trunk/Objects/typeobject.c ============================================================================== --- python/trunk/Objects/typeobject.c (original) +++ python/trunk/Objects/typeobject.c Sun Mar 11 16:54:54 2007 @@ -1997,13 +1997,11 @@ PyTuple_GET_ITEM(slots, i)); mp->type = T_OBJECT_EX; mp->offset = slotoffset; - if (base->tp_weaklistoffset == 0 && - strcmp(mp->name, "__weakref__") == 0) { - add_weak++; - mp->type = T_OBJECT; - mp->flags = READONLY; - type->tp_weaklistoffset = slotoffset; - } + + /* __dict__ and __weakref__ are already filtered out */ + assert(strcmp(mp->name, "__dict__") != 0); + assert(strcmp(mp->name, "__weakref__") != 0); + slotoffset += sizeof(PyObject *); } } From python-checkins at python.org Sun Mar 11 17:00:23 2007 From: python-checkins at python.org (collin.winter) Date: Sun, 11 Mar 2007 17:00:23 +0100 (CET) Subject: [Python-checkins] r54271 - in python/trunk: Lib/pdb.py Misc/NEWS Message-ID: <20070311160023.8AF691E4005@bag.python.org> Author: collin.winter Date: Sun Mar 11 17:00:20 2007 New Revision: 54271 Modified: python/trunk/Lib/pdb.py python/trunk/Misc/NEWS Log: Patch #1192590: Fix pdb's "ignore" and "condition" commands so they trap the IndexError caused by passing in an invalid breakpoint number. Will backport. Modified: python/trunk/Lib/pdb.py ============================================================================== --- python/trunk/Lib/pdb.py (original) +++ python/trunk/Lib/pdb.py Sun Mar 11 17:00:20 2007 @@ -485,7 +485,11 @@ cond = args[1] except: cond = None - bp = bdb.Breakpoint.bpbynumber[bpnum] + try: + bp = bdb.Breakpoint.bpbynumber[bpnum] + except IndexError: + print >>self.stdout, 'Breakpoint index %r is not valid' % args[0] + return if bp: bp.cond = cond if not cond: @@ -506,7 +510,11 @@ count = int(args[1].strip()) except: count = 0 - bp = bdb.Breakpoint.bpbynumber[bpnum] + try: + bp = bdb.Breakpoint.bpbynumber[bpnum] + except IndexError: + print >>self.stdout, 'Breakpoint index %r is not valid' % args[0] + return if bp: bp.ignore = count if count > 0: Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sun Mar 11 17:00:20 2007 @@ -158,6 +158,9 @@ Library ------- +- Patch #1192590: Fix pdb's "ignore" and "condition" commands so they trap + the IndexError caused by passing in an invalid breakpoint number. + - Patch #1599845: Add an option to disable the implicit calls to server_bind() and server_activate() in the constructors for TCPServer, SimpleXMLRPCServer and DocXMLRPCServer. From python-checkins at python.org Sun Mar 11 17:01:54 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Sun, 11 Mar 2007 17:01:54 +0100 (CET) Subject: [Python-checkins] r54272 - in python/branches/release25-maint: Misc/NEWS Objects/typeobject.c Message-ID: <20070311160154.3F3821E4005@bag.python.org> Author: ziga.seilnacht Date: Sun Mar 11 17:01:51 2007 New Revision: 54272 Modified: python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Objects/typeobject.c Log: Patch #1675981: remove unreachable code from type.__new__() method. __dict__ and __weakref__ are removed from the slots tuple earlier in the code, in the loop that mangles slot names. (backport from rev. 54270) Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sun Mar 11 17:01:51 2007 @@ -12,6 +12,8 @@ Core and builtins ----------------- +- Patch #1675981: remove unreachable code from ``type.__new__()`` method. + - Patch #1638879: don't accept strings with embedded NUL bytes in long(). - Bug #1674503: close the file opened by execfile() in an error condition. Modified: python/branches/release25-maint/Objects/typeobject.c ============================================================================== --- python/branches/release25-maint/Objects/typeobject.c (original) +++ python/branches/release25-maint/Objects/typeobject.c Sun Mar 11 17:01:51 2007 @@ -1935,13 +1935,11 @@ PyTuple_GET_ITEM(slots, i)); mp->type = T_OBJECT_EX; mp->offset = slotoffset; - if (base->tp_weaklistoffset == 0 && - strcmp(mp->name, "__weakref__") == 0) { - add_weak++; - mp->type = T_OBJECT; - mp->flags = READONLY; - type->tp_weaklistoffset = slotoffset; - } + + /* __dict__ and __weakref__ are already filtered out */ + assert(strcmp(mp->name, "__dict__") != 0); + assert(strcmp(mp->name, "__weakref__") != 0); + slotoffset += sizeof(PyObject *); } } From python-checkins at python.org Sun Mar 11 17:04:06 2007 From: python-checkins at python.org (collin.winter) Date: Sun, 11 Mar 2007 17:04:06 +0100 (CET) Subject: [Python-checkins] r54273 - in python/branches/release25-maint: Lib/pdb.py Misc/NEWS Message-ID: <20070311160406.338291E4005@bag.python.org> Author: collin.winter Date: Sun Mar 11 17:04:01 2007 New Revision: 54273 Modified: python/branches/release25-maint/Lib/pdb.py python/branches/release25-maint/Misc/NEWS Log: Patch #1192590: Fix pdb's "ignore" and "condition" commands so they trap the IndexError caused by passing in an invalid breakpoint number. Backport of r54271. Modified: python/branches/release25-maint/Lib/pdb.py ============================================================================== --- python/branches/release25-maint/Lib/pdb.py (original) +++ python/branches/release25-maint/Lib/pdb.py Sun Mar 11 17:04:01 2007 @@ -485,7 +485,11 @@ cond = args[1] except: cond = None - bp = bdb.Breakpoint.bpbynumber[bpnum] + try: + bp = bdb.Breakpoint.bpbynumber[bpnum] + except IndexError: + print >>self.stdout, 'Breakpoint index %r is not valid' % args[0] + return if bp: bp.cond = cond if not cond: @@ -506,7 +510,11 @@ count = int(args[1].strip()) except: count = 0 - bp = bdb.Breakpoint.bpbynumber[bpnum] + try: + bp = bdb.Breakpoint.bpbynumber[bpnum] + except IndexError: + print >>self.stdout, 'Breakpoint index %r is not valid' % args[0] + return if bp: bp.ignore = count if count > 0: Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sun Mar 11 17:04:01 2007 @@ -199,6 +199,9 @@ Library ------- +- Patch #1192590: Fix pdb's "ignore" and "condition" commands so they trap + the IndexError caused by passing in an invalid breakpoint number. + - Bug #1531963: Make SocketServer.TCPServer's server_address always be equal to calling getsockname() on the server's socket. Fixed by patch #1545011. From buildbot at python.org Sun Mar 11 19:20:36 2007 From: buildbot at python.org (buildbot at python.org) Date: Sun, 11 Mar 2007 18:20:36 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 Message-ID: <20070311182037.D344A1E4005@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/53 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: collin.winter,ziga.seilnacht Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Sun Mar 11 19:32:14 2007 From: python-checkins at python.org (vinay.sajip) Date: Sun, 11 Mar 2007 19:32:14 +0100 (CET) Subject: [Python-checkins] r54274 - python/trunk/Lib/test/test_logging.py Message-ID: <20070311183214.5CA771E402C@bag.python.org> Author: vinay.sajip Date: Sun Mar 11 19:32:07 2007 New Revision: 54274 Modified: python/trunk/Lib/test/test_logging.py Log: Fix resource leak reported in SF #1516995. Modified: python/trunk/Lib/test/test_logging.py ============================================================================== --- python/trunk/Lib/test/test_logging.py (original) +++ python/trunk/Lib/test/test_logging.py Sun Mar 11 19:32:07 2007 @@ -555,6 +555,8 @@ except KeyError: logging.exception("just testing") os.remove(fn) + hdlr = logging.getLogger().handlers[0] + logging.getLogger().handlers.remove(hdlr) finally: logging._acquireLock() try: From python-checkins at python.org Sun Mar 11 19:37:22 2007 From: python-checkins at python.org (vinay.sajip) Date: Sun, 11 Mar 2007 19:37:22 +0100 (CET) Subject: [Python-checkins] r54275 - python/branches/release25-maint/Lib/test/test_logging.py Message-ID: <20070311183722.A671F1E400B@bag.python.org> Author: vinay.sajip Date: Sun Mar 11 19:37:20 2007 New Revision: 54275 Modified: python/branches/release25-maint/Lib/test/test_logging.py Log: Fix resource leak reported in SF #1516995. Modified: python/branches/release25-maint/Lib/test/test_logging.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_logging.py (original) +++ python/branches/release25-maint/Lib/test/test_logging.py Sun Mar 11 19:37:20 2007 @@ -555,6 +555,8 @@ except KeyError: logging.exception("just testing") os.remove(fn) + hdlr = logging.getLogger().handlers[0] + logging.getLogger().handlers.remove(hdlr) finally: logging._acquireLock() try: From brett at python.org Sun Mar 11 19:46:42 2007 From: brett at python.org (Brett Cannon) Date: Sun, 11 Mar 2007 10:46:42 -0800 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 In-Reply-To: <45F3B907.9020407@v.loewis.de> References: <20070310051059.C3F381E4002@bag.python.org> <45F34F3B.2080808@v.loewis.de> <45F3B907.9020407@v.loewis.de> Message-ID: On 3/11/07, "Martin v. L?wis" wrote: > Brett Cannon schrieb: > - the code to do the filtering and to compute build step results > >> from that would have to be written > >> > >> So I think it is more reasonable to put this filtering into regrtest. > > > > I was thinking of putting into the actual tests like I did with > > test_socket_ssl and its constant timeout issues. > > Right, that's what I meant - filter it out in the actual test cases. > My question still stands, though: would it be helpful to have a context manager that catches socket timeout and connection resets and raises ResourceDenied in those situations and then wrap the various network calls in the test suite with the manager? -Brett From buildbot at python.org Sun Mar 11 20:38:48 2007 From: buildbot at python.org (buildbot at python.org) Date: Sun, 11 Mar 2007 19:38:48 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 2.5 Message-ID: <20070311193848.7A1CB1E4005@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%25202.5/builds/204 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: vinay.sajip Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket sincerely, -The Buildbot From python-checkins at python.org Sun Mar 11 22:35:02 2007 From: python-checkins at python.org (patrick.maupin) Date: Sun, 11 Mar 2007 22:35:02 +0100 (CET) Subject: [Python-checkins] r54276 - sandbox/trunk/pep3101/proposed-pep-changes.txt Message-ID: <20070311213502.6F72D1E4005@bag.python.org> Author: patrick.maupin Date: Sun Mar 11 22:34:54 2007 New Revision: 54276 Added: sandbox/trunk/pep3101/proposed-pep-changes.txt - copied, changed from r54275, peps/trunk/pep-3101.txt Log: Initial version of proposed-pep-changes.txt file Copied: sandbox/trunk/pep3101/proposed-pep-changes.txt (from r54275, peps/trunk/pep-3101.txt) ============================================================================== --- peps/trunk/pep-3101.txt (original) +++ sandbox/trunk/pep3101/proposed-pep-changes.txt Sun Mar 11 22:34:54 2007 @@ -15,7 +15,10 @@ This PEP proposes a new system for built-in string formatting operations, intended as a replacement for the existing '%' string - formatting operator. + formatting operator. The C engine which supports this proposal may + also be accessible from the string module to allow for additional + formatting options, and may be compilable as a compatible separate + extension module for use with older versions of Python. Rationale @@ -26,10 +29,10 @@ - The string.Template module. [2] - The scope of this PEP will be restricted to proposals for built-in + The primary scope of this PEP concerns proposals for built-in string formatting operations (in other words, methods of the built-in string type). - + The '%' operator is primarily limited by the fact that it is a binary operator, and therefore can take at most two arguments. One of those arguments is already dedicated to the format string, @@ -42,9 +45,14 @@ While there is some overlap between this proposal and string.Template, it is felt that each serves a distinct need, - and that one does not obviate the other. In any case, - string.Template will not be discussed here. - + and that one does not obviate the other. This proposal is for + a mechanism which, like '%', is efficient for small strings + which are only used once, so, for example, compilation of a + string into a template is not contemplated in this proposal, + although the proposal does take care to define format strings + and the API in such a way that an efficient template package + could reuse the syntax and even some of the underlying + formatting code. Specification @@ -53,6 +61,13 @@ - Specification of a new formatting method to be added to the built-in string class. + - Specification of functions and flag values to be added to + the string module, so that the underlying formatting engine + can be used with additional options. + + - Specification of the module name to be used for backporting + to earlier version of Python than 2.6. + - Specification of a new syntax for format strings. - Specification of a new set of class methods to control the @@ -61,31 +76,31 @@ - Specification of an API for user-defined formatting classes. - Specification of how formatting errors are handled. - - Note on string encodings: Since this PEP is being targeted - at Python 3.0, it is assumed that all strings are unicode strings, + + Note on string encodings: When discussing this PEP in the context + of Python 3.0, it is assumed that all strings are unicode strings, and that the use of the word 'string' in the context of this document will generally refer to a Python 3.0 string, which is the same as Python 2.x unicode object. - - If it should happen that this functionality is backported to - the 2.x series, then it will be necessary to handle both regular - string as well as unicode objects. All of the function call + + In the context of Python 2.x, the use of the word 'string' in the + context of this document refers to an object which may either be + a regular string or a unicode object. All of the function call interfaces described in this PEP can be used for both strings and unicode objects, and in all cases there is sufficient information to be able to properly deduce the output string type (in other words, there is no need for two separate APIs). - In all cases, the type of the template string dominates - that + In all cases, the type of the format string dominates - that is, the result of the conversion will always result in an object that contains the same representation of characters as the - input template string. + input format string. -String Methods +String Methods (Python 2.6 and above) - The build-in string class will gain a new method, 'format', - which takes takes an arbitrary number of positional and keyword - arguments: + The built-in string class (and also the unicode class in 2.6) will + gain a new method, 'format', which takes an arbitrary number of + positional and keyword arguments: "The story of {0}, {1}, and {c}".format(a, b, c=d) @@ -95,30 +110,215 @@ identified by its keyword name, so in the above example, 'c' is used to refer to the third argument. + Two keyword argument names are reserved for use by the format + method: + + The namespace argument, if present, should be bound to a + dictionary or tuple of dictionaries, which will be searched + whenevar a keyword argument is not found in the **kwargs + passed to format(). + + The field_hook argument, if present, defines a "hook" callback + function which allows greater user control over the formatting + operation. + + Automatic namespace generation: + + If format() is called with no parameters, a namespace will + automatically be generated which contains the caller's locals() + and globals(). + +string module additions (Python 2.6 and above) + + The string module will have two new functions: + + format(format_string, *args, **kwargs) + + The format function is identical in operation to the + string/unicode format method. In other words, the + output from: + + str.format(some_string, *args, **kwargs) + + and: + + string.format(some_string, *args, **kwargs) + + will be indentical. + + flag_format(flags, format_string, *args, **kwargs) + + The flag_format function adds an integer flags + argument in front of the parameters which are + passed to the format method. If this flags parameter + is 0, the results of calling flags_format will be + identical to the results of calling format with the + same string and *args and **kwargs. Setting bits + in the flags parameter allows finer control over + the formatter operation. + + The string module will have some new variables which are bound + to integer constants. These define options which can be passed + to flag_format in the flags parameter. Most options can be combined + by using the bitwise or (|) operator. + + FORMAT_SYNTAX_BRACES_BALANCED + FORMAT_SYNTAX_BRACES_UNBALANCED + FORMAT_SYNTAX_DOLLAR + FORMAT_SYNTAX_BRACES_WHITESPACE + FORMAT_SYNTAX_SINGLE_FIELD + + These define the initial syntax mode of the string. At most + one of these can be ORed into the flags parameter. The default + is FORMAT_SYNTAX_BRACES_BALANCED. The syntax modes are discussed + later in this PEP. + + FORMAT_HOOK_ALWAYS + + By default, the hook function is only called on fields with a + type specifier of 'h'. If this option is set, the hook function + will be called on every single field. (It can defer processing + to the internal field formatter by returning None instead of + a result string.) + + FORMAT_ALLOW_LEADING_UNDERSCORES + + By default, leading underscores are not allowed in identifier + lookups (getattr or setattr). Setting this flag will allow this. + + FORMAT_USE_ALL_ARGUMENTS + + By default, the formatting engine does not check that all + arguments passed to it are used by the format string. If + this flag is set, an exception will be thrown if some + arguments are unused. + +Backporting to earlier versions of Python + + An extension module will be maintained which is usable + with at least Python 2.3, 2.4, and 2.5. The name of this + extension module will be "string_format", and it will contain + exactly the same functions and flag identifiers as are being + added to the string module in 2.6 and 3.0. This will allow + new code which requires this functionality to import it as + follows: + + try: + from string import format + except ImportError: + from string_format import format Format Strings - Brace characters ('curly braces') are used to indicate a - replacement field within the string: + Format strings consist of intermingled character data and markup. + + Character data is data which is transferred unchanged from the + format string to the output string; markup is not transferred from + the format string directly to the output, but instead consists of + control information which describes to the format engine what should + be placed in the output string in the place of the markup. + + The transition from character data to markup and back is controlled + by the syntax mode currently in effect. + + The only markup currently defined in this PEP is the markup for + a replacement field, and the markup for a syntax mode change. + +Syntax Modes + + The parsing of the transition from character data to markup is + simple enough that the parser can easily handle a few different + syntax modes with very little loss of efficiency, so this proposal + provides for a few different syntax modes. The rationale for + modes chosen or not is provided later in the "Alternate syntax" + section of this PEP. + + The following syntax modes are supported: + + Mode 0 uses an open brace to transition from character data + to markup, and a close brace to transition back to character + data. Literal braces (which should appear in the output + text unchanged) are created by placing two open braces or + two close braces in the text. The constant for this mode + in the string module is FORMAT_SYNTAX_BRACES_BALANCED. + + Mode 1 is identical to mode 0, but only requires literal + open braces to be escaped, not literal close braces. The + constant for this mode in the string module is + FORMAT_SYNTAX_BRACES_UNBALANCED. + + Mode 2 is similar to the default escaping in the PEP 292 + string.Template object. Transitions from character data to + markup are normally accomplished via "${" and transitions + back by "}", but if the markup consists of a field name with + no conversion specifier, and the character data immediately + following the field name is a space or newline, then the + transition to markup may be specified by "$" (without the + open brace), and the transition back to character data will + happen implicitly on the whitespace. Literal dollar + signs are created by doubling them ($$). The constant for + this mode in the string module is FORMAT_SYNTAX_BRACES_DOLLAR. + + Mode 3, like modes 0 and 1, uses braces to transition from + character data to markup. Literal closing braces are not + escaped (this is like mode 1), and literal opening braces + are escaped by placing whitespace ('\r', '\n', or ' ') + immediately after the brace in the format string. If the + whitespace is a literal space, the brace will be transferred + to the output string, but the space will not. If the whitespace + is a carriage return or linefeed, it will be transferred intact, + along with the brace. The constant for this mode in the string + module is FORMAT_SYNTAX_BRACES_WHITESPACE. + +Syntax mode transitions - "My name is {0}".format('Fred') + The default syntax mode is mode 0. The mode can be changed in the + format string by using a markup string (delimited by the syntax + mode currently in use) which consists of a leading "@" character, + plus the letters "syntax" and the number "0" through "3". + When the syntax mode is changed, a trailing newline (after the + transition back to character data) will be considered to be part + of the markup rather than part of the character data. For example, + in the string: - The result of this is the string: + '''{@syntax1} + Now I can have } without having to double them. + ''' - "My name is Fred" + the first non-markup character will be the 'N'. - Braces can be escaped by doubling: + The default mode can also be set in the flags parameter when using + the flag_format() function. - "My name is {0} :-{{}}".format('Fred') +Syntax examples - Which would produce: + Throughout this document, unless otherwise stated, all syntax + examples are for syntax mode 0. Here are some basic examples + of mode 0 syntax: - "My name is Fred :-{}" - - The element within the braces is called a 'field'. Fields consist + Brace characters ('curly braces') are used to indicate a + replacement field within the string: + + "My name is {0}".format('Fred') + + The result of this is the string: + + "My name is Fred" + + Braces can be escaped by doubling: + + "My name is {0} :-{{}}".format('Fred') + + Which would produce: + + "My name is Fred :-{}" + +Replacement fields + + The usual markup element (e.g. inside the braces in syntax mode 0) + is called a 'replacement field', or field for short. Fields consist of a 'field name', which can either be simple or compound, and an optional 'conversion specifier'. - Simple and Compound Field Names @@ -126,12 +326,12 @@ must be valid base-10 integers; if names, they must be valid Python identifiers. A number is used to identify a positional argument, while a name is used to identify a keyword argument. - + A compound field name is a combination of multiple simple field names in an expression: "My name is {0.name}".format(file('out.txt')) - + This example shows the use of the 'getattr' or 'dot' operator in a field expression. The dot operator allows an attribute of an input value to be specified as the field value. @@ -142,22 +342,30 @@ Python expressions inside of strings. Only two operators are supported, the '.' (getattr) operator, and the '[]' (getitem) operator. - + An example of the 'getitem' syntax: - + "My name is {0[name]}".format(dict(name='Fred')) - + It should be noted that the use of 'getitem' within a string is much more limited than its normal use. In the above example, the string 'name' really is the literal string 'name', not a variable - named 'name'. The rules for parsing an item key are the same as - for parsing a simple name - in other words, if it looks like a - number, then its treated as a number, if it looks like an - identifier, then it is used as a string. - + named 'name'. The rules for parsing an item key are very simple. + If it starts with a digit, then its treated as a number, otherwise + it is used as a string. + It is not possible to specify arbitrary dictionary keys from within a format string. + Implementation note: The implementation of this proposal is + not required to enforce the rule about a name being a valid + Python identifier. Instead, it will rely on the getattr function + of the underlying object to throw an exception if the identifier + is not legal. The format function will have a minimalist parser + which only attempts to figure out when it is "done" with an + identifier (by finding a '.' or a ']', or '}', etc.) The only + exception to this laissez-faire approach is that, by default, + strings are not allowed to have leading underscores. Conversion Specifiers @@ -176,14 +384,18 @@ Conversion specifiers can themselves contain replacement fields. For example, a field whose field width is itself a parameter could be specified via: - + "{0:{1}}".format(a, b, c) - + Note that the doubled '}' at the end, which would normally be escaped, is not escaped in this case. The reason is because the '{{' and '}}' syntax for escapes is only applied when used *outside* of a format field. Within a format field, the brace - characters always have their normal meaning. + characters always have their normal meaning. Also, within + a format field, the markup syntax is always syntax 0, so, for + example, the equivalent code for syntax 2 would be: + + "${0:{1}}".format(a, b, c) The syntax for conversion specifiers is open-ended, since a class can override the standard conversion specifiers. In such cases, @@ -201,13 +413,13 @@ differences. The standard conversion specifiers fall into three major categories: string conversions, integer conversions and floating point conversions. - + The general form of a standard conversion specifier is: [[fill]align][sign][width][.precision][type] The brackets ([]) indicate an optional element. - + Then the optional align flag can be one of the following: '<' - Forces the field to be left-aligned within the available @@ -217,18 +429,18 @@ '=' - Forces the padding to be placed after the sign (if any) but before the digits. This is used for printing fields in the form '+000000120'. - + Note that unless a minimum field width is defined, the field width will always be the same size as the data to fill it, so that the alignment option has no meaning in this case. - + The optional 'fill' character defines the character to be used to pad the field to the minimum width. The alignment flag must be supplied if the character is a number other than 0 (otherwise the character would be interpreted as part of the field width specifier). A zero fill character without an alignment flag implies an alignment type of '='. - + The 'sign' element can be one of the following: '+' - indicates that a sign should be used for both @@ -249,7 +461,7 @@ conversion. In a string conversion the field indicates how many characters will be used from the field content. The precision is ignored for integer conversions. - + Finally, the 'type' determines how the data should be presented. If the type field is absent, an appropriate type will be assigned based on the value to be formatted ('d' for integers and longs, @@ -299,6 +511,11 @@ '%' - Percentage. Multiplies the number by 100 and displays in fixed ('f') format, followed by a percent sign. + If the conversion type (the last character of the conversion + specifier) is 'h', the remainder of the conversion specifier + is not examined, and the object and specifier are passed to + the 'field_hook' argument to the format function for processing. + Objects are able to define their own conversion specifiers to replace the standard ones. An example is the 'datetime' class, whose conversion specifiers might look something like the @@ -307,7 +524,7 @@ "Today is: {0:a b d H:M:S Y}".format(datetime.now()) -Controlling Formatting +Controlling Formatting on a per-class basis A class that wishes to implement a custom interpretation of its conversion specifiers can implement a __format__ method: @@ -334,67 +551,65 @@ 3) Otherwise, call str() or unicode() as appropriate. +Controlling Formatting on a per-field basis + + If the built-in formatting is not sufficient for a particular + field, then a 'field_hook' can be passed to the formatter. + This hook function has the same call signature as the + class __format__ method described above; that is, it takes + an object and a format specifier string, and returns a result + string which format() will insert in the output string it + is building at the appropriate spot: + + field_output_string = field_hook(fieldobj, formatspec) + + Note that, in this case, the last character of formatspec + will always be 'h'. + User-Defined Formatting Classes There will be times when customizing the formatting of fields - on a per-type basis is not enough. An example might be an - accounting application, which displays negative numbers in + on a per-type or per-field basis is not enough. An example might + be an accounting application, which displays negative numbers in parentheses rather than using a negative sign. - + The string formatting system facilitates this kind of application- specific formatting by allowing user code to directly invoke the code that interprets format strings and fields. User-written code can intercept the normal formatting operations on a per-field basis, substituting their own formatting methods. - + For example, in the aforementioned accounting application, there could be an application-specific number formatter, which reuses the string.format templating code to do most of the work. The API for such an application-specific formatter is up to the application; here are several possible examples: - + cell_format("The total is: {0}", total) - + TemplateString("The total is: {0}").format(total) - + Creating an application-specific formatter is relatively straight- - forward. The string and unicode classes will have a class method - called 'cformat' that does all the actual work of formatting; The - built-in format() method is just a wrapper that calls cformat. - - The type signature for the cFormat function is as follows: - - cformat(template, format_hook, args, kwargs) - - The parameters to the cformat function are: - - -- The format template string. - -- A callable 'format hook', which is called once per field - -- A tuple containing the positional arguments - -- A dict containing the keyword arguments - - The cformat function will parse all of the fields in the format - string, and return a new string (or unicode) with all of the - fields replaced with their formatted values. - - The format hook is a callable object supplied by the user, which - is invoked once per field, and which can override the normal - formatting for that field. For each field, the cformat function - will attempt to call the field format hook with the following - arguments: + forward. The flag_format() function in the string module has + a flag that can be set to indicate that the 'field_hook' function + should be called on every single field, rather than just on + fields which have a specifier type of 'h'. In this case, the + field_hook function has the option of returning None rather than + a string, to indicate that it wants the internal formatter to + format the field. The hook function is called as follows: - format_hook(value, conversion) + result = field_hook(fieldobj, fieldspec) - The 'value' field corresponds to the value being formatted, which + The 'fieldobj' field corresponds to the value being formatted, which was retrieved from the arguments using the field name. - The 'conversion' argument is the conversion spec part of the + The 'fieldspec' argument is the conversion spec part of the field, which will be either a string or unicode object, depending on the type of the original format string. The field_hook will be called once per field. The field_hook may take one of two actions: - + 1) Return a string or unicode object that is the result of the formatting operation. @@ -403,38 +618,42 @@ used. This decision should be based on the type of the value object, and the contents of the conversion string. + The hook function can even call back into the flag_format() function + for help in formatting a field. In this case, it can use the + FORMAT_SYNTAX_SINGLE_FIELD option to pass in a conversion specifier + and the object to be formatted. This will bypass the machinery which + transitions between character data and markup, and the machinery which + parses the field name, and will call the internal field formatter on + the single object. + Error handling - The string formatting system has two error handling modes, which - are controlled by the value of a class variable: - - string.strict_format_errors = True - - The 'strict_format_errors' flag defaults to False, or 'lenient' - mode. Setting it to True enables 'strict' mode. The current mode - determines how errors are handled, depending on the type of the - error. - - The types of errors that can occur are: - - 1) Reference to a missing or invalid argument from within a - field specifier. In strict mode, this will raise an exception. - In lenient mode, this will cause the value of the field to be - replaced with the string '?name?', where 'name' will be the - type of error (KeyError, IndexError, or AttributeError). - - So for example: - - >>> string.strict_format_errors = False - >>> print 'Item 2 of argument 0 is: {0[2]}'.format( [0,1] ) - "Item 2 of argument 0 is: ?IndexError?" - - 2) Unused argument. In strict mode, this will raise an exception. - In lenient mode, this will be ignored. - - 3) Exception raised by underlying formatter. These exceptions - are always passed through, regardless of the current mode. + There are two classes of exceptions which can occur during formatting: + exceptions generated by the formatter code itself, and exceptions + generated by user code (such as a field object's getattr function, or + the field_hook function). + + In general, exceptions generated by the formatter code itself are + of the "ValueError" variety -- there is an error in the actual "value" + of the format string. (This is not always true; for example, the + string.format() function might be passed a non-string as its first + parameter, which would result in a TypeError.) + + The text associated with these internally generated ValueError + exceptions will indicate the location of the exception inside + the format string, as well as the nature of the exception. + + For exceptions generated by user code, a trace record and + dummy frame will be added to the traceback stack to help + in determining the location in the string where the exception + occurred. The inserted traceback will indicate that the + error occurred at: + + File "", line XX, in column_YY + + where XX and YY represent the line and character position + information in the string, respectively. Alternate Syntax @@ -483,9 +702,9 @@ - Other variations include Ruby's #{}, PHP's {$name}, and so on. - + Some specific aspects of the syntax warrant additional comments: - + 1) Backslash character for escapes. The original version of this PEP used backslash rather than doubling to escape a bracket. This worked because backslashes in Python string literals that @@ -494,18 +713,94 @@ of confusion, and led to potential situations of multiple recursive escapes, i.e. '\\\\{' to place a literal backslash in front of a bracket. - + 2) The use of the colon character (':') as a separator for conversion specifiers. This was chosen simply because that's what .Net uses. - + + The inclusion of multiple syntaxes into the proposal: + + This proposal has a few different syntax methods, one of + which might be expected to work reasonably well with most + user's applications. It might be unwieldy (and require + inefficient code) to support too many different markup + syntaxes, but the currently supported ones are similar enough + (and the set small enough) to be parsed by the same C loop + quite easily. It may seem that the choice of syntax comes down + to personal taste (and there is undoubtedly a lot of that), but + different problem domains arguably lend themselves to different + syntaxes. + + The "personal preference" argument is also quite powerful. + Some individuals have a hard time distinguishing "{" and "}" + characters (which are very lightweight in some fonts, almost + indistinguishable from "(" and ")") and prefer the visual + impact of seeing "$" in front of markup, while other individuals + have a very visceral negative reaction to the "$". + + One thing that seems certain is that, if different syntaxes are + to be supported, it is desirable that the format string itself + have a mechanism by which it can announce which syntax it is + using, so that automated tools can be used to analyze format + strings, and so that the syntax conforms to the needs of the + author of the format string, rather than the author of the + Python code. + + The default syntax, as we have seen, uses {} to delineate markup + from normal text. + + It was pointed out that XML, for instance, requires a literal + < to be escaped, but not a literal >. Obviously, for some sorts of + text, it will be useful to see {{ balance }}, but for other sorts + of texts, the braces aren't matched, and it is cumbersome to escape + the closing brace, so syntax 1 doesn't require this. + + In some text with a lot of braces, but few markup substitutions, + it might be difficult to visually find the markup inside the text. + Syntax 2 handles these situations handily by requiring a more + traditional ${} or $identifier approach to markup. + + This brings us to the last syntax supported by the sandbox + implementation. Syntax 3 would send any non-Python programmer + running, because it depends on significant whitespace. It works + great for things like C templates where most left braces are + followed by a newline. + +Argument name collisions + + The 'namespace' and 'field_hook' arguments to format share the + same namespace as the user's field names. There is nothing + which keeps a format string which does not require the namespace + or field_hook from reusing these names for its own variables. + + For clarity, use of names with leading underscores, like + _namespace and _field_hook, was considered and rejected, because + the number of people who want to format variables named "field_hook" + and "namespace" is probably vanishingly small compared to the number + of people who actually want to use the namespace and field_hook of + the format function. + +Automatic inclusion of locals() and globals() + + If no parameters are passed to the format() method, it will + automatically user the caller's locals() and globals(). + It is a tough call as to whether this should be done or not; + on the one hand it is awfully convenient, but on the other + hand it may be considered to violate the EIBTI principle. If + it is decided to remove this capability, however, then the + similar functionality of eval() should be reconsidered for + Python 3000, because the arguments for and against the + capability appear to be identical in both cases. Sample Implementation - A rough prototype of the underlying 'cformat' function has been - coded in Python, however it needs much refinement before being - submitted. - + Talin generated a rough Python prototype of some of the functionality + described in this PEP, and Patrick Maupin and Eric Smith generated + a functional C version. There are a few discrepancies between + the C and this proposal, but the learning experience of writing the + C has helped to hone the proposal, so it is expected that it will not + be too much work to bring the C code in line with the final version + of this PEP. Backwards Compatibility From buildbot at python.org Sun Mar 11 22:35:48 2007 From: buildbot at python.org (buildbot at python.org) Date: Sun, 11 Mar 2007 21:35:48 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070311213548.92F011E4005@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/108 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: vinay.sajip Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Mon Mar 12 01:18:27 2007 From: python-checkins at python.org (patrick.maupin) Date: Mon, 12 Mar 2007 01:18:27 +0100 (CET) Subject: [Python-checkins] r54277 - sandbox/trunk/pep3101/proposed-pep-changes.txt Message-ID: <20070312001827.DD49F1E4005@bag.python.org> Author: patrick.maupin Date: Mon Mar 12 01:18:26 2007 New Revision: 54277 Modified: sandbox/trunk/pep3101/proposed-pep-changes.txt Log: Corrected a few typos Modified: sandbox/trunk/pep3101/proposed-pep-changes.txt ============================================================================== --- sandbox/trunk/pep3101/proposed-pep-changes.txt (original) +++ sandbox/trunk/pep3101/proposed-pep-changes.txt Mon Mar 12 01:18:26 2007 @@ -113,12 +113,12 @@ Two keyword argument names are reserved for use by the format method: - The namespace argument, if present, should be bound to a + The 'namespace' argument, if present, should be bound to a dictionary or tuple of dictionaries, which will be searched whenevar a keyword argument is not found in the **kwargs passed to format(). - The field_hook argument, if present, defines a "hook" callback + The 'field_hook' argument, if present, defines a "hook" callback function which allows greater user control over the formatting operation. @@ -138,11 +138,11 @@ string/unicode format method. In other words, the output from: - str.format(some_string, *args, **kwargs) + str.format(format_string, *args, **kwargs) and: - string.format(some_string, *args, **kwargs) + string.format(format_string, *args, **kwargs) will be indentical. @@ -151,7 +151,7 @@ The flag_format function adds an integer flags argument in front of the parameters which are passed to the format method. If this flags parameter - is 0, the results of calling flags_format will be + is 0, the results of calling flag_format will be identical to the results of calling format with the same string and *args and **kwargs. Setting bits in the flags parameter allows finer control over @@ -184,13 +184,13 @@ FORMAT_ALLOW_LEADING_UNDERSCORES By default, leading underscores are not allowed in identifier - lookups (getattr or setattr). Setting this flag will allow this. + lookups (getattr or getitem). Setting this flag will allow this. FORMAT_USE_ALL_ARGUMENTS By default, the formatting engine does not check that all arguments passed to it are used by the format string. If - this flag is set, an exception will be thrown if some + this flag is set, an exception will be raised if some arguments are unused. Backporting to earlier versions of Python @@ -768,10 +768,11 @@ Argument name collisions - The 'namespace' and 'field_hook' arguments to format share the - same namespace as the user's field names. There is nothing - which keeps a format string which does not require the namespace - or field_hook from reusing these names for its own variables. + The 'namespace' and 'field_hook' arguments to format() share the + same namespace as the user's keyword argument field names. There + is nothing to prevent a format string which does not require the + 'namespace' or 'field_hook' arguments from reusing these names + for its own variables. For clarity, use of names with leading underscores, like _namespace and _field_hook, was considered and rejected, because @@ -783,7 +784,7 @@ Automatic inclusion of locals() and globals() If no parameters are passed to the format() method, it will - automatically user the caller's locals() and globals(). + automatically use the caller's locals() and globals(). It is a tough call as to whether this should be done or not; on the one hand it is awfully convenient, but on the other hand it may be considered to violate the EIBTI principle. If From python-checkins at python.org Mon Mar 12 02:55:57 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 02:55:57 +0100 (CET) Subject: [Python-checkins] r54278 - python/trunk/Lib/urllib.py Message-ID: <20070312015557.A45A21E4006@bag.python.org> Author: collin.winter Date: Mon Mar 12 02:55:54 2007 New Revision: 54278 Modified: python/trunk/Lib/urllib.py Log: Patch #1678662: ftp.python.org does not exist. So the testcode in urllib.py must use a more stable FTP. Will backport. Modified: python/trunk/Lib/urllib.py ============================================================================== --- python/trunk/Lib/urllib.py (original) +++ python/trunk/Lib/urllib.py Mon Mar 12 02:55:54 2007 @@ -1471,7 +1471,7 @@ '/etc/passwd', 'file:/etc/passwd', 'file://localhost/etc/passwd', - 'ftp://ftp.python.org/pub/python/README', + 'ftp://ftp.gnu.org/pub/README', ## 'gopher://gopher.micro.umn.edu/1/', 'http://www.python.org/index.html', ] From python-checkins at python.org Mon Mar 12 02:57:51 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 02:57:51 +0100 (CET) Subject: [Python-checkins] r54279 - python/branches/release25-maint/Lib/urllib.py Message-ID: <20070312015751.842B41E4005@bag.python.org> Author: collin.winter Date: Mon Mar 12 02:57:49 2007 New Revision: 54279 Modified: python/branches/release25-maint/Lib/urllib.py Log: Patch #1678662: ftp.python.org does not exist. So the testcode in urllib.py must use a more stable FTP. Backported from r54278. Modified: python/branches/release25-maint/Lib/urllib.py ============================================================================== --- python/branches/release25-maint/Lib/urllib.py (original) +++ python/branches/release25-maint/Lib/urllib.py Mon Mar 12 02:57:49 2007 @@ -1471,7 +1471,7 @@ '/etc/passwd', 'file:/etc/passwd', 'file://localhost/etc/passwd', - 'ftp://ftp.python.org/pub/python/README', + 'ftp://ftp.gnu.org/pub/README', ## 'gopher://gopher.micro.umn.edu/1/', 'http://www.python.org/index.html', ] From python-checkins at python.org Mon Mar 12 04:20:07 2007 From: python-checkins at python.org (barry.warsaw) Date: Mon, 12 Mar 2007 04:20:07 +0100 (CET) Subject: [Python-checkins] r54280 - in python/trunk/Lib/email: _parseaddr.py test/test_email.py test/test_email_renamed.py Message-ID: <20070312032007.0044E1E4005@bag.python.org> Author: barry.warsaw Date: Mon Mar 12 04:20:01 2007 New Revision: 54280 Modified: python/trunk/Lib/email/_parseaddr.py python/trunk/Lib/email/test/test_email.py python/trunk/Lib/email/test/test_email_renamed.py Log: Tokio Kikuchi's fix for SF bug #1629369; folding whitespace allowed in the display name of an email address, e.g. Foo \tBar Test case added by Barry. Modified: python/trunk/Lib/email/_parseaddr.py ============================================================================== --- python/trunk/Lib/email/_parseaddr.py (original) +++ python/trunk/Lib/email/_parseaddr.py Mon Mar 12 04:20:01 2007 @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2006 Python Software Foundation +# Copyright (C) 2002-2007 Python Software Foundation # Contact: email-sig at python.org """Email address parsing code. @@ -172,6 +172,7 @@ self.pos = 0 self.LWS = ' \t' self.CR = '\r\n' + self.FWS = self.LWS + self.CR self.atomends = self.specials + self.LWS + self.CR # Note that RFC 2822 now specifies `.' as obs-phrase, meaning that it # is obsolete syntax. RFC 2822 requires that we recognize obsolete @@ -418,7 +419,7 @@ plist = [] while self.pos < len(self.field): - if self.field[self.pos] in self.LWS: + if self.field[self.pos] in self.FWS: self.pos += 1 elif self.field[self.pos] == '"': plist.append(self.getquote()) Modified: python/trunk/Lib/email/test/test_email.py ============================================================================== --- python/trunk/Lib/email/test/test_email.py (original) +++ python/trunk/Lib/email/test/test_email.py Mon Mar 12 04:20:01 2007 @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 Python Software Foundation +# Copyright (C) 2001-2007 Python Software Foundation # Contact: email-sig at python.org # email package unit tests @@ -2165,6 +2165,12 @@ # formataddr() quotes the name if there's a dot in it self.assertEqual(Utils.formataddr((a, b)), y) + def test_multiline_from_comment(self): + x = """\ +Foo +\tBar """ + self.assertEqual(Utils.parseaddr(x), ('Foo Bar', 'foo at example.com')) + def test_quote_dump(self): self.assertEqual( Utils.formataddr(('A Silly; Person', 'person at dom.ain')), Modified: python/trunk/Lib/email/test/test_email_renamed.py ============================================================================== --- python/trunk/Lib/email/test/test_email_renamed.py (original) +++ python/trunk/Lib/email/test/test_email_renamed.py Mon Mar 12 04:20:01 2007 @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 Python Software Foundation +# Copyright (C) 2001-2007 Python Software Foundation # Contact: email-sig at python.org # email package unit tests @@ -2171,6 +2171,12 @@ # formataddr() quotes the name if there's a dot in it self.assertEqual(utils.formataddr((a, b)), y) + def test_multiline_from_comment(self): + x = """\ +Foo +\tBar """ + self.assertEqual(utils.parseaddr(x), ('Foo Bar', 'foo at example.com')) + def test_quote_dump(self): self.assertEqual( utils.formataddr(('A Silly; Person', 'person at dom.ain')), From python-checkins at python.org Mon Mar 12 04:21:29 2007 From: python-checkins at python.org (barry.warsaw) Date: Mon, 12 Mar 2007 04:21:29 +0100 (CET) Subject: [Python-checkins] r54281 - in python/branches/release25-maint/Lib/email: _parseaddr.py test/test_email.py test/test_email_renamed.py Message-ID: <20070312032129.54CED1E400F@bag.python.org> Author: barry.warsaw Date: Mon Mar 12 04:21:28 2007 New Revision: 54281 Modified: python/branches/release25-maint/Lib/email/_parseaddr.py python/branches/release25-maint/Lib/email/test/test_email.py python/branches/release25-maint/Lib/email/test/test_email_renamed.py Log: Tokio Kikuchi's fix for SF bug #1629369; folding whitespace allowed in the display name of an email address, e.g. Foo \tBar Test case added by Barry. Modified: python/branches/release25-maint/Lib/email/_parseaddr.py ============================================================================== --- python/branches/release25-maint/Lib/email/_parseaddr.py (original) +++ python/branches/release25-maint/Lib/email/_parseaddr.py Mon Mar 12 04:21:28 2007 @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2006 Python Software Foundation +# Copyright (C) 2002-2007 Python Software Foundation # Contact: email-sig at python.org """Email address parsing code. @@ -172,6 +172,7 @@ self.pos = 0 self.LWS = ' \t' self.CR = '\r\n' + self.FWS = self.LWS + self.CR self.atomends = self.specials + self.LWS + self.CR # Note that RFC 2822 now specifies `.' as obs-phrase, meaning that it # is obsolete syntax. RFC 2822 requires that we recognize obsolete @@ -418,7 +419,7 @@ plist = [] while self.pos < len(self.field): - if self.field[self.pos] in self.LWS: + if self.field[self.pos] in self.FWS: self.pos += 1 elif self.field[self.pos] == '"': plist.append(self.getquote()) Modified: python/branches/release25-maint/Lib/email/test/test_email.py ============================================================================== --- python/branches/release25-maint/Lib/email/test/test_email.py (original) +++ python/branches/release25-maint/Lib/email/test/test_email.py Mon Mar 12 04:21:28 2007 @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 Python Software Foundation +# Copyright (C) 2001-2007 Python Software Foundation # Contact: email-sig at python.org # email package unit tests @@ -2165,6 +2165,12 @@ # formataddr() quotes the name if there's a dot in it self.assertEqual(Utils.formataddr((a, b)), y) + def test_multiline_from_comment(self): + x = """\ +Foo +\tBar """ + self.assertEqual(Utils.parseaddr(x), ('Foo Bar', 'foo at example.com')) + def test_quote_dump(self): self.assertEqual( Utils.formataddr(('A Silly; Person', 'person at dom.ain')), Modified: python/branches/release25-maint/Lib/email/test/test_email_renamed.py ============================================================================== --- python/branches/release25-maint/Lib/email/test/test_email_renamed.py (original) +++ python/branches/release25-maint/Lib/email/test/test_email_renamed.py Mon Mar 12 04:21:28 2007 @@ -1,4 +1,4 @@ -# Copyright (C) 2001-2006 Python Software Foundation +# Copyright (C) 2001-2007 Python Software Foundation # Contact: email-sig at python.org # email package unit tests @@ -2171,6 +2171,12 @@ # formataddr() quotes the name if there's a dot in it self.assertEqual(utils.formataddr((a, b)), y) + def test_multiline_from_comment(self): + x = """\ +Foo +\tBar """ + self.assertEqual(utils.parseaddr(x), ('Foo Bar', 'foo at example.com')) + def test_quote_dump(self): self.assertEqual( utils.formataddr(('A Silly; Person', 'person at dom.ain')), From python-checkins at python.org Mon Mar 12 04:30:54 2007 From: python-checkins at python.org (skip.montanaro) Date: Mon, 12 Mar 2007 04:30:54 +0100 (CET) Subject: [Python-checkins] r54282 - python/trunk/Lib/test/test_csv.py Message-ID: <20070312033054.851371E4014@bag.python.org> Author: skip.montanaro Date: Mon Mar 12 04:30:50 2007 New Revision: 54282 Modified: python/trunk/Lib/test/test_csv.py Log: Sane humans would call these invalid tests, but Andrew McNamara pointed out that given the inputs in these tests Excel does indeed produce the output these tests expect. Document that for future confused folks. Modified: python/trunk/Lib/test/test_csv.py ============================================================================== --- python/trunk/Lib/test/test_csv.py (original) +++ python/trunk/Lib/test/test_csv.py Mon Mar 12 04:30:50 2007 @@ -484,12 +484,16 @@ self.readerAssertEqual('a"b"c', [['a"b"c']]) def test_quotes_and_more(self): + # Excel would never write a field containing '"a"b', but when + # reading one, it will return 'ab'. self.readerAssertEqual('"a"b', [['ab']]) def test_lone_quote(self): self.readerAssertEqual('a"b', [['a"b']]) def test_quote_and_quote(self): + # Excel would never write a field containing '"a" "b"', but when + # reading one, it will return 'a "b"'. self.readerAssertEqual('"a" "b"', [['a "b"']]) def test_space_and_quote(self): From buildbot at python.org Mon Mar 12 05:36:40 2007 From: buildbot at python.org (buildbot at python.org) Date: Mon, 12 Mar 2007 04:36:40 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 Message-ID: <20070312043640.AC5E71E4006@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/55 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From collinw at gmail.com Mon Mar 12 05:41:55 2007 From: collinw at gmail.com (Collin Winter) Date: Sun, 11 Mar 2007 23:41:55 -0500 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 In-Reply-To: References: <20070310051059.C3F381E4002@bag.python.org> <45F34F3B.2080808@v.loewis.de> <45F3B907.9020407@v.loewis.de> Message-ID: <43aa6ff70703112141y5d9e504bx148bb442c2570063@mail.gmail.com> On 3/11/07, Brett Cannon wrote: > On 3/11/07, "Martin v. L?wis" wrote: > > Brett Cannon schrieb: > > - the code to do the filtering and to compute build step results > > >> from that would have to be written > > >> > > >> So I think it is more reasonable to put this filtering into regrtest. > > > > > > I was thinking of putting into the actual tests like I did with > > > test_socket_ssl and its constant timeout issues. > > > > Right, that's what I meant - filter it out in the actual test cases. > > > > My question still stands, though: would it be helpful to have a > context manager that catches socket timeout and connection resets and > raises ResourceDenied in those situations and then wrap the various > network calls in the test suite with the manager? Sounds like a good idea to me. Bonus points if works for test_wait3, too (http://www.python.org/dev/buildbot/all/hppa%20Ubuntu%20dapper%202.5/builds/55/step-test/0). Collin Winter From python-checkins at python.org Mon Mar 12 11:50:43 2007 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 12 Mar 2007 11:50:43 +0100 (CET) Subject: [Python-checkins] r54283 - in python/trunk: Misc/NEWS configure configure.in Message-ID: <20070312105043.3E2F71E4006@bag.python.org> Author: martin.v.loewis Date: Mon Mar 12 11:50:39 2007 New Revision: 54283 Modified: python/trunk/Misc/NEWS python/trunk/configure python/trunk/configure.in Log: Bug #1675511: Use -Kpic instead of -xcode=pic32 on Solaris/x86. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Mon Mar 12 11:50:39 2007 @@ -619,6 +619,8 @@ Build ----- +- Bug #1675511: Use -Kpic instead of -xcode=pic32 on Solaris/x86. + - Disable _XOPEN_SOURCE on NetBSD 1.x. - configure now checks whether gcc supports the PyArg_ParseTuple format Modified: python/trunk/configure ============================================================================== --- python/trunk/configure (original) +++ python/trunk/configure Mon Mar 12 11:50:39 2007 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 53508 . +# From configure.in Revision: 53826 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for python 2.6. # @@ -11623,9 +11623,11 @@ then case $ac_sys_system/$ac_sys_release in SunOS*) if test "$GCC" = yes; - then CCSHARED="-fPIC"; - else CCSHARED="-xcode=pic32"; - fi;; + then CCSHARED="-fPIC"; + elif test `uname -p` = sparc; + then CCSHARED="-xcode=pic32"; + else CCSHARED="-Kpic"; + fi;; hp*|HP*) if test "$GCC" = yes; then CCSHARED="-fPIC"; else CCSHARED="+z"; Modified: python/trunk/configure.in ============================================================================== --- python/trunk/configure.in (original) +++ python/trunk/configure.in Mon Mar 12 11:50:39 2007 @@ -1571,9 +1571,11 @@ then case $ac_sys_system/$ac_sys_release in SunOS*) if test "$GCC" = yes; - then CCSHARED="-fPIC"; - else CCSHARED="-xcode=pic32"; - fi;; + then CCSHARED="-fPIC"; + elif test `uname -p` = sparc; + then CCSHARED="-xcode=pic32"; + else CCSHARED="-Kpic"; + fi;; hp*|HP*) if test "$GCC" = yes; then CCSHARED="-fPIC"; else CCSHARED="+z"; From python-checkins at python.org Mon Mar 12 11:50:55 2007 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 12 Mar 2007 11:50:55 +0100 (CET) Subject: [Python-checkins] r54284 - in python/branches/release25-maint: Misc/NEWS configure configure.in Message-ID: <20070312105055.586AF1E4006@bag.python.org> Author: martin.v.loewis Date: Mon Mar 12 11:50:51 2007 New Revision: 54284 Modified: python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/configure python/branches/release25-maint/configure.in Log: Bug #1675511: Use -Kpic instead of -xcode=pic32 on Solaris/x86. Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Mon Mar 12 11:50:51 2007 @@ -378,6 +378,8 @@ Build ----- +- Bug #1675511: Use -Kpic instead of -xcode=pic32 on Solaris/x86. + - Disable _XOPEN_SOURCE on NetBSD 1.x. - Bug #1578513: Cross compilation was broken by a change to configure. Modified: python/branches/release25-maint/configure ============================================================================== --- python/branches/release25-maint/configure (original) +++ python/branches/release25-maint/configure Mon Mar 12 11:50:51 2007 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 52457 . +# From configure.in Revision: 52844 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for python 2.5. # @@ -11085,9 +11085,11 @@ then case $ac_sys_system/$ac_sys_release in SunOS*) if test "$GCC" = yes; - then CCSHARED="-fPIC"; - else CCSHARED="-xcode=pic32"; - fi;; + then CCSHARED="-fPIC"; + elif test `uname -p` = sparc; + then CCSHARED="-xcode=pic32"; + else CCSHARED="-Kpic"; + fi;; hp*|HP*) if test "$GCC" = yes; then CCSHARED="-fPIC"; else CCSHARED="+z"; Modified: python/branches/release25-maint/configure.in ============================================================================== --- python/branches/release25-maint/configure.in (original) +++ python/branches/release25-maint/configure.in Mon Mar 12 11:50:51 2007 @@ -1544,9 +1544,11 @@ then case $ac_sys_system/$ac_sys_release in SunOS*) if test "$GCC" = yes; - then CCSHARED="-fPIC"; - else CCSHARED="-xcode=pic32"; - fi;; + then CCSHARED="-fPIC"; + elif test `uname -p` = sparc; + then CCSHARED="-xcode=pic32"; + else CCSHARED="-Kpic"; + fi;; hp*|HP*) if test "$GCC" = yes; then CCSHARED="-fPIC"; else CCSHARED="+z"; From python-checkins at python.org Mon Mar 12 12:01:17 2007 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 12 Mar 2007 12:01:17 +0100 (CET) Subject: [Python-checkins] r54285 - in python/trunk: Doc/lib/libsite.tex Lib/site.py Misc/NEWS Message-ID: <20070312110117.B82871E4006@bag.python.org> Author: martin.v.loewis Date: Mon Mar 12 12:01:10 2007 New Revision: 54285 Modified: python/trunk/Doc/lib/libsite.tex python/trunk/Lib/site.py python/trunk/Misc/NEWS Log: Patch #1677862: Require a space or tab after import in .pth files. Modified: python/trunk/Doc/lib/libsite.tex ============================================================================== --- python/trunk/Doc/lib/libsite.tex (original) +++ python/trunk/Doc/lib/libsite.tex Mon Mar 12 12:01:10 2007 @@ -28,12 +28,17 @@ A path configuration file is a file whose name has the form \file{\var{package}.pth} and exists in one of the four directories -mentioned above; its contents are additional items (one -per line) to be added to \code{sys.path}. Non-existing items are -never added to \code{sys.path}, but no check is made that the item -refers to a directory (rather than a file). No item is added to -\code{sys.path} more than once. Blank lines and lines beginning with -\code{\#} are skipped. Lines starting with \code{import} are executed. +mentioned above; its contents are additional items (one per line) to +be added to \code{sys.path}. Non-existing items are never added to +\code{sys.path}, but no check is made that the item refers to a +directory (rather than a file). No item is added to \code{sys.path} +more than once. Blank lines and lines beginning with \code{\#} are +skipped. Lines starting with \code{import} (followed by space or tab) +are executed. + +\versionchanged[A space or tab is now required after the import +keyword]{2.6} + \index{package} \indexiii{path}{configuration}{file} Modified: python/trunk/Lib/site.py ============================================================================== --- python/trunk/Lib/site.py (original) +++ python/trunk/Lib/site.py Mon Mar 12 12:01:10 2007 @@ -134,7 +134,7 @@ for line in f: if line.startswith("#"): continue - if line.startswith("import"): + if line.startswith("import ") or line.startswith("import\t"): exec line continue line = line.rstrip() Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Mon Mar 12 12:01:10 2007 @@ -158,6 +158,8 @@ Library ------- +- Patch #1677862: Require a space or tab after import in .pth files. + - Patch #1192590: Fix pdb's "ignore" and "condition" commands so they trap the IndexError caused by passing in an invalid breakpoint number. From kbqku at terra.com.br Mon Mar 12 12:21:00 2007 From: kbqku at terra.com.br (cc:) Date: Mon, 12 Mar 2007 12:21:00 +0100 Subject: [Python-checkins] What type of manufacturing environment - products did you support? Message-ID: <001801c76498$c078d760$e2e7c3d0@kex> A climbing wall, a volleyball court and two lap pools. Describe any projects that you have wastewater design experience. In my very non-scientific survey, Twitter is winning the SXSWi battle. I was in Brush Square Park for the Dorkbot meet-up Saturday evening, and the duo of singing coils were one of the coolest things I've seen in a long time. A largest and Leading Engineering Consultancy Company in Middle East Urgently requires a Contracts Manager with B. Do you have any experience with sketch-up? A bachelors degree in Mechanical or Civil Engineering is preferred; PE a definite plus. Should be familiar with Related Computer Aided Designs of Aviation Runways and Fields. Must have proven design engineering with a minimum of two years experience using AutoCAD and a working knowledge of Land Development Desktop. "I think a lot of it now comes down to the costs of the sensors. Where do you currently reside? Local candidates or those willing to relocate on their own. Company offers excellent compensation plan and a GREAT benefits package. He added: "Chapter one begins today: It begins within each of us. com, the Engineering Job Source And it made him question how film as art is made. Looking Urgently for Finance Manager Having University Degree with Minimum 7 Years Experience as Finance Manager in A Large and Reputable Manufacturing Company. Local candidates or those willing to relocate on their own. Need an outgoing communication style. Where do you currently live? per market competitive rates based on Qualifications and meeting clients minimum requirements. Do you presently hold a BS in Planning or in Environmental Science and from what college or university did you graduate? The shuttles may not be able to lift Google's stock price, but they have struck a chord with employees. NEPA requirements will be a plus. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20070312/8dfe5f2d/attachment-0001.html -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: image/gif Size: 30204 bytes Desc: not available Url : http://mail.python.org/pipermail/python-checkins/attachments/20070312/8dfe5f2d/attachment-0001.gif From buildbot at python.org Mon Mar 12 13:33:50 2007 From: buildbot at python.org (buildbot at python.org) Date: Mon, 12 Mar 2007 12:33:50 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070312123350.AB4E71E4006@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/112 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From buildbot at python.org Mon Mar 12 13:50:01 2007 From: buildbot at python.org (buildbot at python.org) Date: Mon, 12 Mar 2007 12:50:01 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070312125001.43A8A1E4006@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/283 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_urllib2net sincerely, -The Buildbot From python-checkins at python.org Mon Mar 12 14:17:47 2007 From: python-checkins at python.org (georg.brandl) Date: Mon, 12 Mar 2007 14:17:47 +0100 (CET) Subject: [Python-checkins] r54287 - in python/trunk: Doc/lib/libfuncs.tex Lib/test/test_builtin.py Misc/NEWS Objects/object.c Python/bltinmodule.c Message-ID: <20070312131747.4FDA11E4006@bag.python.org> Author: georg.brandl Date: Mon Mar 12 14:17:36 2007 New Revision: 54287 Modified: python/trunk/Doc/lib/libfuncs.tex python/trunk/Lib/test/test_builtin.py python/trunk/Misc/NEWS python/trunk/Objects/object.c python/trunk/Python/bltinmodule.c Log: Backport from Py3k branch: Patch #1591665: implement the __dir__() special function lookup in PyObject_Dir. Had to change a few bits of the patch because classobjs and __methods__ are still in Py2.6. Modified: python/trunk/Doc/lib/libfuncs.tex ============================================================================== --- python/trunk/Doc/lib/libfuncs.tex (original) +++ python/trunk/Doc/lib/libfuncs.tex Mon Mar 12 14:17:36 2007 @@ -274,21 +274,34 @@ \end{funcdesc} \begin{funcdesc}{dir}{\optional{object}} - Without arguments, return the list of names in the current local - symbol table. With an argument, attempts to return a list of valid - attributes for that object. This information is gleaned from the - object's \member{__dict__} attribute, if defined, and from the class - or type object. The list is not necessarily complete. - If the object is a module object, the list contains the names of the - module's attributes. - If the object is a type or class object, - the list contains the names of its attributes, - and recursively of the attributes of its bases. - Otherwise, the list contains the object's attributes' names, - the names of its class's attributes, - and recursively of the attributes of its class's base classes. - The resulting list is sorted alphabetically. - For example: + Without arguments, return the list of names in the current local scope. With + an argument, attempt to return a list of valid attributes for that object. + + If the object has a method named \method{__dir__()}, this method will be + called and must return the list of attributes. This allows objects that + implement a custom \function{__getattr__()} or \function{__getattribute__()} + function to customize the way \function{dir()} reports their attributes. + + If the object does not provide \method{__dir__()}, the function tries its best + to gather information from the object's \member{__dict__} attribute, if + defined, and from its type object. The resulting list is not necessarily + complete, and may be inaccurate when the object has a custom + \function{__getattr__()}. + + The default \function{dir()} mechanism behaves differently with different + types of objects, as it attempts to produce the most relevant, rather than + complete, information: + \begin{itemize} + \item If the object is a module object, the list contains the names of the + module's attributes. + \item If the object is a type or class object, the list contains the names of + its attributes, and recursively of the attributes of its bases. + \item Otherwise, the list contains the object's attributes' names, the names + of its class's attributes, and recursively of the attributes of its class's + base classes. + \end{itemize} + + The resulting list is sorted alphabetically. For example: \begin{verbatim} >>> import struct @@ -296,13 +309,19 @@ ['__builtins__', '__doc__', '__name__', 'struct'] >>> dir(struct) ['__doc__', '__name__', 'calcsize', 'error', 'pack', 'unpack'] +>>> class Foo(object): +... def __dir__(self): +... return ["kan", "ga", "roo"] +... +>>> f = Foo() +>>> dir(f) +['ga', 'kan', 'roo'] \end{verbatim} - \note{Because \function{dir()} is supplied primarily as a convenience - for use at an interactive prompt, - it tries to supply an interesting set of names more than it tries to - supply a rigorously or consistently defined set of names, - and its detailed behavior may change across releases.} + \note{Because \function{dir()} is supplied primarily as a convenience for use + at an interactive prompt, it tries to supply an interesting set of names + more than it tries to supply a rigorously or consistently defined set of + names, and its detailed behavior may change across releases.} \end{funcdesc} \begin{funcdesc}{divmod}{a, b} Modified: python/trunk/Lib/test/test_builtin.py ============================================================================== --- python/trunk/Lib/test/test_builtin.py (original) +++ python/trunk/Lib/test/test_builtin.py Mon Mar 12 14:17:36 2007 @@ -259,12 +259,67 @@ self.assertRaises(TypeError, delattr) def test_dir(self): - x = 1 - self.assert_('x' in dir()) - import sys - self.assert_('modules' in dir(sys)) + # dir(wrong number of arguments) self.assertRaises(TypeError, dir, 42, 42) + # dir() - local scope + local_var = 1 + self.assert_('local_var' in dir()) + + # dir(module) + import sys + self.assert_('exit' in dir(sys)) + + # dir(module_with_invalid__dict__) + import types + class Foo(types.ModuleType): + __dict__ = 8 + f = Foo("foo") + self.assertRaises(TypeError, dir, f) + + # dir(type) + self.assert_("strip" in dir(str)) + self.assert_("__mro__" not in dir(str)) + + # dir(obj) + class Foo(object): + def __init__(self): + self.x = 7 + self.y = 8 + self.z = 9 + f = Foo() + self.assert_("y" in dir(f)) + + # dir(obj_no__dict__) + class Foo(object): + __slots__ = [] + f = Foo() + self.assert_("__repr__" in dir(f)) + + # dir(obj_no__class__with__dict__) + # (an ugly trick to cause getattr(f, "__class__") to fail) + class Foo(object): + __slots__ = ["__class__", "__dict__"] + def __init__(self): + self.bar = "wow" + f = Foo() + self.assert_("__repr__" not in dir(f)) + self.assert_("bar" in dir(f)) + + # dir(obj_using __dir__) + class Foo(object): + def __dir__(self): + return ["kan", "ga", "roo"] + f = Foo() + self.assert_(dir(f) == ["ga", "kan", "roo"]) + + # dir(obj__dir__not_list) + class Foo(object): + def __dir__(self): + return 7 + f = Foo() + self.assertRaises(TypeError, dir, f) + def test_divmod(self): self.assertEqual(divmod(12, 7), (1, 5)) self.assertEqual(divmod(-12, 7), (-2, 2)) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Mon Mar 12 14:17:36 2007 @@ -12,6 +12,10 @@ Core and builtins ----------------- +- The dir() function has been extended to call the __dir__() method on + its argument, if it exists. If not, it will work like before. This allows + customizing the output of dir() in the presence of a __getattr__(). + - Patch #1675981: remove unreachable code from ``type.__new__()`` method. - Patch #1491866: change the complex() constructor to allow parthensized Modified: python/trunk/Objects/object.c ============================================================================== --- python/trunk/Objects/object.c (original) +++ python/trunk/Objects/object.c Mon Mar 12 14:17:36 2007 @@ -1566,6 +1566,8 @@ } } +/* ------------------------- PyObject_Dir() helpers ------------------------- */ + /* Helper for PyObject_Dir. Merge the __dict__ of aclass into dict, and recursively also all the __dict__s of aclass's base classes. The order of merging isn't @@ -1662,121 +1664,192 @@ return result; } -/* Like __builtin__.dir(arg). See bltinmodule.c's builtin_dir for the - docstring, which should be kept in synch with this implementation. */ - -PyObject * -PyObject_Dir(PyObject *arg) +/* Helper for PyObject_Dir without arguments: returns the local scope. */ +static PyObject * +_dir_locals() { - /* Set exactly one of these non-NULL before the end. */ - PyObject *result = NULL; /* result list */ - PyObject *masterdict = NULL; /* result is masterdict.keys() */ - - /* If NULL arg, return the locals. */ - if (arg == NULL) { - PyObject *locals = PyEval_GetLocals(); - if (locals == NULL) - goto error; - result = PyMapping_Keys(locals); - if (result == NULL) - goto error; - } + PyObject *names; + PyObject *locals = PyEval_GetLocals(); - /* Elif this is some form of module, we only want its dict. */ - else if (PyModule_Check(arg)) { - masterdict = PyObject_GetAttrString(arg, "__dict__"); - if (masterdict == NULL) - goto error; - if (!PyDict_Check(masterdict)) { - PyErr_SetString(PyExc_TypeError, - "module.__dict__ is not a dictionary"); - goto error; - } + if (locals == NULL) { + PyErr_SetString(PyExc_SystemError, "frame does not exist"); + return NULL; } - /* Elif some form of type or class, grab its dict and its bases. - We deliberately don't suck up its __class__, as methods belonging - to the metaclass would probably be more confusing than helpful. */ - else if (PyType_Check(arg) || PyClass_Check(arg)) { - masterdict = PyDict_New(); - if (masterdict == NULL) - goto error; - if (merge_class_dict(masterdict, arg) < 0) - goto error; + names = PyMapping_Keys(locals); + if (!names) + return NULL; + if (!PyList_Check(names)) { + PyErr_Format(PyExc_TypeError, + "dir(): expected keys() of locals to be a list, " + "not '%.200s'", names->ob_type->tp_name); + Py_DECREF(names); + return NULL; } + /* the locals don't need to be DECREF'd */ + return names; +} - /* Else look at its dict, and the attrs reachable from its class. */ - else { - PyObject *itsclass; - /* Create a dict to start with. CAUTION: Not everything - responding to __dict__ returns a dict! */ - masterdict = PyObject_GetAttrString(arg, "__dict__"); - if (masterdict == NULL) { - PyErr_Clear(); - masterdict = PyDict_New(); - } - else if (!PyDict_Check(masterdict)) { - Py_DECREF(masterdict); - masterdict = PyDict_New(); - } - else { - /* The object may have returned a reference to its - dict, so copy it to avoid mutating it. */ - PyObject *temp = PyDict_Copy(masterdict); - Py_DECREF(masterdict); - masterdict = temp; - } - if (masterdict == NULL) - goto error; +/* Helper for PyObject_Dir of type objects: returns __dict__ and __bases__. + We deliberately don't suck up its __class__, as methods belonging to the + metaclass would probably be more confusing than helpful. +*/ +static PyObject * +_specialized_dir_type(PyObject *obj) +{ + PyObject *result = NULL; + PyObject *dict = PyDict_New(); - /* Merge in __members__ and __methods__ (if any). - XXX Would like this to go away someday; for now, it's - XXX needed to get at im_self etc of method objects. */ - if (merge_list_attr(masterdict, arg, "__members__") < 0) - goto error; - if (merge_list_attr(masterdict, arg, "__methods__") < 0) - goto error; + if (dict != NULL && merge_class_dict(dict, obj) == 0) + result = PyDict_Keys(dict); - /* Merge in attrs reachable from its class. - CAUTION: Not all objects have a __class__ attr. */ - itsclass = PyObject_GetAttrString(arg, "__class__"); - if (itsclass == NULL) - PyErr_Clear(); + Py_XDECREF(dict); + return result; +} + +/* Helper for PyObject_Dir of module objects: returns the module's __dict__. */ +static PyObject * +_specialized_dir_module(PyObject *obj) +{ + PyObject *result = NULL; + PyObject *dict = PyObject_GetAttrString(obj, "__dict__"); + + if (dict != NULL) { + if (PyDict_Check(dict)) + result = PyDict_Keys(dict); else { - int status = merge_class_dict(masterdict, itsclass); - Py_DECREF(itsclass); - if (status < 0) - goto error; + PyErr_Format(PyExc_TypeError, + "%.200s.__dict__ is not a dictionary", + PyModule_GetName(obj)); } } - assert((result == NULL) ^ (masterdict == NULL)); - if (masterdict != NULL) { - /* The result comes from its keys. */ - assert(result == NULL); - result = PyDict_Keys(masterdict); - if (result == NULL) - goto error; + Py_XDECREF(dict); + return result; +} + +/* Helper for PyObject_Dir of generic objects: returns __dict__, __class__, + and recursively up the __class__.__bases__ chain. +*/ +static PyObject * +_generic_dir(PyObject *obj) +{ + PyObject *result = NULL; + PyObject *dict = NULL; + PyObject *itsclass = NULL; + + /* Get __dict__ (which may or may not be a real dict...) */ + dict = PyObject_GetAttrString(obj, "__dict__"); + if (dict == NULL) { + PyErr_Clear(); + dict = PyDict_New(); + } + else if (!PyDict_Check(dict)) { + Py_DECREF(dict); + dict = PyDict_New(); + } + else { + /* Copy __dict__ to avoid mutating it. */ + PyObject *temp = PyDict_Copy(dict); + Py_DECREF(dict); + dict = temp; } - assert(result); - if (!PyList_Check(result)) { - PyErr_Format(PyExc_TypeError, - "Expected keys() to be a list, not '%.200s'", - result->ob_type->tp_name); + if (dict == NULL) goto error; - } - if (PyList_Sort(result) != 0) + + /* Merge in __members__ and __methods__ (if any). + * This is removed in Python 3000. */ + if (merge_list_attr(dict, obj, "__members__") < 0) + goto error; + if (merge_list_attr(dict, obj, "__methods__") < 0) goto error; - else - goto normal_return; - error: - Py_XDECREF(result); - result = NULL; + /* Merge in attrs reachable from its class. */ + itsclass = PyObject_GetAttrString(obj, "__class__"); + if (itsclass == NULL) + /* XXX(tomer): Perhaps fall back to obj->ob_type if no + __class__ exists? */ + PyErr_Clear(); + else { + if (merge_class_dict(dict, itsclass) != 0) + goto error; + } + + result = PyDict_Keys(dict); /* fall through */ - normal_return: - Py_XDECREF(masterdict); +error: + Py_XDECREF(itsclass); + Py_XDECREF(dict); + return result; +} + +/* Helper for PyObject_Dir: object introspection. + This calls one of the above specialized versions if no __dir__ method + exists. */ +static PyObject * +_dir_object(PyObject *obj) +{ + PyObject * result = NULL; + PyObject * dirfunc = PyObject_GetAttrString((PyObject*)obj->ob_type, + "__dir__"); + + assert(obj); + if (dirfunc == NULL) { + /* use default implementation */ + PyErr_Clear(); + if (PyModule_Check(obj)) + result = _specialized_dir_module(obj); + else if (PyType_Check(obj) || PyClass_Check(obj)) + result = _specialized_dir_type(obj); + else + result = _generic_dir(obj); + } + else { + /* use __dir__ */ + result = PyObject_CallFunctionObjArgs(dirfunc, obj, NULL); + Py_DECREF(dirfunc); + if (result == NULL) + return NULL; + + /* result must be a list */ + /* XXX(gbrandl): could also check if all items are strings */ + if (!PyList_Check(result)) { + PyErr_Format(PyExc_TypeError, + "__dir__() must return a list, not %.200s", + result->ob_type->tp_name); + Py_DECREF(result); + result = NULL; + } + } + + return result; +} + +/* Implementation of dir() -- if obj is NULL, returns the names in the current + (local) scope. Otherwise, performs introspection of the object: returns a + sorted list of attribute names (supposedly) accessible from the object +*/ +PyObject * +PyObject_Dir(PyObject *obj) +{ + PyObject * result; + + if (obj == NULL) + /* no object -- introspect the locals */ + result = _dir_locals(); + else + /* object -- introspect the object */ + result = _dir_object(obj); + + assert(result == NULL || PyList_Check(result)); + + if (result != NULL && PyList_Sort(result) != 0) { + /* sorting the list failed */ + Py_DECREF(result); + result = NULL; + } + return result; } Modified: python/trunk/Python/bltinmodule.c ============================================================================== --- python/trunk/Python/bltinmodule.c (original) +++ python/trunk/Python/bltinmodule.c Mon Mar 12 14:17:36 2007 @@ -495,15 +495,16 @@ PyDoc_STRVAR(dir_doc, "dir([object]) -> list of strings\n" "\n" -"Return an alphabetized list of names comprising (some of) the attributes\n" -"of the given object, and of attributes reachable from it:\n" -"\n" -"No argument: the names in the current scope.\n" -"Module object: the module attributes.\n" -"Type or class object: its attributes, and recursively the attributes of\n" -" its bases.\n" -"Otherwise: its attributes, its class's attributes, and recursively the\n" -" attributes of its class's base classes."); +"If called without an argument, return the names in the current scope.\n" +"Else, return an alphabetized list of names comprising (some of) the attributes\n" +"of the given object, and of attributes reachable from it.\n" +"If the object supplies a method named __dir__, it will be used; otherwise\n" +"the default dir() logic is used and returns:\n" +" for a module object: the module's attributes.\n" +" for a class object: its attributes, and recursively the attributes\n" +" of its bases.\n" +" for an other object: its attributes, its class's attributes, and\n" +" recursively the attributes of its class's base classes."); static PyObject * builtin_divmod(PyObject *self, PyObject *args) From buildbot at python.org Mon Mar 12 14:41:27 2007 From: buildbot at python.org (buildbot at python.org) Date: Mon, 12 Mar 2007 13:41:27 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 Message-ID: <20070312134128.05F0A1E4014@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/57 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Mon Mar 12 15:30:21 2007 From: python-checkins at python.org (georg.brandl) Date: Mon, 12 Mar 2007 15:30:21 +0100 (CET) Subject: [Python-checkins] r54288 - in python/trunk: Misc/NEWS Python/pythonrun.c Message-ID: <20070312143021.DA1651E4006@bag.python.org> Author: georg.brandl Date: Mon Mar 12 15:30:05 2007 New Revision: 54288 Modified: python/trunk/Misc/NEWS python/trunk/Python/pythonrun.c Log: Bug #1678647: write a newline after printing an exception in any case, even when converting the value to a string failed. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Mon Mar 12 15:30:05 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Bug #1678647: write a newline after printing an exception in any + case, even when converting the value to a string failed. + - The dir() function has been extended to call the __dir__() method on its argument, if it exists. If not, it will work like before. This allows customizing the output of dir() in the presence of a __getattr__(). Modified: python/trunk/Python/pythonrun.c ============================================================================== --- python/trunk/Python/pythonrun.c (original) +++ python/trunk/Python/pythonrun.c Mon Mar 12 15:30:05 2007 @@ -1226,8 +1226,8 @@ err = PyFile_WriteObject(s, f, Py_PRINT_RAW); Py_XDECREF(s); } - if (err == 0) - err = PyFile_WriteString("\n", f); + /* try to write a newline in any case */ + err += PyFile_WriteString("\n", f); } Py_DECREF(value); /* If an error happened here, don't show it. From python-checkins at python.org Mon Mar 12 15:48:37 2007 From: python-checkins at python.org (eric.smith) Date: Mon, 12 Mar 2007 15:48:37 +0100 (CET) Subject: [Python-checkins] r54289 - sandbox/trunk/pep3101/pep_differences.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Message-ID: <20070312144837.66DA81E4006@bag.python.org> Author: eric.smith Date: Mon Mar 12 15:48:34 2007 New Revision: 54289 Modified: sandbox/trunk/pep3101/pep_differences.txt sandbox/trunk/pep3101/test_simpleformat.py sandbox/trunk/pep3101/unicodeformat.c Log: Added centering alignment, using '^'. Added test cases, and updated pep_differences.txt. Modified: sandbox/trunk/pep3101/pep_differences.txt ============================================================================== --- sandbox/trunk/pep3101/pep_differences.txt (original) +++ sandbox/trunk/pep3101/pep_differences.txt Mon Mar 12 15:48:34 2007 @@ -136,6 +136,12 @@ format('control string', parameter1, ...) + Support for centering alignment + +In addition to left, right, and sign alignment ('<', '>', and '=', +respectively), support has been added for center alignment, using '^'. + + format_item function A large portion of the code in the new advanced formatter is the code Modified: sandbox/trunk/pep3101/test_simpleformat.py ============================================================================== --- sandbox/trunk/pep3101/test_simpleformat.py (original) +++ sandbox/trunk/pep3101/test_simpleformat.py Mon Mar 12 15:48:34 2007 @@ -130,6 +130,10 @@ self.formatEqualsWithUnicode("result ", "{0:<7s}", "result") self.formatEqualsWithUnicode(" result", "{0:>7s}", "result") self.formatEqualsWithUnicode(" result", "{0:>8s}", "result") + self.formatEqualsWithUnicode("result ", "{0:=8s}", "result") + self.formatEqualsWithUnicode(" result ", "{0:^8s}", "result") + self.formatEqualsWithUnicode(" result ", "{0:^9s}", "result") + self.formatEqualsWithUnicode(" result ", "{0:^10s}", "result") def test_repr_specifiers(self): self.formatEqualsWithUnicode("3", "{0:r}", 3) @@ -157,12 +161,25 @@ # memory move) in 'd' handling self.formatEqualsWithUnicode(" " * 997 + "100", "{0:1000d}", 100) - # now test with the 3 kinds of padding + # now test with the 4 kinds of aligning + + # first, without a specified width + self.formatEqualsWithUnicode("1", "{0:d}", 1) + self.formatEqualsWithUnicode("1", "{0:=d}", 1) + self.formatEqualsWithUnicode("1", "{0:^d}", 1) + self.formatEqualsWithUnicode("-1", "{0:d}", -1) + self.formatEqualsWithUnicode("-1", "{0:=d}", -1) + self.formatEqualsWithUnicode("-1", "{0:^d}", -1) + self.formatEqualsWithUnicode("0 ", "{0:<10d}", 0) self.formatEqualsWithUnicode("123 ", "{0:<10d}", 123) self.formatEqualsWithUnicode("-123 ", "{0:<10d}", -123) self.formatEqualsWithUnicode(" 123", "{0:>10d}", 123) self.formatEqualsWithUnicode(" -123", "{0:>10d}", -123) + self.formatEqualsWithUnicode(" 123 ", "{0:^10d}", 123) + self.formatEqualsWithUnicode(" -123 ", "{0:^10d}", -123) self.formatEqualsWithUnicode(" 123", "{0:=10d}", 123) self.formatEqualsWithUnicode("+ 123", "{0:=+10d}", 123) self.formatEqualsWithUnicode("- 123", "{0:=10d}", -123) @@ -173,9 +190,11 @@ self.formatEqualsWithUnicode("( 123)", "{0:=()10d}", -123) self.formatEqualsWithUnicode(" (123)", "{0:>()10d}", -123) self.formatEqualsWithUnicode("(123) ", "{0:<()10d}", -123) + self.formatEqualsWithUnicode(" (123) ", "{0:^()10d}", -123) self.formatEqualsWithUnicode("( 123)", "{0:=()10d}", long(-123)) self.formatEqualsWithUnicode(" (123)", "{0:>()10d}", long(-123)) self.formatEqualsWithUnicode("(123) ", "{0:<()10d}", long(-123)) + self.formatEqualsWithUnicode(" (123) ", "{0:^()10d}", long(-123)) self.formatEqualsWithUnicode("1" + "0" * 100, "{0:d}", 10**100) self.formatEqualsWithUnicode("-1" + "0" * 100, "{0:d}", -10**100) @@ -287,6 +306,7 @@ self.formatEqualsWithUnicode(" 0", "{0:>10b}", 0) self.formatEqualsWithUnicode("1001 ", "{0:<10b}", 9) self.formatEqualsWithUnicode(" 1001", "{0:>10b}", 9) + self.formatEqualsWithUnicode(" 1001 ", "{0:^10b}", 9) self.formatEqualsWithUnicode("1" + "0" * 100, "{0:b}", 2**100) self.formatEqualsWithUnicode("-1" + "0" * 100, "{0:b}", -2**100) self.formatEqualsWithUnicode("1" + "0" * 98 + "11", "{0:b}", 2**100 + 3) Modified: sandbox/trunk/pep3101/unicodeformat.c ============================================================================== --- sandbox/trunk/pep3101/unicodeformat.c (original) +++ sandbox/trunk/pep3101/unicodeformat.c Mon Mar 12 15:48:34 2007 @@ -874,7 +874,7 @@ alignment_token(CH_TYPE c) { switch (c) { - case '<': case '>': case '=': + case '<': case '>': case '=': case '^': return 1; default: return 0; @@ -998,6 +998,7 @@ const InternalFormatSpec *format) { Py_ssize_t width; /* total field width */ + Py_ssize_t lpad; CH_TYPE *dst; /* if precision is specified, output no more that format.precision @@ -1023,10 +1024,18 @@ /* now write into that space */ + /* figure out how much leading space we need, based + on the aligning */ + if (format->align == '>') + lpad = width - len; + else if (format->align == '^') + lpad = (width - len) / 2; + else + lpad = 0; + /* if right aligning, increment the destination allow space on the left */ - memcpy(dst + (format->align == '>' ? (width - len) : 0), src, - len * sizeof(CH_TYPE)); + memcpy(dst + lpad, src, len * sizeof(CH_TYPE)); /* do any padding */ if (width > len) { @@ -1036,13 +1045,13 @@ fill_char = ' '; } - if (format->align == '>') { - /* right align, pad on left */ - CH_TYPE_FILL(dst, fill_char, width - len); - } else { - /* left align, pad on right */ - CH_TYPE_FILL(dst + len, fill_char, width - len); - } + /* pad on left */ + if (lpad) + CH_TYPE_FILL(dst, fill_char, lpad); + + /* pad on right */ + if (width - len - lpad) + CH_TYPE_FILL(dst + len + lpad, fill_char, width - len - lpad); } return 1; } @@ -1127,7 +1136,10 @@ r->n_rpadding = padding; else if (format->align == '>') r->n_lpadding = padding; - else + else if (format->align == '^') { + r->n_lpadding = padding / 2; + r->n_rpadding = padding - r->n_lpadding; + } else /* must be '=' */ r->n_spadding = padding; } From python-checkins at python.org Mon Mar 12 16:57:24 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 16:57:24 +0100 (CET) Subject: [Python-checkins] r54290 - in python/trunk/Lib/test: output/test_operations regrtest.py test_dict.py test_operations.py Message-ID: <20070312155724.56B221E400F@bag.python.org> Author: collin.winter Date: Mon Mar 12 16:57:19 2007 New Revision: 54290 Removed: python/trunk/Lib/test/output/test_operations python/trunk/Lib/test/test_operations.py Modified: python/trunk/Lib/test/regrtest.py python/trunk/Lib/test/test_dict.py Log: Patch #1678088: convert test_operations to use unittest, fold the result into test_dict. Deleted: /python/trunk/Lib/test/output/test_operations ============================================================================== --- /python/trunk/Lib/test/output/test_operations Mon Mar 12 16:57:19 2007 +++ (empty file) @@ -1,21 +0,0 @@ -test_operations -3. Operations -XXX Mostly not yet implemented -3.1 Dictionary lookups fail if __cmp__() raises an exception -raising error -d[x2] = 2: caught the RuntimeError outside -raising error -z = d[x2]: caught the RuntimeError outside -raising error -x2 in d: caught the RuntimeError outside -raising error -d.has_key(x2): caught the RuntimeError outside -raising error -d.get(x2): caught the RuntimeError outside -raising error -d.setdefault(x2, 42): caught the RuntimeError outside -raising error -d.pop(x2): caught the RuntimeError outside -raising error -d.update({x2: 2}): caught the RuntimeError outside -resize bugs not triggered. Modified: python/trunk/Lib/test/regrtest.py ============================================================================== --- python/trunk/Lib/test/regrtest.py (original) +++ python/trunk/Lib/test/regrtest.py Mon Mar 12 16:57:19 2007 @@ -470,7 +470,7 @@ STDTESTS = [ 'test_grammar', 'test_opcodes', - 'test_operations', + 'test_dict', 'test_builtin', 'test_exceptions', 'test_types', Modified: python/trunk/Lib/test/test_dict.py ============================================================================== --- python/trunk/Lib/test/test_dict.py (original) +++ python/trunk/Lib/test/test_dict.py Mon Mar 12 16:57:19 2007 @@ -461,6 +461,77 @@ self.assertEqual(e.args, ((1,),)) else: self.fail("missing KeyError") + + def test_bad_key(self): + # Dictionary lookups should fail if __cmp__() raises an exception. + class CustomException(Exception): + pass + + class BadDictKey: + def __hash__(self): + return hash(self.__class__) + + def __cmp__(self, other): + if isinstance(other, self.__class__): + raise CustomException + return other + + d = {} + x1 = BadDictKey() + x2 = BadDictKey() + d[x1] = 1 + for stmt in ['d[x2] = 2', + 'z = d[x2]', + 'x2 in d', + 'd.has_key(x2)', + 'd.get(x2)', + 'd.setdefault(x2, 42)', + 'd.pop(x2)', + 'd.update({x2: 2})']: + try: + exec stmt in locals() + except CustomException: + pass + else: + self.fail("Statement didn't raise exception") + + def test_resize1(self): + # Dict resizing bug, found by Jack Jansen in 2.2 CVS development. + # This version got an assert failure in debug build, infinite loop in + # release build. Unfortunately, provoking this kind of stuff requires + # a mix of inserts and deletes hitting exactly the right hash codes in + # exactly the right order, and I can't think of a randomized approach + # that would be *likely* to hit a failing case in reasonable time. + + d = {} + for i in range(5): + d[i] = i + for i in range(5): + del d[i] + for i in range(5, 9): # i==8 was the problem + d[i] = i + + def test_resize2(self): + # Another dict resizing bug (SF bug #1456209). + # This caused Segmentation faults or Illegal instructions. + + class X(object): + def __hash__(self): + return 5 + def __eq__(self, other): + if resizing: + d.clear() + return False + d = {} + resizing = False + d[X()] = 1 + d[X()] = 2 + d[X()] = 3 + d[X()] = 4 + d[X()] = 5 + # now trigger a resize + resizing = True + d[9] = 6 from test import mapping_tests Deleted: /python/trunk/Lib/test/test_operations.py ============================================================================== --- /python/trunk/Lib/test/test_operations.py Mon Mar 12 16:57:19 2007 +++ (empty file) @@ -1,78 +0,0 @@ -# Python test set -- part 3, built-in operations. - - -print '3. Operations' -print 'XXX Mostly not yet implemented' - - -print '3.1 Dictionary lookups fail if __cmp__() raises an exception' - -class BadDictKey: - - def __hash__(self): - return hash(self.__class__) - - def __cmp__(self, other): - if isinstance(other, self.__class__): - print "raising error" - raise RuntimeError, "gotcha" - return other - -d = {} -x1 = BadDictKey() -x2 = BadDictKey() -d[x1] = 1 -for stmt in ['d[x2] = 2', - 'z = d[x2]', - 'x2 in d', - 'd.has_key(x2)', - 'd.get(x2)', - 'd.setdefault(x2, 42)', - 'd.pop(x2)', - 'd.update({x2: 2})']: - try: - exec stmt - except RuntimeError: - print "%s: caught the RuntimeError outside" % (stmt,) - else: - print "%s: No exception passed through!" # old CPython behavior - - -# Dict resizing bug, found by Jack Jansen in 2.2 CVS development. -# This version got an assert failure in debug build, infinite loop in -# release build. Unfortunately, provoking this kind of stuff requires -# a mix of inserts and deletes hitting exactly the right hash codes in -# exactly the right order, and I can't think of a randomized approach -# that would be *likely* to hit a failing case in reasonable time. - -d = {} -for i in range(5): - d[i] = i -for i in range(5): - del d[i] -for i in range(5, 9): # i==8 was the problem - d[i] = i - - -# Another dict resizing bug (SF bug #1456209). -# This caused Segmentation faults or Illegal instructions. - -class X(object): - def __hash__(self): - return 5 - def __eq__(self, other): - if resizing: - d.clear() - return False -d = {} -resizing = False -d[X()] = 1 -d[X()] = 2 -d[X()] = 3 -d[X()] = 4 -d[X()] = 5 -# now trigger a resize -resizing = True -d[9] = 6 - -print 'resize bugs not triggered.' From python-checkins at python.org Mon Mar 12 17:11:40 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 17:11:40 +0100 (CET) Subject: [Python-checkins] r54291 - in python/trunk: Include/pystate.h Lib/test/infinite_reload.py Lib/test/test_import.py Misc/NEWS Python/import.c Python/pystate.c Python/pythonrun.c Message-ID: <20070312161140.E0F3E1E4008@bag.python.org> Author: collin.winter Date: Mon Mar 12 17:11:39 2007 New Revision: 54291 Added: python/trunk/Lib/test/infinite_reload.py (contents, props changed) Modified: python/trunk/Include/pystate.h python/trunk/Lib/test/test_import.py python/trunk/Misc/NEWS python/trunk/Python/import.c python/trunk/Python/pystate.c python/trunk/Python/pythonrun.c Log: Bug #742342: make Python stop segfaulting on infinitely-recursive reload()s. Fixed by patch #922167. Will backport. Modified: python/trunk/Include/pystate.h ============================================================================== --- python/trunk/Include/pystate.h (original) +++ python/trunk/Include/pystate.h Mon Mar 12 17:11:39 2007 @@ -21,6 +21,7 @@ PyObject *modules; PyObject *sysdict; PyObject *builtins; + PyObject *modules_reloading; PyObject *codec_search_path; PyObject *codec_search_cache; Added: python/trunk/Lib/test/infinite_reload.py ============================================================================== --- (empty file) +++ python/trunk/Lib/test/infinite_reload.py Mon Mar 12 17:11:39 2007 @@ -0,0 +1,7 @@ +# For testing http://python.org/sf/742342, which reports that Python +# segfaults (infinite recursion in C) in the presence of infinite +# reload()ing. This module is imported by test_import.py:test_infinite_reload +# to make sure this doesn't happen any more. + +import infinite_reload +reload(infinite_reload) Modified: python/trunk/Lib/test/test_import.py ============================================================================== --- python/trunk/Lib/test/test_import.py (original) +++ python/trunk/Lib/test/test_import.py Mon Mar 12 17:11:39 2007 @@ -192,6 +192,16 @@ remove_files(TESTFN) if TESTFN in sys.modules: del sys.modules[TESTFN] + + def test_infinite_reload(self): + # Bug #742342 reports that Python segfaults (infinite recursion in C) + # when faced with self-recursive reload()ing. + + sys.path.insert(0, os.path.dirname(__file__)) + try: + import infinite_reload + finally: + sys.path.pop(0) def test_import_name_binding(self): # import x.y.z binds x in the current namespace Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Mon Mar 12 17:11:39 2007 @@ -19,6 +19,9 @@ its argument, if it exists. If not, it will work like before. This allows customizing the output of dir() in the presence of a __getattr__(). +- Patch #922167: Python no longer segfaults when faced with infinitely + self-recursive reload() calls (as reported by bug #742342). + - Patch #1675981: remove unreachable code from ``type.__new__()`` method. - Patch #1491866: change the complex() constructor to allow parthensized Modified: python/trunk/Python/import.c ============================================================================== --- python/trunk/Python/import.c (original) +++ python/trunk/Python/import.c Mon Mar 12 17:11:39 2007 @@ -340,6 +340,25 @@ return Py_None; } +PyObject * +PyImport_GetModulesReloading(void) +{ + PyInterpreterState *interp = PyThreadState_Get()->interp; + if (interp->modules_reloading == NULL) + Py_FatalError("PyImport_GetModuleDict: no modules_reloading dictionary!"); + return interp->modules_reloading; +} + +static void +imp_modules_reloading_clear (void) +{ + PyInterpreterState *interp = PyThreadState_Get()->interp; + if (interp->modules_reloading == NULL) + return; + PyDict_Clear(interp->modules_reloading); + return; +} + /* Helper for sys */ PyObject * @@ -499,6 +518,7 @@ PyDict_Clear(modules); interp->modules = NULL; Py_DECREF(modules); + Py_CLEAR(interp->modules_reloading); } @@ -2401,8 +2421,9 @@ PyObject * PyImport_ReloadModule(PyObject *m) { + PyObject *modules_reloading = PyImport_GetModulesReloading(); PyObject *modules = PyImport_GetModuleDict(); - PyObject *path = NULL, *loader = NULL; + PyObject *path = NULL, *loader = NULL, *existing_m = NULL; char *name, *subname; char buf[MAXPATHLEN+1]; struct filedescr *fdp; @@ -2423,20 +2444,30 @@ name); return NULL; } + if ((existing_m = PyDict_GetItemString(modules_reloading, name)) != NULL) { + /* Due to a recursive reload, this module is already being reloaded. */ + Py_INCREF(existing_m); + return existing_m; + } + PyDict_SetItemString(modules_reloading, name, m); + subname = strrchr(name, '.'); if (subname == NULL) subname = name; else { PyObject *parentname, *parent; parentname = PyString_FromStringAndSize(name, (subname-name)); - if (parentname == NULL) + if (parentname == NULL) { + imp_modules_reloading_clear(); return NULL; + } parent = PyDict_GetItem(modules, parentname); if (parent == NULL) { PyErr_Format(PyExc_ImportError, "reload(): parent %.200s not in sys.modules", PyString_AS_STRING(parentname)); Py_DECREF(parentname); + imp_modules_reloading_clear(); return NULL; } Py_DECREF(parentname); @@ -2451,6 +2482,7 @@ if (fdp == NULL) { Py_XDECREF(loader); + imp_modules_reloading_clear(); return NULL; } @@ -2467,6 +2499,7 @@ */ PyDict_SetItemString(modules, name, m); } + imp_modules_reloading_clear (); return newm; } Modified: python/trunk/Python/pystate.c ============================================================================== --- python/trunk/Python/pystate.c (original) +++ python/trunk/Python/pystate.c Mon Mar 12 17:11:39 2007 @@ -68,6 +68,7 @@ Py_FatalError("Can't initialize threads for interpreter"); #endif interp->modules = NULL; + interp->modules_reloading = NULL; interp->sysdict = NULL; interp->builtins = NULL; interp->tstate_head = NULL; @@ -107,6 +108,7 @@ Py_CLEAR(interp->codec_search_cache); Py_CLEAR(interp->codec_error_registry); Py_CLEAR(interp->modules); + Py_CLEAR(interp->modules_reloading); Py_CLEAR(interp->sysdict); Py_CLEAR(interp->builtins); } Modified: python/trunk/Python/pythonrun.c ============================================================================== --- python/trunk/Python/pythonrun.c (original) +++ python/trunk/Python/pythonrun.c Mon Mar 12 17:11:39 2007 @@ -194,6 +194,9 @@ interp->modules = PyDict_New(); if (interp->modules == NULL) Py_FatalError("Py_Initialize: can't make modules dictionary"); + interp->modules_reloading = PyDict_New(); + if (interp->modules_reloading == NULL) + Py_FatalError("Py_Initialize: can't make modules_reloading dictionary"); #ifdef Py_USING_UNICODE /* Init Unicode implementation; relies on the codec registry */ @@ -531,6 +534,7 @@ /* XXX The following is lax in error checking */ interp->modules = PyDict_New(); + interp->modules_reloading = PyDict_New(); bimod = _PyImport_FindExtension("__builtin__", "__builtin__"); if (bimod != NULL) { From python-checkins at python.org Mon Mar 12 17:15:13 2007 From: python-checkins at python.org (georg.brandl) Date: Mon, 12 Mar 2007 17:15:13 +0100 (CET) Subject: [Python-checkins] r54292 - python/trunk/Doc/lib/libctypes.tex Message-ID: <20070312161513.6061A1E4006@bag.python.org> Author: georg.brandl Date: Mon Mar 12 17:15:09 2007 New Revision: 54292 Modified: python/trunk/Doc/lib/libctypes.tex Log: Typo fix. Modified: python/trunk/Doc/lib/libctypes.tex ============================================================================== --- python/trunk/Doc/lib/libctypes.tex (original) +++ python/trunk/Doc/lib/libctypes.tex Mon Mar 12 17:15:09 2007 @@ -1219,7 +1219,7 @@ It is quite interesting to see that the Windows \function{qsort} function needs more comparisons than the linux version! -As we can easily check, our array sorted now: +As we can easily check, our array is sorted now: \begin{verbatim} >>> for i in ia: print i, ... From python-checkins at python.org Mon Mar 12 17:15:18 2007 From: python-checkins at python.org (georg.brandl) Date: Mon, 12 Mar 2007 17:15:18 +0100 (CET) Subject: [Python-checkins] r54293 - python/branches/release25-maint/Doc/lib/libctypes.tex Message-ID: <20070312161518.AC5031E4006@bag.python.org> Author: georg.brandl Date: Mon Mar 12 17:15:17 2007 New Revision: 54293 Modified: python/branches/release25-maint/Doc/lib/libctypes.tex Log: Typo fix. (backport from rev. 54292) Modified: python/branches/release25-maint/Doc/lib/libctypes.tex ============================================================================== --- python/branches/release25-maint/Doc/lib/libctypes.tex (original) +++ python/branches/release25-maint/Doc/lib/libctypes.tex Mon Mar 12 17:15:17 2007 @@ -1219,7 +1219,7 @@ It is quite interesting to see that the Windows \function{qsort} function needs more comparisons than the linux version! -As we can easily check, our array sorted now: +As we can easily check, our array is sorted now: \begin{verbatim} >>> for i in ia: print i, ... From python-checkins at python.org Mon Mar 12 17:49:28 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 17:49:28 +0100 (CET) Subject: [Python-checkins] r54294 - in python/branches/release25-maint: Include/pystate.h Lib/test/infinite_reload.py Lib/test/test_import.py Misc/NEWS Python/import.c Python/pystate.c Python/pythonrun.c Message-ID: <20070312164928.AC3DE1E4003@bag.python.org> Author: collin.winter Date: Mon Mar 12 17:49:23 2007 New Revision: 54294 Added: python/branches/release25-maint/Lib/test/infinite_reload.py (contents, props changed) Modified: python/branches/release25-maint/Include/pystate.h python/branches/release25-maint/Lib/test/test_import.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Python/import.c python/branches/release25-maint/Python/pystate.c python/branches/release25-maint/Python/pythonrun.c Log: Bug #742342: make Python stop segfaulting on infinitely-recursive reload()s. Fixed by patch #922167. Backported from r54291. Modified: python/branches/release25-maint/Include/pystate.h ============================================================================== --- python/branches/release25-maint/Include/pystate.h (original) +++ python/branches/release25-maint/Include/pystate.h Mon Mar 12 17:49:23 2007 @@ -21,6 +21,7 @@ PyObject *modules; PyObject *sysdict; PyObject *builtins; + PyObject *modules_reloading; PyObject *codec_search_path; PyObject *codec_search_cache; Added: python/branches/release25-maint/Lib/test/infinite_reload.py ============================================================================== --- (empty file) +++ python/branches/release25-maint/Lib/test/infinite_reload.py Mon Mar 12 17:49:23 2007 @@ -0,0 +1,7 @@ +# For testing http://python.org/sf/742342, which reports that Python +# segfaults (infinite recursion in C) in the presence of infinite +# reload()ing. This module is imported by test_import.py:test_infinite_reload +# to make sure this doesn't happen any more. + +import infinite_reload +reload(infinite_reload) Modified: python/branches/release25-maint/Lib/test/test_import.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_import.py (original) +++ python/branches/release25-maint/Lib/test/test_import.py Mon Mar 12 17:49:23 2007 @@ -222,3 +222,15 @@ warnings.filters = oldfilters test_import_initless_directory_warning() + +def test_infinite_reload(): + # Bug #742342 reports that Python segfaults (infinite recursion in C) + # when faced with self-recursive reload()ing. + + sys.path.insert(0, os.path.dirname(__file__)) + try: + import infinite_reload + finally: + sys.path.pop(0) + +test_infinite_reload() Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Mon Mar 12 17:49:23 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #922167: Python no longer segfaults when faced with infinitely + self-recursive reload() calls (as reported by bug #742342). + - Patch #1675981: remove unreachable code from ``type.__new__()`` method. - Patch #1638879: don't accept strings with embedded NUL bytes in long(). Modified: python/branches/release25-maint/Python/import.c ============================================================================== --- python/branches/release25-maint/Python/import.c (original) +++ python/branches/release25-maint/Python/import.c Mon Mar 12 17:49:23 2007 @@ -339,6 +339,25 @@ return Py_None; } +PyObject * +PyImport_GetModulesReloading(void) +{ + PyInterpreterState *interp = PyThreadState_Get()->interp; + if (interp->modules_reloading == NULL) + Py_FatalError("PyImport_GetModuleDict: no modules_reloading dictionary!"); + return interp->modules_reloading; +} + +static void +imp_modules_reloading_clear (void) +{ + PyInterpreterState *interp = PyThreadState_Get()->interp; + if (interp->modules_reloading == NULL) + return; + PyDict_Clear(interp->modules_reloading); + return; +} + /* Helper for sys */ PyObject * @@ -498,6 +517,7 @@ PyDict_Clear(modules); interp->modules = NULL; Py_DECREF(modules); + Py_CLEAR(interp->modules_reloading); } @@ -2400,8 +2420,9 @@ PyObject * PyImport_ReloadModule(PyObject *m) { + PyObject *modules_reloading = PyImport_GetModulesReloading(); PyObject *modules = PyImport_GetModuleDict(); - PyObject *path = NULL, *loader = NULL; + PyObject *path = NULL, *loader = NULL, *existing_m = NULL; char *name, *subname; char buf[MAXPATHLEN+1]; struct filedescr *fdp; @@ -2422,20 +2443,30 @@ name); return NULL; } + if ((existing_m = PyDict_GetItemString(modules_reloading, name)) != NULL) { + /* Due to a recursive reload, this module is already being reloaded. */ + Py_INCREF(existing_m); + return existing_m; + } + PyDict_SetItemString(modules_reloading, name, m); + subname = strrchr(name, '.'); if (subname == NULL) subname = name; else { PyObject *parentname, *parent; parentname = PyString_FromStringAndSize(name, (subname-name)); - if (parentname == NULL) + if (parentname == NULL) { + imp_modules_reloading_clear(); return NULL; + } parent = PyDict_GetItem(modules, parentname); if (parent == NULL) { PyErr_Format(PyExc_ImportError, "reload(): parent %.200s not in sys.modules", PyString_AS_STRING(parentname)); Py_DECREF(parentname); + imp_modules_reloading_clear(); return NULL; } Py_DECREF(parentname); @@ -2450,6 +2481,7 @@ if (fdp == NULL) { Py_XDECREF(loader); + imp_modules_reloading_clear(); return NULL; } @@ -2466,6 +2498,7 @@ */ PyDict_SetItemString(modules, name, m); } + imp_modules_reloading_clear(); return newm; } Modified: python/branches/release25-maint/Python/pystate.c ============================================================================== --- python/branches/release25-maint/Python/pystate.c (original) +++ python/branches/release25-maint/Python/pystate.c Mon Mar 12 17:49:23 2007 @@ -68,6 +68,7 @@ Py_FatalError("Can't initialize threads for interpreter"); #endif interp->modules = NULL; + interp->modules_reloading = NULL; interp->sysdict = NULL; interp->builtins = NULL; interp->tstate_head = NULL; @@ -107,6 +108,7 @@ Py_CLEAR(interp->codec_search_cache); Py_CLEAR(interp->codec_error_registry); Py_CLEAR(interp->modules); + Py_CLEAR(interp->modules_reloading); Py_CLEAR(interp->sysdict); Py_CLEAR(interp->builtins); } Modified: python/branches/release25-maint/Python/pythonrun.c ============================================================================== --- python/branches/release25-maint/Python/pythonrun.c (original) +++ python/branches/release25-maint/Python/pythonrun.c Mon Mar 12 17:49:23 2007 @@ -193,6 +193,9 @@ interp->modules = PyDict_New(); if (interp->modules == NULL) Py_FatalError("Py_Initialize: can't make modules dictionary"); + interp->modules_reloading = PyDict_New(); + if (interp->modules_reloading == NULL) + Py_FatalError("Py_Initialize: can't make modules_reloading dictionary"); #ifdef Py_USING_UNICODE /* Init Unicode implementation; relies on the codec registry */ @@ -530,6 +533,7 @@ /* XXX The following is lax in error checking */ interp->modules = PyDict_New(); + interp->modules_reloading = PyDict_New(); bimod = _PyImport_FindExtension("__builtin__", "__builtin__"); if (bimod != NULL) { From python-checkins at python.org Mon Mar 12 18:24:10 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 18:24:10 +0100 (CET) Subject: [Python-checkins] r54295 - in python/trunk/Lib/test: output/test_threadedtempfile test_threadedtempfile.py Message-ID: <20070312172410.AF5081E4003@bag.python.org> Author: collin.winter Date: Mon Mar 12 18:24:07 2007 New Revision: 54295 Removed: python/trunk/Lib/test/output/test_threadedtempfile Modified: python/trunk/Lib/test/test_threadedtempfile.py Log: Patch #1670993: Refactor test_threadedtempfile.py to use unittest. Deleted: /python/trunk/Lib/test/output/test_threadedtempfile ============================================================================== --- /python/trunk/Lib/test/output/test_threadedtempfile Mon Mar 12 18:24:07 2007 +++ (empty file) @@ -1,5 +0,0 @@ -test_threadedtempfile -Creating -Starting -Reaping -Done: errors 0 ok 1000 Modified: python/trunk/Lib/test/test_threadedtempfile.py ============================================================================== --- python/trunk/Lib/test/test_threadedtempfile.py (original) +++ python/trunk/Lib/test/test_threadedtempfile.py Mon Mar 12 18:24:07 2007 @@ -10,22 +10,20 @@ By default, NUM_THREADS == 20 and FILES_PER_THREAD == 50. This is enough to create about 150 failures per run under Win98SE in 2.0, and runs pretty quickly. Guido reports needing to boost FILES_PER_THREAD to 500 before -provoking a 2.0 failure under Linux. Run the test alone to boost either -via cmdline switches: - --f FILES_PER_THREAD (int) --t NUM_THREADS (int) +provoking a 2.0 failure under Linux. """ -NUM_THREADS = 20 # change w/ -t option -FILES_PER_THREAD = 50 # change w/ -f option +NUM_THREADS = 20 +FILES_PER_THREAD = 50 import thread # If this fails, we can't test this module import threading -from test.test_support import TestFailed, threading_setup, threading_cleanup +import tempfile + +from test.test_support import threading_setup, threading_cleanup, run_unittest +import unittest import StringIO from traceback import print_exc -import tempfile startEvent = threading.Event() @@ -46,41 +44,36 @@ else: self.ok_count += 1 -def test_main(): - threads = [] - thread_info = threading_setup() - print "Creating" - for i in range(NUM_THREADS): - t = TempFileGreedy() - threads.append(t) - t.start() - - print "Starting" - startEvent.set() - - print "Reaping" - ok = errors = 0 - for t in threads: - t.join() - ok += t.ok_count - errors += t.error_count - if t.error_count: - print '%s errors:\n%s' % (t.getName(), t.errors.getvalue()) - - msg = "Done: errors %d ok %d" % (errors, ok) - print msg - if errors: - raise TestFailed(msg) +class ThreadedTempFileTest(unittest.TestCase): + def test_main(self): + threads = [] + thread_info = threading_setup() + + for i in range(NUM_THREADS): + t = TempFileGreedy() + threads.append(t) + t.start() + + startEvent.set() + + ok = 0 + errors = [] + for t in threads: + t.join() + ok += t.ok_count + if t.error_count: + errors.append(str(t.getName()) + str(t.errors.getvalue())) + + threading_cleanup(*thread_info) + + msg = "Errors: errors %d ok %d\n%s" % (len(errors), ok, + '\n'.join(errors)) + self.assertEquals(errors, [], msg) + self.assertEquals(ok, NUM_THREADS * FILES_PER_THREAD) - threading_cleanup(*thread_info) +def test_main(): + run_unittest(ThreadedTempFileTest) if __name__ == "__main__": - import sys, getopt - opts, args = getopt.getopt(sys.argv[1:], "t:f:") - for o, v in opts: - if o == "-f": - FILES_PER_THREAD = int(v) - elif o == "-t": - NUM_THREADS = int(v) test_main() From python-checkins at python.org Mon Mar 12 19:08:12 2007 From: python-checkins at python.org (tim.peters) Date: Mon, 12 Mar 2007 19:08:12 +0100 (CET) Subject: [Python-checkins] r54296 - in python/trunk/Lib: SocketServer.py genericpath.py smtplib.py subprocess.py test/test_curses.py test/test_descr.py test/test_dict.py test/test_import.py test/test_itertools.py test/test_posixpath.py test/test_pty.py test/test_sax.py test/test_set.py test/test_threadedtempfile.py test/test_unittest.py test/test_zipfile.py urllib2.py zipfile.py Message-ID: <20070312180812.83B341E4003@bag.python.org> Author: tim.peters Date: Mon Mar 12 19:07:52 2007 New Revision: 54296 Modified: python/trunk/Lib/SocketServer.py python/trunk/Lib/genericpath.py python/trunk/Lib/smtplib.py python/trunk/Lib/subprocess.py python/trunk/Lib/test/test_curses.py python/trunk/Lib/test/test_descr.py python/trunk/Lib/test/test_dict.py python/trunk/Lib/test/test_import.py python/trunk/Lib/test/test_itertools.py python/trunk/Lib/test/test_posixpath.py python/trunk/Lib/test/test_pty.py python/trunk/Lib/test/test_sax.py python/trunk/Lib/test/test_set.py python/trunk/Lib/test/test_threadedtempfile.py python/trunk/Lib/test/test_unittest.py python/trunk/Lib/test/test_zipfile.py python/trunk/Lib/urllib2.py python/trunk/Lib/zipfile.py Log: Whitespace normalization. Modified: python/trunk/Lib/SocketServer.py ============================================================================== --- python/trunk/Lib/SocketServer.py (original) +++ python/trunk/Lib/SocketServer.py Mon Mar 12 19:07:52 2007 @@ -328,8 +328,8 @@ self.socket = socket.socket(self.address_family, self.socket_type) if bind_and_activate: - self.server_bind() - self.server_activate() + self.server_bind() + self.server_activate() def server_bind(self): """Called by constructor to bind the socket. Modified: python/trunk/Lib/genericpath.py ============================================================================== --- python/trunk/Lib/genericpath.py (original) +++ python/trunk/Lib/genericpath.py Mon Mar 12 19:07:52 2007 @@ -84,7 +84,7 @@ # Generic implementation of splitext, to be parametrized with # the separators def _splitext(p, sep, altsep, extsep): - """Split the extension from a pathname. + """Split the extension from a pathname. Extension is everything from the last dot to the end, ignoring leading dots. Returns "(root, ext)"; ext may be empty.""" Modified: python/trunk/Lib/smtplib.py ============================================================================== --- python/trunk/Lib/smtplib.py (original) +++ python/trunk/Lib/smtplib.py Mon Mar 12 19:07:52 2007 @@ -766,7 +766,7 @@ authentication, but your mileage might vary.""" ehlo_msg = "lhlo" - + def __init__(self, host = '', port = LMTP_PORT, local_hostname = None): """Initialize a new instance.""" SMTP.__init__(self, host, port, local_hostname) Modified: python/trunk/Lib/subprocess.py ============================================================================== --- python/trunk/Lib/subprocess.py (original) +++ python/trunk/Lib/subprocess.py Mon Mar 12 19:07:52 2007 @@ -596,7 +596,7 @@ # either have to redirect all three or none. If the subprocess # user has only redirected one or two handles, we are # automatically creating PIPEs for the rest. We should close - # these after the process is started. See bug #1124861. + # these after the process is started. See bug #1124861. if mswindows: if stdin is None and p2cwrite is not None: os.close(p2cwrite) Modified: python/trunk/Lib/test/test_curses.py ============================================================================== --- python/trunk/Lib/test/test_curses.py (original) +++ python/trunk/Lib/test/test_curses.py Mon Mar 12 19:07:52 2007 @@ -245,7 +245,7 @@ if hasattr(curses, 'resizeterm'): lines, cols = curses.LINES, curses.COLS curses.resizeterm(lines - 1, cols + 1) - + if curses.LINES != lines - 1 or curses.COLS != cols + 1: raise RuntimeError, "Expected resizeterm to update LINES and COLS" Modified: python/trunk/Lib/test/test_descr.py ============================================================================== --- python/trunk/Lib/test/test_descr.py (original) +++ python/trunk/Lib/test/test_descr.py Mon Mar 12 19:07:52 2007 @@ -1466,7 +1466,7 @@ >>> class A(object): ... pass - + >>> class B(A, type): ... pass Traceback (most recent call last): @@ -1494,7 +1494,7 @@ ... pass Also check that assignment to bases is safe. - + >>> B.__bases__ = A1, A2 Traceback (most recent call last): TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases Modified: python/trunk/Lib/test/test_dict.py ============================================================================== --- python/trunk/Lib/test/test_dict.py (original) +++ python/trunk/Lib/test/test_dict.py Mon Mar 12 19:07:52 2007 @@ -461,12 +461,12 @@ self.assertEqual(e.args, ((1,),)) else: self.fail("missing KeyError") - + def test_bad_key(self): # Dictionary lookups should fail if __cmp__() raises an exception. class CustomException(Exception): pass - + class BadDictKey: def __hash__(self): return hash(self.__class__) @@ -475,7 +475,7 @@ if isinstance(other, self.__class__): raise CustomException return other - + d = {} x1 = BadDictKey() x2 = BadDictKey() @@ -502,7 +502,7 @@ # a mix of inserts and deletes hitting exactly the right hash codes in # exactly the right order, and I can't think of a randomized approach # that would be *likely* to hit a failing case in reasonable time. - + d = {} for i in range(5): d[i] = i @@ -514,7 +514,7 @@ def test_resize2(self): # Another dict resizing bug (SF bug #1456209). # This caused Segmentation faults or Illegal instructions. - + class X(object): def __hash__(self): return 5 Modified: python/trunk/Lib/test/test_import.py ============================================================================== --- python/trunk/Lib/test/test_import.py (original) +++ python/trunk/Lib/test/test_import.py Mon Mar 12 19:07:52 2007 @@ -192,11 +192,11 @@ remove_files(TESTFN) if TESTFN in sys.modules: del sys.modules[TESTFN] - + def test_infinite_reload(self): # Bug #742342 reports that Python segfaults (infinite recursion in C) # when faced with self-recursive reload()ing. - + sys.path.insert(0, os.path.dirname(__file__)) try: import infinite_reload Modified: python/trunk/Lib/test/test_itertools.py ============================================================================== --- python/trunk/Lib/test/test_itertools.py (original) +++ python/trunk/Lib/test/test_itertools.py Mon Mar 12 19:07:52 2007 @@ -211,20 +211,20 @@ self.assertEqual(list(izip_longest(*args, **{})), target) target = [tuple((e is None and 'X' or e) for e in t) for t in target] # Replace None fills with 'X' self.assertEqual(list(izip_longest(*args, **dict(fillvalue='X'))), target) - + self.assertEqual(take(3,izip_longest('abcdef', count())), zip('abcdef', range(3))) # take 3 from infinite input self.assertEqual(list(izip_longest()), zip()) self.assertEqual(list(izip_longest([])), zip([])) self.assertEqual(list(izip_longest('abcdef')), zip('abcdef')) - + self.assertEqual(list(izip_longest('abc', 'defg', **{})), map(None, 'abc', 'defg')) # empty keyword dict self.assertRaises(TypeError, izip_longest, 3) self.assertRaises(TypeError, izip_longest, range(3), 3) for stmt in [ "izip_longest('abc', fv=1)", - "izip_longest('abc', fillvalue=1, bogus_keyword=None)", + "izip_longest('abc', fillvalue=1, bogus_keyword=None)", ]: try: eval(stmt, globals(), locals()) @@ -232,7 +232,7 @@ pass else: self.fail('Did not raise Type in: ' + stmt) - + # Check tuple re-use (implementation detail) self.assertEqual([tuple(list(pair)) for pair in izip_longest('abc', 'def')], zip('abc', 'def')) Modified: python/trunk/Lib/test/test_posixpath.py ============================================================================== --- python/trunk/Lib/test/test_posixpath.py (original) +++ python/trunk/Lib/test/test_posixpath.py Mon Mar 12 19:07:52 2007 @@ -24,7 +24,7 @@ for suffix in ["", "1", "2"]: test_support.unlink(test_support.TESTFN + suffix) safe_rmdir(test_support.TESTFN + suffix) - + def assertIs(self, a, b): self.assert_(a is b) @@ -161,7 +161,7 @@ if not f.closed: f.close() - def test_islink(self): + def test_islink(self): self.assertIs(posixpath.islink(test_support.TESTFN + "1"), False) f = open(test_support.TESTFN + "1", "wb") try: Modified: python/trunk/Lib/test/test_pty.py ============================================================================== --- python/trunk/Lib/test/test_pty.py (original) +++ python/trunk/Lib/test/test_pty.py Mon Mar 12 19:07:52 2007 @@ -41,19 +41,19 @@ # because pty code is not too portable. class PtyTest(unittest.TestCase): def setUp(self): - # isatty() and close() can hang on some platforms. Set an alarm + # isatty() and close() can hang on some platforms. Set an alarm # before running the test to make sure we don't hang forever. self.old_alarm = signal.signal(signal.SIGALRM, self.handle_sig) signal.alarm(10) - + def tearDown(self): # remove alarm, restore old alarm handler signal.alarm(0) signal.signal(signal.SIGALRM, self.old_alarm) - + def handle_sig(self, sig, frame): self.fail("isatty hung") - + def test_basic(self): try: debug("Calling master_open()") @@ -68,19 +68,19 @@ raise TestSkipped, "Pseudo-terminals (seemingly) not functional." self.assertTrue(os.isatty(slave_fd), 'slave_fd is not a tty') - + debug("Writing to slave_fd") os.write(slave_fd, TEST_STRING_1) s1 = os.read(master_fd, 1024) - self.assertEquals('I wish to buy a fish license.\n', + self.assertEquals('I wish to buy a fish license.\n', normalize_output(s1)) - + debug("Writing chunked output") os.write(slave_fd, TEST_STRING_2[:5]) os.write(slave_fd, TEST_STRING_2[5:]) s2 = os.read(master_fd, 1024) self.assertEquals('For my pet fish, Eric.\n', normalize_output(s2)) - + os.close(slave_fd) os.close(master_fd) @@ -93,7 +93,7 @@ if not os.isatty(1): debug("Child's fd 1 is not a tty?!") os._exit(3) - + # After pty.fork(), the child should already be a session leader. # (on those systems that have that concept.) debug("In child, calling os.setsid()") @@ -125,7 +125,7 @@ ##if False and lines != ['In child, calling os.setsid()', ## 'Good: OSError was raised.', '']: ## raise TestFailed("Unexpected output from child: %r" % line) - + (pid, status) = os.waitpid(pid, 0) res = status >> 8 debug("Child (%d) exited with status %d (%d)." % (pid, res, status)) @@ -137,7 +137,7 @@ self.fail("Child spawned by pty.fork() did not have a tty as stdout") elif res != 4: self.fail("pty.fork() failed for unknown reasons.") - + ##debug("Reading from master_fd now that the child has exited") ##try: ## s1 = os.read(master_fd, 1024) @@ -145,9 +145,9 @@ ## pass ##else: ## raise TestFailed("Read from master_fd did not raise exception") - + os.close(master_fd) - + # pty.fork() passed. def test_main(verbose=None): Modified: python/trunk/Lib/test/test_sax.py ============================================================================== --- python/trunk/Lib/test/test_sax.py (original) +++ python/trunk/Lib/test/test_sax.py Mon Mar 12 19:07:52 2007 @@ -252,7 +252,7 @@ gen.endDocument() return result.getvalue() == start+'' - + # ===== Xmlfilterbase def test_filter_basic(): Modified: python/trunk/Lib/test/test_set.py ============================================================================== --- python/trunk/Lib/test/test_set.py (original) +++ python/trunk/Lib/test/test_set.py Mon Mar 12 19:07:52 2007 @@ -285,10 +285,10 @@ s = self.thetype(d) self.assertEqual(sum(elem.hash_count for elem in d), n) s.difference(d) - self.assertEqual(sum(elem.hash_count for elem in d), n) + self.assertEqual(sum(elem.hash_count for elem in d), n) if hasattr(s, 'symmetric_difference_update'): s.symmetric_difference_update(d) - self.assertEqual(sum(elem.hash_count for elem in d), n) + self.assertEqual(sum(elem.hash_count for elem in d), n) class TestSet(TestJointOps): thetype = set Modified: python/trunk/Lib/test/test_threadedtempfile.py ============================================================================== --- python/trunk/Lib/test/test_threadedtempfile.py (original) +++ python/trunk/Lib/test/test_threadedtempfile.py Mon Mar 12 19:07:52 2007 @@ -49,14 +49,14 @@ def test_main(self): threads = [] thread_info = threading_setup() - + for i in range(NUM_THREADS): t = TempFileGreedy() threads.append(t) t.start() - + startEvent.set() - + ok = 0 errors = [] for t in threads: @@ -66,8 +66,8 @@ errors.append(str(t.getName()) + str(t.errors.getvalue())) threading_cleanup(*thread_info) - - msg = "Errors: errors %d ok %d\n%s" % (len(errors), ok, + + msg = "Errors: errors %d ok %d\n%s" % (len(errors), ok, '\n'.join(errors)) self.assertEquals(errors, [], msg) self.assertEquals(ok, NUM_THREADS * FILES_PER_THREAD) Modified: python/trunk/Lib/test/test_unittest.py ============================================================================== --- python/trunk/Lib/test/test_unittest.py (original) +++ python/trunk/Lib/test/test_unittest.py Mon Mar 12 19:07:52 2007 @@ -21,34 +21,34 @@ def startTest(self, test): self._events.append('startTest') super(LoggingResult, self).startTest(test) - + def stopTest(self, test): self._events.append('stopTest') super(LoggingResult, self).stopTest(test) - + def addFailure(self, *args): self._events.append('addFailure') super(LoggingResult, self).addFailure(*args) - + def addError(self, *args): self._events.append('addError') super(LoggingResult, self).addError(*args) class TestEquality(object): - # Check for a valid __eq__ implementation + # Check for a valid __eq__ implementation def test_eq(self): for obj_1, obj_2 in self.eq_pairs: self.assertEqual(obj_1, obj_2) self.assertEqual(obj_2, obj_1) - - # Check for a valid __ne__ implementation + + # Check for a valid __ne__ implementation def test_ne(self): for obj_1, obj_2 in self.ne_pairs: self.failIfEqual(obj_1, obj_2) self.failIfEqual(obj_2, obj_1) - + class TestHashing(object): - # Check for a valid __hash__ implementation + # Check for a valid __hash__ implementation def test_hash(self): for obj_1, obj_2 in self.eq_pairs: try: @@ -59,7 +59,7 @@ self.fail("%s and %s do not hash equal" % (obj_1, obj_2)) except Exception, e: self.fail("Problem hashing %s and %s: %s" % (obj_1, obj_2, e)) - + for obj_1, obj_2 in self.ne_pairs: try: assert hash(obj_1) != hash(obj_2) @@ -69,7 +69,7 @@ self.fail("%s and %s hash equal, but shouldn't" % (obj_1, obj_2)) except Exception, e: self.fail("Problem hashing %s and %s: %s" % (obj_1, obj_2, e)) - + ################################################################ ### /Support code @@ -86,25 +86,25 @@ def test_1(self): pass def test_2(self): pass def foo_bar(self): pass - + tests = unittest.TestSuite([Foo('test_1'), Foo('test_2')]) - + loader = unittest.TestLoader() self.assertEqual(loader.loadTestsFromTestCase(Foo), tests) - + # "Return a suite of all tests cases contained in the TestCase-derived # class testCaseClass" # - # Make sure it does the right thing even if no tests were found + # Make sure it does the right thing even if no tests were found def test_loadTestsFromTestCase__no_matches(self): class Foo(unittest.TestCase): def foo_bar(self): pass - + empty_suite = unittest.TestSuite() - + loader = unittest.TestLoader() self.assertEqual(loader.loadTestsFromTestCase(Foo), empty_suite) - + # "Return a suite of all tests cases contained in the TestCase-derived # class testCaseClass" # @@ -117,7 +117,7 @@ def test_loadTestsFromTestCase__TestSuite_subclass(self): class NotATestCase(unittest.TestSuite): pass - + loader = unittest.TestLoader() try: loader.loadTestsFromTestCase(NotATestCase) @@ -125,7 +125,7 @@ pass else: self.fail('Should raise TypeError') - + # "Return a suite of all tests cases contained in the TestCase-derived # class testCaseClass" # @@ -136,18 +136,18 @@ class Foo(unittest.TestCase): def runTest(self): pass - + loader = unittest.TestLoader() # This has to be false for the test to succeed self.failIf('runTest'.startswith(loader.testMethodPrefix)) - + suite = loader.loadTestsFromTestCase(Foo) self.failUnless(isinstance(suite, loader.suiteClass)) self.assertEqual(list(suite), [Foo('runTest')]) ################################################################ ### /Tests for TestLoader.loadTestsFromTestCase - + ### Tests for TestLoader.loadTestsFromModule ################################################################ @@ -159,42 +159,42 @@ def test(self): pass m.testcase_1 = MyTestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromModule(m) self.failUnless(isinstance(suite, loader.suiteClass)) - + expected = [loader.suiteClass([MyTestCase('test')])] self.assertEqual(list(suite), expected) - + # "This method searches `module` for classes derived from TestCase" - # + # # What happens if no tests are found (no TestCase instances)? def test_loadTestsFromModule__no_TestCase_instances(self): import new m = new.module('m') - + loader = unittest.TestLoader() suite = loader.loadTestsFromModule(m) self.failUnless(isinstance(suite, loader.suiteClass)) self.assertEqual(list(suite), []) - + # "This method searches `module` for classes derived from TestCase" # - # What happens if no tests are found (TestCases instances, but no tests)? + # What happens if no tests are found (TestCases instances, but no tests)? def test_loadTestsFromModule__no_TestCase_tests(self): import new m = new.module('m') class MyTestCase(unittest.TestCase): pass m.testcase_1 = MyTestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromModule(m) self.failUnless(isinstance(suite, loader.suiteClass)) - + self.assertEqual(list(suite), [loader.suiteClass()]) - + # "This method searches `module` for classes derived from TestCase"s # # What happens if loadTestsFromModule() is given something other @@ -209,22 +209,22 @@ class MyTestCase(unittest.TestCase): def test(self): pass - + class NotAModule(object): test_2 = MyTestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromModule(NotAModule) - + reference = [unittest.TestSuite([MyTestCase('test')])] self.assertEqual(list(suite), reference) - + ################################################################ ### /Tests for TestLoader.loadTestsFromModule() - + ### Tests for TestLoader.loadTestsFromName() ################################################################ - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -233,23 +233,23 @@ # Is ValueError raised in response to an empty name? def test_loadTestsFromName__empty_name(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromName('') except ValueError, e: self.assertEqual(str(e), "Empty module name") else: self.fail("TestLoader.loadTestsFromName failed to raise ValueError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a # TestCase or TestSuite instance." # - # What happens when the name contains invalid characters? + # What happens when the name contains invalid characters? def test_loadTestsFromName__malformed_name(self): loader = unittest.TestLoader() - + # XXX Should this raise ValueError or ImportError? try: loader.loadTestsFromName('abc () //') @@ -259,37 +259,37 @@ pass else: self.fail("TestLoader.loadTestsFromName failed to raise ValueError") - + # "The specifier name is a ``dotted name'' that may resolve ... to a # module" # - # What happens when a module by that name can't be found? + # What happens when a module by that name can't be found? def test_loadTestsFromName__unknown_module_name(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromName('sdasfasfasdf') except ImportError, e: self.assertEqual(str(e), "No module named sdasfasfasdf") else: self.fail("TestLoader.loadTestsFromName failed to raise ImportError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a # TestCase or TestSuite instance." # - # What happens when the module is found, but the attribute can't? + # What happens when the module is found, but the attribute can't? def test_loadTestsFromName__unknown_attr_name(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromName('unittest.sdasfasfasdf') except AttributeError, e: self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") else: self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -299,14 +299,14 @@ # found? def test_loadTestsFromName__relative_unknown_name(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromName('sdasfasfasdf', unittest) except AttributeError, e: self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") else: self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -320,14 +320,14 @@ # XXX Should probably raise a ValueError instead of an AttributeError def test_loadTestsFromName__relative_empty_name(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromName('', unittest) except AttributeError, e: pass else: self.fail("Failed to raise AttributeError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -339,7 +339,7 @@ # `module`? def test_loadTestsFromName__relative_malformed_name(self): loader = unittest.TestLoader() - + # XXX Should this raise AttributeError or ValueError? try: loader.loadTestsFromName('abc () //', unittest) @@ -363,16 +363,16 @@ class MyTestCase(unittest.TestCase): def test(self): pass - + class NotAModule(object): test_2 = MyTestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromName('test_2', NotAModule) - + reference = [MyTestCase('test')] self.assertEqual(list(suite), reference) - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -384,7 +384,7 @@ import new m = new.module('m') m.testcase_1 = object() - + loader = unittest.TestLoader() try: loader.loadTestsFromName('testcase_1', m) @@ -402,12 +402,12 @@ def test(self): pass m.testcase_1 = MyTestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromName('testcase_1', m) self.failUnless(isinstance(suite, loader.suiteClass)) self.assertEqual(list(suite), [MyTestCase('test')]) - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -419,13 +419,13 @@ def test(self): pass m.testsuite = unittest.TestSuite([MyTestCase('test')]) - + loader = unittest.TestLoader() suite = loader.loadTestsFromName('testsuite', m) self.failUnless(isinstance(suite, loader.suiteClass)) - + self.assertEqual(list(suite), [MyTestCase('test')]) - + # "The specifier name is a ``dotted name'' that may resolve ... to # ... a test method within a test case class" def test_loadTestsFromName__relative_testmethod(self): @@ -435,13 +435,13 @@ def test(self): pass m.testcase_1 = MyTestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromName('testcase_1.test', m) self.failUnless(isinstance(suite, loader.suiteClass)) - + self.assertEqual(list(suite), [MyTestCase('test')]) - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -457,7 +457,7 @@ def test(self): pass m.testcase_1 = MyTestCase - + loader = unittest.TestLoader() try: loader.loadTestsFromName('testcase_1.testfoo', m) @@ -476,12 +476,12 @@ def return_TestSuite(): return unittest.TestSuite([testcase_1, testcase_2]) m.return_TestSuite = return_TestSuite - + loader = unittest.TestLoader() suite = loader.loadTestsFromName('return_TestSuite', m) self.failUnless(isinstance(suite, loader.suiteClass)) self.assertEqual(list(suite), [testcase_1, testcase_2]) - + # "The specifier name is a ``dotted name'' that may resolve ... to # ... a callable object which returns a TestCase ... instance" def test_loadTestsFromName__callable__TestCase_instance(self): @@ -491,12 +491,12 @@ def return_TestCase(): return testcase_1 m.return_TestCase = return_TestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromName('return_TestCase', m) self.failUnless(isinstance(suite, loader.suiteClass)) self.assertEqual(list(suite), [testcase_1]) - + # "The specifier name is a ``dotted name'' that may resolve ... to # ... a callable object which returns a TestCase or TestSuite instance" # @@ -507,7 +507,7 @@ def return_wrong(): return 6 m.return_wrong = return_wrong - + loader = unittest.TestLoader() try: suite = loader.loadTestsFromName('return_wrong', m) @@ -515,9 +515,9 @@ pass else: self.fail("TestLoader.loadTestsFromName failed to raise TypeError") - + # "The specifier can refer to modules and packages which have not been - # imported; they will be imported as a side-effect" + # imported; they will be imported as a side-effect" def test_loadTestsFromName__module_not_loaded(self): # We're going to try to load this module as a side-effect, so it # better not be loaded before we try. @@ -525,11 +525,11 @@ # Why pick audioop? Google shows it isn't used very often, so there's # a good chance that it won't be imported when this test is run module_name = 'audioop' - + import sys if module_name in sys.modules: del sys.modules[module_name] - + loader = unittest.TestLoader() try: suite = loader.loadTestsFromName(module_name) @@ -547,18 +547,18 @@ ### Tests for TestLoader.loadTestsFromNames() ################################################################ - + # "Similar to loadTestsFromName(), but takes a sequence of names rather # than a single name." # # What happens if that sequence of names is empty? def test_loadTestsFromNames__empty_name_list(self): loader = unittest.TestLoader() - + suite = loader.loadTestsFromNames([]) self.failUnless(isinstance(suite, loader.suiteClass)) self.assertEqual(list(suite), []) - + # "Similar to loadTestsFromName(), but takes a sequence of names rather # than a single name." # ... @@ -569,7 +569,7 @@ # XXX Should this raise a ValueError or just return an empty TestSuite? def test_loadTestsFromNames__relative_empty_name_list(self): loader = unittest.TestLoader() - + suite = loader.loadTestsFromNames([], unittest) self.failUnless(isinstance(suite, loader.suiteClass)) self.assertEqual(list(suite), []) @@ -582,23 +582,23 @@ # Is ValueError raised in response to an empty name? def test_loadTestsFromNames__empty_name(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromNames(['']) except ValueError, e: self.assertEqual(str(e), "Empty module name") else: self.fail("TestLoader.loadTestsFromNames failed to raise ValueError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a # TestCase or TestSuite instance." # - # What happens when presented with an impossible module name? + # What happens when presented with an impossible module name? def test_loadTestsFromNames__malformed_name(self): loader = unittest.TestLoader() - + # XXX Should this raise ValueError or ImportError? try: loader.loadTestsFromNames(['abc () //']) @@ -608,39 +608,39 @@ pass else: self.fail("TestLoader.loadTestsFromNames failed to raise ValueError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a # TestCase or TestSuite instance." # - # What happens when no module can be found for the given name? + # What happens when no module can be found for the given name? def test_loadTestsFromNames__unknown_module_name(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromNames(['sdasfasfasdf']) except ImportError, e: self.assertEqual(str(e), "No module named sdasfasfasdf") else: self.fail("TestLoader.loadTestsFromNames failed to raise ImportError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a # TestCase or TestSuite instance." # - # What happens when the module can be found, but not the attribute? + # What happens when the module can be found, but not the attribute? def test_loadTestsFromNames__unknown_attr_name(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromNames(['unittest.sdasfasfasdf', 'unittest']) except AttributeError, e: self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") else: self.fail("TestLoader.loadTestsFromNames failed to raise AttributeError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -652,14 +652,14 @@ # argument? def test_loadTestsFromNames__unknown_name_relative_1(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromNames(['sdasfasfasdf'], unittest) except AttributeError, e: self.assertEqual(str(e), "'module' object has no attribute 'sdasfasfasdf'") else: self.fail("TestLoader.loadTestsFromName failed to raise AttributeError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -668,10 +668,10 @@ # "The method optionally resolves name relative to the given module" # # Do unknown attributes (relative to a provided module) still raise an - # exception even in the presence of valid attribute names? + # exception even in the presence of valid attribute names? def test_loadTestsFromNames__unknown_name_relative_2(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromNames(['TestCase', 'sdasfasfasdf'], unittest) except AttributeError, e: @@ -692,14 +692,14 @@ # more appropriate def test_loadTestsFromNames__relative_empty_name(self): loader = unittest.TestLoader() - + try: loader.loadTestsFromNames([''], unittest) except AttributeError: pass else: self.fail("Failed to raise ValueError") - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -707,10 +707,10 @@ # ... # "The method optionally resolves name relative to the given module" # - # What happens when presented with an impossible attribute name? + # What happens when presented with an impossible attribute name? def test_loadTestsFromNames__relative_malformed_name(self): loader = unittest.TestLoader() - + # XXX Should this raise AttributeError or ValueError? try: loader.loadTestsFromNames(['abc () //'], unittest) @@ -732,16 +732,16 @@ class MyTestCase(unittest.TestCase): def test(self): pass - + class NotAModule(object): test_2 = MyTestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromNames(['test_2'], NotAModule) - + reference = [unittest.TestSuite([MyTestCase('test')])] self.assertEqual(list(suite), reference) - + # "The specifier name is a ``dotted name'' that may resolve either to # a module, a test case class, a TestSuite instance, a test method # within a test case class, or a callable object which returns a @@ -753,7 +753,7 @@ import new m = new.module('m') m.testcase_1 = object() - + loader = unittest.TestLoader() try: loader.loadTestsFromNames(['testcase_1'], m) @@ -771,14 +771,14 @@ def test(self): pass m.testcase_1 = MyTestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromNames(['testcase_1'], m) self.failUnless(isinstance(suite, loader.suiteClass)) - + expected = loader.suiteClass([MyTestCase('test')]) self.assertEqual(list(suite), [expected]) - + # "The specifier name is a ``dotted name'' that may resolve ... to # ... a TestSuite instance" def test_loadTestsFromNames__relative_TestSuite(self): @@ -788,13 +788,13 @@ def test(self): pass m.testsuite = unittest.TestSuite([MyTestCase('test')]) - + loader = unittest.TestLoader() suite = loader.loadTestsFromNames(['testsuite'], m) self.failUnless(isinstance(suite, loader.suiteClass)) - + self.assertEqual(list(suite), [m.testsuite]) - + # "The specifier name is a ``dotted name'' that may resolve ... to ... a # test method within a test case class" def test_loadTestsFromNames__relative_testmethod(self): @@ -804,19 +804,19 @@ def test(self): pass m.testcase_1 = MyTestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromNames(['testcase_1.test'], m) self.failUnless(isinstance(suite, loader.suiteClass)) - + ref_suite = unittest.TestSuite([MyTestCase('test')]) self.assertEqual(list(suite), [ref_suite]) - + # "The specifier name is a ``dotted name'' that may resolve ... to ... a # test method within a test case class" # # Does the method gracefully handle names that initially look like they - # resolve to "a test method within a test case class" but don't? + # resolve to "a test method within a test case class" but don't? def test_loadTestsFromNames__relative_invalid_testmethod(self): import new m = new.module('m') @@ -824,7 +824,7 @@ def test(self): pass m.testcase_1 = MyTestCase - + loader = unittest.TestLoader() try: loader.loadTestsFromNames(['testcase_1.testfoo'], m) @@ -843,14 +843,14 @@ def return_TestSuite(): return unittest.TestSuite([testcase_1, testcase_2]) m.return_TestSuite = return_TestSuite - + loader = unittest.TestLoader() suite = loader.loadTestsFromNames(['return_TestSuite'], m) self.failUnless(isinstance(suite, loader.suiteClass)) - + expected = unittest.TestSuite([testcase_1, testcase_2]) self.assertEqual(list(suite), [expected]) - + # "The specifier name is a ``dotted name'' that may resolve ... to # ... a callable object which returns a TestCase ... instance" def test_loadTestsFromNames__callable__TestCase_instance(self): @@ -860,39 +860,39 @@ def return_TestCase(): return testcase_1 m.return_TestCase = return_TestCase - + loader = unittest.TestLoader() suite = loader.loadTestsFromNames(['return_TestCase'], m) self.failUnless(isinstance(suite, loader.suiteClass)) - + ref_suite = unittest.TestSuite([testcase_1]) self.assertEqual(list(suite), [ref_suite]) - + # "The specifier name is a ``dotted name'' that may resolve ... to # ... a callable object which returns a TestCase or TestSuite instance" # - # Are staticmethods handled correctly? + # Are staticmethods handled correctly? def test_loadTestsFromNames__callable__call_staticmethod(self): import new m = new.module('m') class Test1(unittest.TestCase): def test(self): pass - + testcase_1 = Test1('test') class Foo(unittest.TestCase): @staticmethod def foo(): return testcase_1 m.Foo = Foo - + loader = unittest.TestLoader() suite = loader.loadTestsFromNames(['Foo.foo'], m) self.failUnless(isinstance(suite, loader.suiteClass)) - + ref_suite = unittest.TestSuite([testcase_1]) self.assertEqual(list(suite), [ref_suite]) - + # "The specifier name is a ``dotted name'' that may resolve ... to # ... a callable object which returns a TestCase or TestSuite instance" # @@ -903,7 +903,7 @@ def return_wrong(): return 6 m.return_wrong = return_wrong - + loader = unittest.TestLoader() try: suite = loader.loadTestsFromNames(['return_wrong'], m) @@ -911,9 +911,9 @@ pass else: self.fail("TestLoader.loadTestsFromNames failed to raise TypeError") - + # "The specifier can refer to modules and packages which have not been - # imported; they will be imported as a side-effect" + # imported; they will be imported as a side-effect" def test_loadTestsFromNames__module_not_loaded(self): # We're going to try to load this module as a side-effect, so it # better not be loaded before we try. @@ -921,11 +921,11 @@ # Why pick audioop? Google shows it isn't used very often, so there's # a good chance that it won't be imported when this test is run module_name = 'audioop' - + import sys if module_name in sys.modules: del sys.modules[module_name] - + loader = unittest.TestLoader() try: suite = loader.loadTestsFromNames([module_name]) @@ -937,38 +937,38 @@ self.failUnless(module_name in sys.modules) finally: del sys.modules[module_name] - + ################################################################ ### /Tests for TestLoader.loadTestsFromNames() ### Tests for TestLoader.getTestCaseNames() ################################################################ - + # "Return a sorted sequence of method names found within testCaseClass" # # Test.foobar is defined to make sure getTestCaseNames() respects - # loader.testMethodPrefix + # loader.testMethodPrefix def test_getTestCaseNames(self): class Test(unittest.TestCase): def test_1(self): pass def test_2(self): pass def foobar(self): pass - + loader = unittest.TestLoader() - + self.assertEqual(loader.getTestCaseNames(Test), ['test_1', 'test_2']) - + # "Return a sorted sequence of method names found within testCaseClass" # - # Does getTestCaseNames() behave appropriately if no tests are found? + # Does getTestCaseNames() behave appropriately if no tests are found? def test_getTestCaseNames__no_tests(self): class Test(unittest.TestCase): def foobar(self): pass - + loader = unittest.TestLoader() - + self.assertEqual(loader.getTestCaseNames(Test), []) - + # "Return a sorted sequence of method names found within testCaseClass" # # Are not-TestCases handled gracefully? @@ -981,42 +981,42 @@ class BadCase(int): def test_foo(self): pass - + loader = unittest.TestLoader() names = loader.getTestCaseNames(BadCase) - + self.assertEqual(names, ['test_foo']) - + # "Return a sorted sequence of method names found within testCaseClass" # # Make sure inherited names are handled. # # TestP.foobar is defined to make sure getTestCaseNames() respects - # loader.testMethodPrefix + # loader.testMethodPrefix def test_getTestCaseNames__inheritance(self): class TestP(unittest.TestCase): def test_1(self): pass def test_2(self): pass def foobar(self): pass - + class TestC(TestP): def test_1(self): pass def test_3(self): pass - + loader = unittest.TestLoader() - + names = ['test_1', 'test_2', 'test_3'] self.assertEqual(loader.getTestCaseNames(TestC), names) - - ################################################################ + + ################################################################ ### /Tests for TestLoader.getTestCaseNames() ### Tests for TestLoader.testMethodPrefix ################################################################ - + # "String giving the prefix of method names which will be interpreted as # test methods" - # + # # Implicit in the documentation is that testMethodPrefix is respected by # all loadTestsFrom* methods. def test_testMethodPrefix__loadTestsFromTestCase(self): @@ -1024,20 +1024,20 @@ def test_1(self): pass def test_2(self): pass def foo_bar(self): pass - + tests_1 = unittest.TestSuite([Foo('foo_bar')]) tests_2 = unittest.TestSuite([Foo('test_1'), Foo('test_2')]) - + loader = unittest.TestLoader() loader.testMethodPrefix = 'foo' self.assertEqual(loader.loadTestsFromTestCase(Foo), tests_1) loader.testMethodPrefix = 'test' self.assertEqual(loader.loadTestsFromTestCase(Foo), tests_2) - + # "String giving the prefix of method names which will be interpreted as # test methods" - # + # # Implicit in the documentation is that testMethodPrefix is respected by # all loadTestsFrom* methods. def test_testMethodPrefix__loadTestsFromModule(self): @@ -1048,20 +1048,20 @@ def test_2(self): pass def foo_bar(self): pass m.Foo = Foo - + tests_1 = [unittest.TestSuite([Foo('foo_bar')])] tests_2 = [unittest.TestSuite([Foo('test_1'), Foo('test_2')])] - + loader = unittest.TestLoader() loader.testMethodPrefix = 'foo' self.assertEqual(list(loader.loadTestsFromModule(m)), tests_1) loader.testMethodPrefix = 'test' self.assertEqual(list(loader.loadTestsFromModule(m)), tests_2) - + # "String giving the prefix of method names which will be interpreted as # test methods" - # + # # Implicit in the documentation is that testMethodPrefix is respected by # all loadTestsFrom* methods. def test_testMethodPrefix__loadTestsFromName(self): @@ -1072,20 +1072,20 @@ def test_2(self): pass def foo_bar(self): pass m.Foo = Foo - + tests_1 = unittest.TestSuite([Foo('foo_bar')]) tests_2 = unittest.TestSuite([Foo('test_1'), Foo('test_2')]) - + loader = unittest.TestLoader() loader.testMethodPrefix = 'foo' self.assertEqual(loader.loadTestsFromName('Foo', m), tests_1) loader.testMethodPrefix = 'test' self.assertEqual(loader.loadTestsFromName('Foo', m), tests_2) - + # "String giving the prefix of method names which will be interpreted as # test methods" - # + # # Implicit in the documentation is that testMethodPrefix is respected by # all loadTestsFrom* methods. def test_testMethodPrefix__loadTestsFromNames(self): @@ -1096,102 +1096,102 @@ def test_2(self): pass def foo_bar(self): pass m.Foo = Foo - + tests_1 = unittest.TestSuite([unittest.TestSuite([Foo('foo_bar')])]) tests_2 = unittest.TestSuite([Foo('test_1'), Foo('test_2')]) tests_2 = unittest.TestSuite([tests_2]) - + loader = unittest.TestLoader() loader.testMethodPrefix = 'foo' self.assertEqual(loader.loadTestsFromNames(['Foo'], m), tests_1) loader.testMethodPrefix = 'test' self.assertEqual(loader.loadTestsFromNames(['Foo'], m), tests_2) - + # "The default value is 'test'" def test_testMethodPrefix__default_value(self): loader = unittest.TestLoader() self.failUnless(loader.testMethodPrefix == 'test') - + ################################################################ ### /Tests for TestLoader.testMethodPrefix - ### Tests for TestLoader.sortTestMethodsUsing + ### Tests for TestLoader.sortTestMethodsUsing ################################################################ - + # "Function to be used to compare method names when sorting them in # getTestCaseNames() and all the loadTestsFromX() methods" def test_sortTestMethodsUsing__loadTestsFromTestCase(self): def reversed_cmp(x, y): return -cmp(x, y) - + class Foo(unittest.TestCase): def test_1(self): pass def test_2(self): pass - + loader = unittest.TestLoader() loader.sortTestMethodsUsing = reversed_cmp - + tests = loader.suiteClass([Foo('test_2'), Foo('test_1')]) self.assertEqual(loader.loadTestsFromTestCase(Foo), tests) - + # "Function to be used to compare method names when sorting them in # getTestCaseNames() and all the loadTestsFromX() methods" def test_sortTestMethodsUsing__loadTestsFromModule(self): def reversed_cmp(x, y): return -cmp(x, y) - + import new - m = new.module('m') + m = new.module('m') class Foo(unittest.TestCase): def test_1(self): pass def test_2(self): pass m.Foo = Foo - + loader = unittest.TestLoader() loader.sortTestMethodsUsing = reversed_cmp - + tests = [loader.suiteClass([Foo('test_2'), Foo('test_1')])] self.assertEqual(list(loader.loadTestsFromModule(m)), tests) - + # "Function to be used to compare method names when sorting them in # getTestCaseNames() and all the loadTestsFromX() methods" def test_sortTestMethodsUsing__loadTestsFromName(self): def reversed_cmp(x, y): return -cmp(x, y) - + import new - m = new.module('m') + m = new.module('m') class Foo(unittest.TestCase): def test_1(self): pass def test_2(self): pass m.Foo = Foo - + loader = unittest.TestLoader() loader.sortTestMethodsUsing = reversed_cmp - + tests = loader.suiteClass([Foo('test_2'), Foo('test_1')]) self.assertEqual(loader.loadTestsFromName('Foo', m), tests) - + # "Function to be used to compare method names when sorting them in # getTestCaseNames() and all the loadTestsFromX() methods" def test_sortTestMethodsUsing__loadTestsFromNames(self): def reversed_cmp(x, y): return -cmp(x, y) - + import new - m = new.module('m') + m = new.module('m') class Foo(unittest.TestCase): def test_1(self): pass def test_2(self): pass m.Foo = Foo - + loader = unittest.TestLoader() loader.sortTestMethodsUsing = reversed_cmp - + tests = [loader.suiteClass([Foo('test_2'), Foo('test_1')])] self.assertEqual(list(loader.loadTestsFromNames(['Foo'], m)), tests) - + # "Function to be used to compare method names when sorting them in # getTestCaseNames()" # @@ -1199,22 +1199,22 @@ def test_sortTestMethodsUsing__getTestCaseNames(self): def reversed_cmp(x, y): return -cmp(x, y) - + class Foo(unittest.TestCase): def test_1(self): pass def test_2(self): pass - + loader = unittest.TestLoader() loader.sortTestMethodsUsing = reversed_cmp - + test_names = ['test_2', 'test_1'] self.assertEqual(loader.getTestCaseNames(Foo), test_names) - + # "The default value is the built-in cmp() function" def test_sortTestMethodsUsing__default_value(self): loader = unittest.TestLoader() self.failUnless(loader.sortTestMethodsUsing is cmp) - + # "it can be set to None to disable the sort." # # XXX How is this different from reassigning cmp? Are the tests returned @@ -1223,34 +1223,34 @@ class Foo(unittest.TestCase): def test_1(self): pass def test_2(self): pass - + loader = unittest.TestLoader() loader.sortTestMethodsUsing = None - + test_names = ['test_2', 'test_1'] self.assertEqual(set(loader.getTestCaseNames(Foo)), set(test_names)) - + ################################################################ ### /Tests for TestLoader.sortTestMethodsUsing - + ### Tests for TestLoader.suiteClass ################################################################ - + # "Callable object that constructs a test suite from a list of tests." def test_suiteClass__loadTestsFromTestCase(self): class Foo(unittest.TestCase): def test_1(self): pass def test_2(self): pass def foo_bar(self): pass - + tests = [Foo('test_1'), Foo('test_2')] loader = unittest.TestLoader() loader.suiteClass = list self.assertEqual(loader.loadTestsFromTestCase(Foo), tests) - + # It is implicit in the documentation for TestLoader.suiteClass that - # all TestLoader.loadTestsFrom* methods respect it. Let's make sure + # all TestLoader.loadTestsFrom* methods respect it. Let's make sure def test_suiteClass__loadTestsFromModule(self): import new m = new.module('m') @@ -1259,15 +1259,15 @@ def test_2(self): pass def foo_bar(self): pass m.Foo = Foo - + tests = [[Foo('test_1'), Foo('test_2')]] loader = unittest.TestLoader() loader.suiteClass = list self.assertEqual(loader.loadTestsFromModule(m), tests) - + # It is implicit in the documentation for TestLoader.suiteClass that - # all TestLoader.loadTestsFrom* methods respect it. Let's make sure + # all TestLoader.loadTestsFrom* methods respect it. Let's make sure def test_suiteClass__loadTestsFromName(self): import new m = new.module('m') @@ -1276,15 +1276,15 @@ def test_2(self): pass def foo_bar(self): pass m.Foo = Foo - + tests = [Foo('test_1'), Foo('test_2')] loader = unittest.TestLoader() loader.suiteClass = list self.assertEqual(loader.loadTestsFromName('Foo', m), tests) - + # It is implicit in the documentation for TestLoader.suiteClass that - # all TestLoader.loadTestsFrom* methods respect it. Let's make sure + # all TestLoader.loadTestsFrom* methods respect it. Let's make sure def test_suiteClass__loadTestsFromNames(self): import new m = new.module('m') @@ -1293,18 +1293,18 @@ def test_2(self): pass def foo_bar(self): pass m.Foo = Foo - + tests = [[Foo('test_1'), Foo('test_2')]] loader = unittest.TestLoader() loader.suiteClass = list self.assertEqual(loader.loadTestsFromNames(['Foo'], m), tests) - + # "The default value is the TestSuite class" def test_suiteClass__default_value(self): loader = unittest.TestLoader() self.failUnless(loader.suiteClass is unittest.TestSuite) - + ################################################################ ### /Tests for TestLoader.suiteClass @@ -1319,7 +1319,7 @@ def _mk_TestSuite(*names): return unittest.TestSuite(Foo(n) for n in names) - + ################################################################ ### /Support code for Test_TestSuite @@ -1332,13 +1332,13 @@ eq_pairs = [(unittest.TestSuite(), unittest.TestSuite()) ,(unittest.TestSuite(), unittest.TestSuite([])) ,(_mk_TestSuite('test_1'), _mk_TestSuite('test_1'))] - - # Used by TestEquality.test_ne + + # Used by TestEquality.test_ne ne_pairs = [(unittest.TestSuite(), _mk_TestSuite('test_1')) ,(unittest.TestSuite([]), _mk_TestSuite('test_1')) ,(_mk_TestSuite('test_1', 'test_2'), _mk_TestSuite('test_1', 'test_3')) ,(_mk_TestSuite('test_1'), _mk_TestSuite('test_2'))] - + ################################################################ ### /Set up attributes needed by inherited tests @@ -1350,41 +1350,41 @@ # The tests iterable should be optional def test_init__tests_optional(self): suite = unittest.TestSuite() - + self.assertEqual(suite.countTestCases(), 0) - + # "class TestSuite([tests])" # ... # "If tests is given, it must be an iterable of individual test cases # or other test suites that will be used to build the suite initially" # # TestSuite should deal with empty tests iterables by allowing the - # creation of an empty suite + # creation of an empty suite def test_init__empty_tests(self): suite = unittest.TestSuite([]) - + self.assertEqual(suite.countTestCases(), 0) - + # "class TestSuite([tests])" # ... # "If tests is given, it must be an iterable of individual test cases # or other test suites that will be used to build the suite initially" # - # TestSuite should allow any iterable to provide tests + # TestSuite should allow any iterable to provide tests def test_init__tests_from_any_iterable(self): def tests(): yield unittest.FunctionTestCase(lambda: None) yield unittest.FunctionTestCase(lambda: None) - + suite_1 = unittest.TestSuite(tests()) self.assertEqual(suite_1.countTestCases(), 2) - + suite_2 = unittest.TestSuite(suite_1) self.assertEqual(suite_2.countTestCases(), 2) - + suite_3 = unittest.TestSuite(set(suite_1)) self.assertEqual(suite_3.countTestCases(), 2) - + # "class TestSuite([tests])" # ... # "If tests is given, it must be an iterable of individual test cases @@ -1397,10 +1397,10 @@ ftc = unittest.FunctionTestCase(lambda: None) yield unittest.TestSuite([ftc]) yield unittest.FunctionTestCase(lambda: None) - + suite = unittest.TestSuite(tests()) self.assertEqual(suite.countTestCases(), 2) - + ################################################################ ### /Tests for TestSuite.__init__ @@ -1409,19 +1409,19 @@ test1 = unittest.FunctionTestCase(lambda: None) test2 = unittest.FunctionTestCase(lambda: None) suite = unittest.TestSuite((test1, test2)) - + self.assertEqual(list(suite), [test1, test2]) - + # "Return the number of tests represented by the this test object. # ...this method is also implemented by the TestSuite class, which can # return larger [greater than 1] values" # - # Presumably an empty TestSuite returns 0? + # Presumably an empty TestSuite returns 0? def test_countTestCases_zero_simple(self): suite = unittest.TestSuite() - + self.assertEqual(suite.countTestCases(), 0) - + # "Return the number of tests represented by the this test object. # ...this method is also implemented by the TestSuite class, which can # return larger [greater than 1] values" @@ -1434,9 +1434,9 @@ pass suite = unittest.TestSuite([unittest.TestSuite()]) - + self.assertEqual(suite.countTestCases(), 0) - + # "Return the number of tests represented by the this test object. # ...this method is also implemented by the TestSuite class, which can # return larger [greater than 1] values" @@ -1444,9 +1444,9 @@ test1 = unittest.FunctionTestCase(lambda: None) test2 = unittest.FunctionTestCase(lambda: None) suite = unittest.TestSuite((test1, test2)) - + self.assertEqual(suite.countTestCases(), 2) - + # "Return the number of tests represented by the this test object. # ...this method is also implemented by the TestSuite class, which can # return larger [greater than 1] values" @@ -1456,14 +1456,14 @@ class Test1(unittest.TestCase): def test1(self): pass def test2(self): pass - + test2 = unittest.FunctionTestCase(lambda: None) test3 = unittest.FunctionTestCase(lambda: None) child = unittest.TestSuite((Test1('test2'), test2)) parent = unittest.TestSuite((test3, child, Test1('test1'))) - + self.assertEqual(parent.countTestCases(), 4) - + # "Run the tests associated with this suite, collecting the result into # the test result object passed as result." # @@ -1471,109 +1471,109 @@ def test_run__empty_suite(self): events = [] result = LoggingResult(events) - + suite = unittest.TestSuite() - + suite.run(result) - + self.assertEqual(events, []) - + # "Note that unlike TestCase.run(), TestSuite.run() requires the # "result object to be passed in." def test_run__requires_result(self): suite = unittest.TestSuite() - + try: suite.run() except TypeError: pass else: self.fail("Failed to raise TypeError") - + # "Run the tests associated with this suite, collecting the result into - # the test result object passed as result." + # the test result object passed as result." def test_run(self): events = [] result = LoggingResult(events) - + class LoggingCase(unittest.TestCase): def run(self, result): events.append('run %s' % self._testMethodName) - + def test1(self): pass def test2(self): pass - - tests = [LoggingCase('test1'), LoggingCase('test2')] - + + tests = [LoggingCase('test1'), LoggingCase('test2')] + unittest.TestSuite(tests).run(result) - + self.assertEqual(events, ['run test1', 'run test2']) - - # "Add a TestCase ... to the suite" + + # "Add a TestCase ... to the suite" def test_addTest__TestCase(self): class Foo(unittest.TestCase): def test(self): pass - + test = Foo('test') suite = unittest.TestSuite() - + suite.addTest(test) - + self.assertEqual(suite.countTestCases(), 1) self.assertEqual(list(suite), [test]) - - # "Add a ... TestSuite to the suite" + + # "Add a ... TestSuite to the suite" def test_addTest__TestSuite(self): class Foo(unittest.TestCase): def test(self): pass - + suite_2 = unittest.TestSuite([Foo('test')]) - + suite = unittest.TestSuite() suite.addTest(suite_2) - + self.assertEqual(suite.countTestCases(), 1) self.assertEqual(list(suite), [suite_2]) - + # "Add all the tests from an iterable of TestCase and TestSuite # instances to this test suite." - # + # # "This is equivalent to iterating over tests, calling addTest() for - # each element" + # each element" def test_addTests(self): class Foo(unittest.TestCase): def test_1(self): pass def test_2(self): pass - + test_1 = Foo('test_1') test_2 = Foo('test_2') inner_suite = unittest.TestSuite([test_2]) - + def gen(): yield test_1 yield test_2 yield inner_suite - + suite_1 = unittest.TestSuite() suite_1.addTests(gen()) - + self.assertEqual(list(suite_1), list(gen())) - + # "This is equivalent to iterating over tests, calling addTest() for - # each element" + # each element" suite_2 = unittest.TestSuite() for t in gen(): suite_2.addTest(t) - + self.assertEqual(suite_1, suite_2) - + # "Add all the tests from an iterable of TestCase and TestSuite # instances to this test suite." # - # What happens if it doesn't get an iterable? + # What happens if it doesn't get an iterable? def test_addTest__noniterable(self): suite = unittest.TestSuite() - + try: suite.addTests(5) except TypeError: @@ -1593,17 +1593,17 @@ def test_addTests__string(self): suite = unittest.TestSuite() self.assertRaises(TypeError, suite.addTests, "foo") - - + + class Test_FunctionTestCase(TestCase): - + # "Return the number of tests represented by the this test object. For - # TestCase instances, this will always be 1" + # TestCase instances, this will always be 1" def test_countTestCases(self): test = unittest.FunctionTestCase(lambda: None) - + self.assertEqual(test.countTestCases(), 1) - + # "When a setUp() method is defined, the test runner will run that method # prior to each test. Likewise, if a tearDown() method is defined, the # test runner will invoke that method after each test. In the example, @@ -1614,7 +1614,7 @@ def test_run_call_order__error_in_setUp(self): events = [] result = LoggingResult(events) - + def setUp(): events.append('setUp') raise RuntimeError('raised by setUp') @@ -1624,11 +1624,11 @@ def tearDown(): events.append('tearDown') - - expected = ['startTest', 'setUp', 'addError', 'stopTest'] + + expected = ['startTest', 'setUp', 'addError', 'stopTest'] unittest.FunctionTestCase(test, setUp, tearDown).run(result) self.assertEqual(events, expected) - + # "When a setUp() method is defined, the test runner will run that method # prior to each test. Likewise, if a tearDown() method is defined, the # test runner will invoke that method after each test. In the example, @@ -1639,7 +1639,7 @@ def test_run_call_order__error_in_test(self): events = [] result = LoggingResult(events) - + def setUp(): events.append('setUp') @@ -1649,12 +1649,12 @@ def tearDown(): events.append('tearDown') - + expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown', 'stopTest'] unittest.FunctionTestCase(test, setUp, tearDown).run(result) self.assertEqual(events, expected) - + # "When a setUp() method is defined, the test runner will run that method # prior to each test. Likewise, if a tearDown() method is defined, the # test runner will invoke that method after each test. In the example, @@ -1665,7 +1665,7 @@ def test_run_call_order__failure_in_test(self): events = [] result = LoggingResult(events) - + def setUp(): events.append('setUp') @@ -1675,12 +1675,12 @@ def tearDown(): events.append('tearDown') - + expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown', 'stopTest'] unittest.FunctionTestCase(test, setUp, tearDown).run(result) self.assertEqual(events, expected) - + # "When a setUp() method is defined, the test runner will run that method # prior to each test. Likewise, if a tearDown() method is defined, the # test runner will invoke that method after each test. In the example, @@ -1691,7 +1691,7 @@ def test_run_call_order__error_in_tearDown(self): events = [] result = LoggingResult(events) - + def setUp(): events.append('setUp') @@ -1701,12 +1701,12 @@ def tearDown(): events.append('tearDown') raise RuntimeError('raised by tearDown') - + expected = ['startTest', 'setUp', 'test', 'tearDown', 'addError', 'stopTest'] unittest.FunctionTestCase(test, setUp, tearDown).run(result) self.assertEqual(events, expected) - + # "Return a string identifying the specific test case." # # Because of the vague nature of the docs, I'm not going to lock this @@ -1715,26 +1715,26 @@ # just say "string") def test_id(self): test = unittest.FunctionTestCase(lambda: None) - + self.failUnless(isinstance(test.id(), basestring)) - + # "Returns a one-line description of the test, or None if no description # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." + # the first line of the test method's docstring, if available, or None." def test_shortDescription__no_docstring(self): test = unittest.FunctionTestCase(lambda: None) - + self.assertEqual(test.shortDescription(), None) - + # "Returns a one-line description of the test, or None if no description # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." + # the first line of the test method's docstring, if available, or None." def test_shortDescription__singleline_docstring(self): desc = "this tests foo" test = unittest.FunctionTestCase(lambda: None, description=desc) - + self.assertEqual(test.shortDescription(), "this tests foo") - + class Test_TestResult(TestCase): # Note: there are not separate tests for TestResult.wasSuccessful(), # TestResult.errors, TestResult.failures, TestResult.testsRun or @@ -1744,75 +1744,75 @@ # Accordingly, tests for the aforenamed attributes are incorporated # in with the tests for the defining methods. ################################################################ - + def test_init(self): result = unittest.TestResult() - + self.failUnless(result.wasSuccessful()) self.assertEqual(len(result.errors), 0) self.assertEqual(len(result.failures), 0) self.assertEqual(result.testsRun, 0) self.assertEqual(result.shouldStop, False) - + # "This method can be called to signal that the set of tests being # run should be aborted by setting the TestResult's shouldStop - # attribute to True." + # attribute to True." def test_stop(self): result = unittest.TestResult() - + result.stop() - + self.assertEqual(result.shouldStop, True) - + # "Called when the test case test is about to be run. The default # implementation simply increments the instance's testsRun counter." def test_startTest(self): class Foo(unittest.TestCase): def test_1(self): pass - + test = Foo('test_1') - + result = unittest.TestResult() - + result.startTest(test) - + self.failUnless(result.wasSuccessful()) self.assertEqual(len(result.errors), 0) self.assertEqual(len(result.failures), 0) self.assertEqual(result.testsRun, 1) self.assertEqual(result.shouldStop, False) - + result.stopTest(test) - + # "Called after the test case test has been executed, regardless of # the outcome. The default implementation does nothing." def test_stopTest(self): class Foo(unittest.TestCase): def test_1(self): pass - + test = Foo('test_1') - + result = unittest.TestResult() - + result.startTest(test) - + self.failUnless(result.wasSuccessful()) self.assertEqual(len(result.errors), 0) self.assertEqual(len(result.failures), 0) self.assertEqual(result.testsRun, 1) self.assertEqual(result.shouldStop, False) - + result.stopTest(test) - + # Same tests as above; make sure nothing has changed self.failUnless(result.wasSuccessful()) self.assertEqual(len(result.errors), 0) self.assertEqual(len(result.failures), 0) self.assertEqual(result.testsRun, 1) self.assertEqual(result.shouldStop, False) - + # "addSuccess(test)" # ... # "Called when the test case test succeeds" @@ -1836,21 +1836,21 @@ class Foo(unittest.TestCase): def test_1(self): pass - + test = Foo('test_1') - + result = unittest.TestResult() - + result.startTest(test) result.addSuccess(test) result.stopTest(test) - + self.failUnless(result.wasSuccessful()) self.assertEqual(len(result.errors), 0) self.assertEqual(len(result.failures), 0) self.assertEqual(result.testsRun, 1) self.assertEqual(result.shouldStop, False) - + # "addFailure(test, err)" # ... # "Called when the test case test signals a failure. err is a tuple of @@ -1873,33 +1873,33 @@ # of sys.exc_info() results." def test_addFailure(self): import sys - + class Foo(unittest.TestCase): def test_1(self): pass - + test = Foo('test_1') try: test.fail("foo") except: exc_info_tuple = sys.exc_info() - + result = unittest.TestResult() - + result.startTest(test) result.addFailure(test, exc_info_tuple) result.stopTest(test) - + self.failIf(result.wasSuccessful()) self.assertEqual(len(result.errors), 0) self.assertEqual(len(result.failures), 1) self.assertEqual(result.testsRun, 1) self.assertEqual(result.shouldStop, False) - + test_case, formatted_exc = result.failures[0] self.failUnless(test_case is test) self.failUnless(isinstance(formatted_exc, str)) - + # "addError(test, err)" # ... # "Called when the test case test raises an unexpected exception err @@ -1923,29 +1923,29 @@ # of sys.exc_info() results." def test_addError(self): import sys - + class Foo(unittest.TestCase): def test_1(self): pass - + test = Foo('test_1') try: raise TypeError() except: exc_info_tuple = sys.exc_info() - + result = unittest.TestResult() - + result.startTest(test) result.addError(test, exc_info_tuple) result.stopTest(test) - + self.failIf(result.wasSuccessful()) self.assertEqual(len(result.errors), 1) self.assertEqual(len(result.failures), 0) self.assertEqual(result.testsRun, 1) self.assertEqual(result.shouldStop, False) - + test_case, formatted_exc = result.errors[0] self.failUnless(test_case is test) self.failUnless(isinstance(formatted_exc, str)) @@ -1956,10 +1956,10 @@ class Foo(unittest.TestCase): def runTest(self): pass def test1(self): pass - + class Bar(Foo): def test2(self): pass - + ################################################################ ### /Support code for Test_TestCase @@ -1970,15 +1970,15 @@ # Used by TestHashing.test_hash and TestEquality.test_eq eq_pairs = [(Foo('test1'), Foo('test1'))] - + # Used by TestEquality.test_ne ne_pairs = [(Foo('test1'), Foo('runTest')) ,(Foo('test1'), Bar('test1')) ,(Foo('test1'), Bar('test2'))] - + ################################################################ ### /Set up attributes used by inherited tests - + # "class TestCase([methodName])" # ... @@ -1993,44 +1993,44 @@ class Test(unittest.TestCase): def runTest(self): raise MyException() def test(self): pass - + self.assertEqual(Test().id()[-13:], '.Test.runTest') - + # "class TestCase([methodName])" # ... # "Each instance of TestCase will run a single test method: the - # method named methodName." + # method named methodName." def test_init__test_name__valid(self): class Test(unittest.TestCase): def runTest(self): raise MyException() def test(self): pass - + self.assertEqual(Test('test').id()[-10:], '.Test.test') - + # "class TestCase([methodName])" # ... # "Each instance of TestCase will run a single test method: the - # method named methodName." + # method named methodName." def test_init__test_name__invalid(self): class Test(unittest.TestCase): def runTest(self): raise MyException() def test(self): pass - + try: Test('testfoo') except ValueError: pass else: self.fail("Failed to raise ValueError") - + # "Return the number of tests represented by the this test object. For - # TestCase instances, this will always be 1" + # TestCase instances, this will always be 1" def test_countTestCases(self): class Foo(unittest.TestCase): def test(self): pass - + self.assertEqual(Foo('test').countTestCases(), 1) - + # "Return the default type of test result object to be used to run this # test. For TestCase instances, this will always be # unittest.TestResult; subclasses of TestCase should @@ -2039,7 +2039,7 @@ class Foo(unittest.TestCase): def runTest(self): pass - + result = Foo().defaultTestResult() self.assertEqual(type(result), unittest.TestResult) @@ -2053,22 +2053,22 @@ def test_run_call_order__error_in_setUp(self): events = [] result = LoggingResult(events) - + class Foo(unittest.TestCase): def setUp(self): events.append('setUp') raise RuntimeError('raised by Foo.setUp') - + def test(self): events.append('test') - + def tearDown(self): events.append('tearDown') - + Foo('test').run(result) expected = ['startTest', 'setUp', 'addError', 'stopTest'] self.assertEqual(events, expected) - + # "When a setUp() method is defined, the test runner will run that method # prior to each test. Likewise, if a tearDown() method is defined, the # test runner will invoke that method after each test. In the example, @@ -2079,23 +2079,23 @@ def test_run_call_order__error_in_test(self): events = [] result = LoggingResult(events) - + class Foo(unittest.TestCase): def setUp(self): events.append('setUp') - + def test(self): events.append('test') raise RuntimeError('raised by Foo.test') - + def tearDown(self): events.append('tearDown') - + expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown', 'stopTest'] Foo('test').run(result) self.assertEqual(events, expected) - + # "When a setUp() method is defined, the test runner will run that method # prior to each test. Likewise, if a tearDown() method is defined, the # test runner will invoke that method after each test. In the example, @@ -2106,23 +2106,23 @@ def test_run_call_order__failure_in_test(self): events = [] result = LoggingResult(events) - + class Foo(unittest.TestCase): def setUp(self): events.append('setUp') - + def test(self): events.append('test') self.fail('raised by Foo.test') - + def tearDown(self): events.append('tearDown') - + expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown', 'stopTest'] Foo('test').run(result) self.assertEqual(events, expected) - + # "When a setUp() method is defined, the test runner will run that method # prior to each test. Likewise, if a tearDown() method is defined, the # test runner will invoke that method after each test. In the example, @@ -2133,23 +2133,23 @@ def test_run_call_order__error_in_tearDown(self): events = [] result = LoggingResult(events) - + class Foo(unittest.TestCase): def setUp(self): events.append('setUp') - + def test(self): events.append('test') - + def tearDown(self): events.append('tearDown') raise RuntimeError('raised by Foo.tearDown') - + Foo('test').run(result) expected = ['startTest', 'setUp', 'test', 'tearDown', 'addError', 'stopTest'] self.assertEqual(events, expected) - + # "This class attribute gives the exception raised by the test() method. # If a test framework needs to use a specialized exception, possibly to # carry additional information, it must subclass this exception in @@ -2159,9 +2159,9 @@ class Foo(unittest.TestCase): def test(self): pass - + self.failUnless(Foo('test').failureException is AssertionError) - + # "This class attribute gives the exception raised by the test() method. # If a test framework needs to use a specialized exception, possibly to # carry additional information, it must subclass this exception in @@ -2171,20 +2171,20 @@ def test_failureException__subclassing__explicit_raise(self): events = [] result = LoggingResult(events) - + class Foo(unittest.TestCase): def test(self): raise RuntimeError() - + failureException = RuntimeError - + self.failUnless(Foo('test').failureException is RuntimeError) - - + + Foo('test').run(result) expected = ['startTest', 'addFailure', 'stopTest'] self.assertEqual(events, expected) - + # "This class attribute gives the exception raised by the test() method. # If a test framework needs to use a specialized exception, possibly to # carry additional information, it must subclass this exception in @@ -2194,38 +2194,38 @@ def test_failureException__subclassing__implicit_raise(self): events = [] result = LoggingResult(events) - + class Foo(unittest.TestCase): def test(self): self.fail("foo") - + failureException = RuntimeError - + self.failUnless(Foo('test').failureException is RuntimeError) - - + + Foo('test').run(result) expected = ['startTest', 'addFailure', 'stopTest'] self.assertEqual(events, expected) - - # "The default implementation does nothing." + + # "The default implementation does nothing." def test_setUp(self): class Foo(unittest.TestCase): def runTest(self): pass - + # ... and nothing should happen Foo().setUp() - - # "The default implementation does nothing." + + # "The default implementation does nothing." def test_tearDown(self): class Foo(unittest.TestCase): def runTest(self): pass - + # ... and nothing should happen Foo().tearDown() - + # "Return a string identifying the specific test case." # # Because of the vague nature of the docs, I'm not going to lock this @@ -2236,57 +2236,57 @@ class Foo(unittest.TestCase): def runTest(self): pass - + self.failUnless(isinstance(Foo().id(), basestring)) - + # "Returns a one-line description of the test, or None if no description # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." + # the first line of the test method's docstring, if available, or None." def test_shortDescription__no_docstring(self): class Foo(unittest.TestCase): def runTest(self): pass - + self.assertEqual(Foo().shortDescription(), None) - + # "Returns a one-line description of the test, or None if no description # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." + # the first line of the test method's docstring, if available, or None." def test_shortDescription__singleline_docstring(self): class Foo(unittest.TestCase): def runTest(self): "this tests foo" pass - + self.assertEqual(Foo().shortDescription(), "this tests foo") - + # "Returns a one-line description of the test, or None if no description # has been provided. The default implementation of this method returns - # the first line of the test method's docstring, if available, or None." + # the first line of the test method's docstring, if available, or None." def test_shortDescription__multiline_docstring(self): class Foo(unittest.TestCase): def runTest(self): """this tests foo blah, bar and baz are also tested""" pass - + self.assertEqual(Foo().shortDescription(), "this tests foo") - + # "If result is omitted or None, a temporary result object is created - # and used, but is not made available to the caller" + # and used, but is not made available to the caller" def test_run__uses_defaultTestResult(self): events = [] - + class Foo(unittest.TestCase): def test(self): events.append('test') - + def defaultTestResult(self): return LoggingResult(events) - - # Make run() find a result object on its own + + # Make run() find a result object on its own Foo('test').run() - + expected = ['startTest', 'test', 'stopTest'] self.assertEqual(events, expected) @@ -2299,4 +2299,4 @@ Test_TestSuite, Test_TestResult, Test_FunctionTestCase) if __name__ == "__main__": - test_main() + test_main() Modified: python/trunk/Lib/test/test_zipfile.py ============================================================================== --- python/trunk/Lib/test/test_zipfile.py (original) +++ python/trunk/Lib/test/test_zipfile.py Mon Mar 12 19:07:52 2007 @@ -117,12 +117,12 @@ if not read_data: break zipdata2.append(read_data) - + self.assertEqual(''.join(zipdata1), self.data) self.assertEqual(''.join(zipdata2), self.data) zipfp.close() - - def testOpenStored(self): + + def testOpenStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipOpenTest(f, zipfile.ZIP_STORED) @@ -141,11 +141,11 @@ self.assertEqual(''.join(zipdata1), self.data) zipfp.close() - - def testRandomOpenStored(self): + + def testRandomOpenStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipRandomOpenTest(f, zipfile.ZIP_STORED) - + def zipReadlineTest(self, f, compression): self.makeTestArchive(f, compression) @@ -178,16 +178,16 @@ self.assertEqual(zipline, line + '\n') zipfp.close() - - def testReadlineStored(self): + + def testReadlineStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipReadlineTest(f, zipfile.ZIP_STORED) - def testReadlinesStored(self): + def testReadlinesStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipReadlinesTest(f, zipfile.ZIP_STORED) - def testIterlinesStored(self): + def testIterlinesStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipIterlinesTest(f, zipfile.ZIP_STORED) @@ -204,18 +204,18 @@ for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipRandomOpenTest(f, zipfile.ZIP_DEFLATED) - def testReadlineDeflated(self): + def testReadlineDeflated(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipReadlineTest(f, zipfile.ZIP_DEFLATED) - def testReadlinesDeflated(self): + def testReadlinesDeflated(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipReadlinesTest(f, zipfile.ZIP_DEFLATED) - def testIterlinesDeflated(self): + def testIterlinesDeflated(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipIterlinesTest(f, zipfile.ZIP_DEFLATED) - + def testLowCompression(self): # Checks for cases where compressed data is larger than original # Create the ZIP archive @@ -437,10 +437,10 @@ def testCreateNonExistentFileForAppend(self): if os.path.exists(TESTFN): os.unlink(TESTFN) - + filename = 'testfile.txt' content = 'hello, world. this is some content.' - + try: zf = zipfile.ZipFile(TESTFN, 'a') zf.writestr(filename, content) @@ -453,9 +453,9 @@ zf = zipfile.ZipFile(TESTFN, 'r') self.assertEqual(zf.read(filename), content) zf.close() - + os.unlink(TESTFN) - + def testCloseErroneousFile(self): # This test checks that the ZipFile constructor closes the file object # it opens if there's an error in the file. If it doesn't, the traceback @@ -472,24 +472,24 @@ os.unlink(TESTFN) def testIsZipErroneousFile(self): - # This test checks that the is_zipfile function correctly identifies + # This test checks that the is_zipfile function correctly identifies # a file that is not a zip file fp = open(TESTFN, "w") fp.write("this is not a legal zip file\n") fp.close() - chk = zipfile.is_zipfile(TESTFN) + chk = zipfile.is_zipfile(TESTFN) os.unlink(TESTFN) - self.assert_(chk is False) + self.assert_(chk is False) def testIsZipValidFile(self): - # This test checks that the is_zipfile function correctly identifies + # This test checks that the is_zipfile function correctly identifies # a file that is a zip file zipf = zipfile.ZipFile(TESTFN, mode="w") zipf.writestr("foo.txt", "O, for a Muse of Fire!") zipf.close() - chk = zipfile.is_zipfile(TESTFN) + chk = zipfile.is_zipfile(TESTFN) os.unlink(TESTFN) - self.assert_(chk is True) + self.assert_(chk is True) def testNonExistentFileRaisesIOError(self): # make sure we don't raise an AttributeError when a partially-constructed @@ -552,7 +552,7 @@ def testBadPassword(self): self.zip.setpassword("perl") self.assertRaises(RuntimeError, self.zip.read, "test.txt") - + def testGoodPassword(self): self.zip.setpassword("python") self.assertEquals(self.zip.read("test.txt"), self.plain) @@ -589,7 +589,7 @@ def testStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipTest(f, zipfile.ZIP_STORED) - + def zipOpenTest(self, f, compression): self.makeTestArchive(f, compression) @@ -610,17 +610,17 @@ if not read_data: break zipdata2.append(read_data) - - testdata1 = ''.join(zipdata1) + + testdata1 = ''.join(zipdata1) self.assertEqual(len(testdata1), len(self.data)) self.assertEqual(testdata1, self.data) - testdata2 = ''.join(zipdata2) + testdata2 = ''.join(zipdata2) self.assertEqual(len(testdata1), len(self.data)) self.assertEqual(testdata1, self.data) zipfp.close() - - def testOpenStored(self): + + def testOpenStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipOpenTest(f, zipfile.ZIP_STORED) @@ -641,8 +641,8 @@ self.assertEqual(len(testdata), len(self.data)) self.assertEqual(testdata, self.data) zipfp.close() - - def testRandomOpenStored(self): + + def testRandomOpenStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.zipRandomOpenTest(f, zipfile.ZIP_STORED) @@ -653,7 +653,7 @@ zipfp.writestr('ones', '1'*FIXEDTEST_SIZE) zipfp.writestr('twos', '2'*FIXEDTEST_SIZE) zipfp.close() - + def testSameFile(self): # Verify that (when the ZipFile is in control of creating file objects) # multiple open() calls can be made without interfering with each other. @@ -694,10 +694,10 @@ self.assertEqual(data1, '1'*FIXEDTEST_SIZE) self.assertEqual(data2, '2'*FIXEDTEST_SIZE) zipf.close() - + def tearDown(self): os.remove(TESTFN2) - + class UniversalNewlineTests(unittest.TestCase): def setUp(self): @@ -726,7 +726,7 @@ self.assertEqual(self.arcdata[sep], zipdata) zipfp.close() - + def readlineTest(self, f, compression): self.makeTestArchive(f, compression) @@ -763,36 +763,36 @@ zipfp.close() - def testReadStored(self): + def testReadStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.readTest(f, zipfile.ZIP_STORED) - - def testReadlineStored(self): + + def testReadlineStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.readlineTest(f, zipfile.ZIP_STORED) - def testReadlinesStored(self): + def testReadlinesStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.readlinesTest(f, zipfile.ZIP_STORED) - def testIterlinesStored(self): + def testIterlinesStored(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.iterlinesTest(f, zipfile.ZIP_STORED) - + if zlib: - def testReadDeflated(self): + def testReadDeflated(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.readTest(f, zipfile.ZIP_DEFLATED) - def testReadlineDeflated(self): + def testReadlineDeflated(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.readlineTest(f, zipfile.ZIP_DEFLATED) - def testReadlinesDeflated(self): + def testReadlinesDeflated(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.readlinesTest(f, zipfile.ZIP_DEFLATED) - def testIterlinesDeflated(self): + def testIterlinesDeflated(self): for f in (TESTFN2, TemporaryFile(), StringIO()): self.iterlinesTest(f, zipfile.ZIP_DEFLATED) @@ -802,8 +802,8 @@ def test_main(): - run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests, - PyZipFileTests, DecryptionTests, TestsWithMultipleOpens, + run_unittest(TestsWithSourceFile, TestZip64InSmallFiles, OtherTests, + PyZipFileTests, DecryptionTests, TestsWithMultipleOpens, UniversalNewlineTests, TestsWithRandomBinaryFiles) #run_unittest(TestZip64InSmallFiles) Modified: python/trunk/Lib/urllib2.py ============================================================================== --- python/trunk/Lib/urllib2.py (original) +++ python/trunk/Lib/urllib2.py Mon Mar 12 19:07:52 2007 @@ -30,7 +30,7 @@ install_opener -- Installs a new opener as the default opener. objects of interest: -OpenerDirector -- +OpenerDirector -- Request -- An object that encapsulates the state of a request. The state can be as simple as the URL. It can also include extra HTTP Modified: python/trunk/Lib/zipfile.py ============================================================================== --- python/trunk/Lib/zipfile.py (original) +++ python/trunk/Lib/zipfile.py Mon Mar 12 19:07:52 2007 @@ -357,9 +357,9 @@ class ZipExtFile: """File-like object for reading an archive member. - Is returned by ZipFile.open(). + Is returned by ZipFile.open(). """ - + def __init__(self, fileobj, zipinfo, decrypt=None): self.fileobj = fileobj self.decrypter = decrypt @@ -374,7 +374,7 @@ self.compress_type = zipinfo.compress_type self.compress_size = zipinfo.compress_size - + self.closed = False self.mode = "r" self.name = zipinfo.filename @@ -386,7 +386,7 @@ def set_univ_newlines(self, univ_newlines): self.univ_newlines = univ_newlines - + # pick line separator char(s) based on universal newlines flag self.nlSeps = ("\n", ) if self.univ_newlines: @@ -394,7 +394,7 @@ def __iter__(self): return self - + def next(self): nextline = self.readline() if not nextline: @@ -414,17 +414,17 @@ if (self.lastdiscard, self.linebuffer[0]) == ('\r','\n'): self.linebuffer = self.linebuffer[1:] - for sep in self.nlSeps: + for sep in self.nlSeps: nl = self.linebuffer.find(sep) if nl >= 0: nllen = len(sep) return nl, nllen return nl, nllen - + def readline(self, size = -1): """Read a line with approx. size. If size is negative, - read a whole line. + read a whole line. """ if size < 0: size = sys.maxint @@ -433,7 +433,7 @@ # check for a newline already in buffer nl, nllen = self._checkfornewline() - + if nl >= 0: # the next line was already in the buffer nl = min(nl, size) @@ -449,7 +449,7 @@ # check for a newline in buffer nl, nllen = self._checkfornewline() - + # we either ran out of bytes in the file, or # met the specified size limit without finding a newline, # so return current buffer @@ -528,8 +528,8 @@ newdata = self.dc.decompress(newdata) self.rawbuffer = self.dc.unconsumed_tail if self.eof and len(self.rawbuffer) == 0: - # we're out of raw bytes (both from the file and - # the local buffer); flush just to make sure the + # we're out of raw bytes (both from the file and + # the local buffer); flush just to make sure the # decompressor is done newdata += self.dc.flush() # prevent decompressor from being used again @@ -547,7 +547,7 @@ self.readbuffer = self.readbuffer[size:] return bytes - + class ZipFile: """ Class with methods to open, read, write, close, list zip files. @@ -738,7 +738,7 @@ raise RuntimeError, \ "Attempt to read ZIP archive that was already closed" - # Only open a new file for instances where we were not + # Only open a new file for instances where we were not # given a file object in the constructor if self._filePassed: zef_file = self.fp From python-checkins at python.org Mon Mar 12 19:09:26 2007 From: python-checkins at python.org (tim.peters) Date: Mon, 12 Mar 2007 19:09:26 +0100 (CET) Subject: [Python-checkins] r54297 - in python/trunk: Doc/ext/shoddy.c Lib/collections.py Lib/test/test_collections.py Message-ID: <20070312180926.0DA091E4003@bag.python.org> Author: tim.peters Date: Mon Mar 12 19:09:22 2007 New Revision: 54297 Modified: python/trunk/Doc/ext/shoddy.c (props changed) python/trunk/Lib/collections.py (props changed) python/trunk/Lib/test/test_collections.py (props changed) Log: Set missing svn:eol-style property on text files. From python-checkins at python.org Mon Mar 12 19:19:06 2007 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 12 Mar 2007 19:19:06 +0100 (CET) Subject: [Python-checkins] r54298 - sandbox/trunk/2to3/README Message-ID: <20070312181906.C636F1E4003@bag.python.org> Author: guido.van.rossum Date: Mon Mar 12 19:19:03 2007 New Revision: 54298 Modified: sandbox/trunk/2to3/README Log: Update to clarify what's here and authorship. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Mon Mar 12 19:19:03 2007 @@ -5,11 +5,13 @@ Files: README - this file +refactor.py - main program; use this to test.py - runs all unittests for 2to3 patcomp.py - pattern compiler pytree.py - parse tree nodes (not specific to Python, despite the name!) pygram.py - code specific to the Python grammar example.py - example input for play.py and fix_*.py +find_pattern.py - script to help determining the PATTERN for a new fix Grammar.txt - Python grammar input (a copy of Python 2.5's Grammar/Grammar) Grammar.pickle - pickled grammar tables (generated file, not in subversion) PatternGrammar.txt - grammar for the pattern language used by patcomp.py @@ -27,7 +29,10 @@ (2) I developed pgen2 while I was at Elemental Security. I modified it while at Google to suit the needs of this refactoring tool. -All new code I wrote here is copyrighted by Google, licensed to the -PSF under a contributor agreement. +The original pgen2 module is copyrighted by Elemental Security. All +new code I wrote specifically for this tool is copyrighted by Google. +New code by others (notably Collin Winter) is copyrighted by the +respective authors. All code (whether by me or by others) is licensed +to the PSF under a contributor agreement. --Guido van Rossum From python-checkins at python.org Mon Mar 12 19:24:39 2007 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 12 Mar 2007 19:24:39 +0100 (CET) Subject: [Python-checkins] r54299 - sandbox/trunk/2to3/fixes/fix_dict2.py Message-ID: <20070312182439.6AA001E400F@bag.python.org> Author: guido.van.rossum Date: Mon Mar 12 19:24:37 2007 New Revision: 54299 Removed: sandbox/trunk/2to3/fixes/fix_dict2.py Log: Deleting the dict2 fixer. It's an attractive nuisance that has done enough damage. Deleted: /sandbox/trunk/2to3/fixes/fix_dict2.py ============================================================================== --- /sandbox/trunk/2to3/fixes/fix_dict2.py Mon Mar 12 19:24:37 2007 +++ (empty file) @@ -1,34 +0,0 @@ -# Copyright 2007 Google, Inc. All Rights Reserved. - -"""Fixer for dict methods, take 2. - -This is less correct but more pragmatic. - -.iterkeys -> .keys -.iteritems -> .items -.itervalues -> .values -""" - -# Local imports -import pytree -from pgen2 import token -from fixes import basefix -from fixes import macros - -class FixDict2(basefix.BaseFix): - - PATTERN = """ - trailer< '.' method=('iterkeys'|'iteritems'|'itervalues') > - """ - - def transform(self, node): - results = self.match(node) - method = results["method"][0].value # Extract method name - assert method.startswith("iter") - newmethod = method[4:] - new = pytree.Node(self.syms.trailer, - [pytree.Leaf(token.DOT, '.'), - macros.Name(newmethod)]) - new.set_prefix(node.get_prefix()) - new.children[1].set_prefix(node.children[1].get_prefix()) - return new From python-checkins at python.org Mon Mar 12 19:26:03 2007 From: python-checkins at python.org (guido.van.rossum) Date: Mon, 12 Mar 2007 19:26:03 +0100 (CET) Subject: [Python-checkins] r54300 - in sandbox/trunk/2to3: test.py tests/support.py Message-ID: <20070312182603.685D01E4003@bag.python.org> Author: guido.van.rossum Date: Mon Mar 12 19:26:00 2007 New Revision: 54300 Modified: sandbox/trunk/2to3/test.py (contents, props changed) sandbox/trunk/2to3/tests/support.py Log: Make test.py executable. Clean up some whitespace. Modified: sandbox/trunk/2to3/test.py ============================================================================== --- sandbox/trunk/2to3/test.py (original) +++ sandbox/trunk/2to3/test.py Mon Mar 12 19:26:00 2007 @@ -1,5 +1,9 @@ -"""Main test file for 2to3. Running "python test.py" will run all -tests in tests/test_*.py.""" +#!/usr/bin/env python2.5 + +"""Main test file for 2to3. + +Running "python test.py" will run all tests in tests/test_*.py. +""" # Author: Collin Winter import tests Modified: sandbox/trunk/2to3/tests/support.py ============================================================================== --- sandbox/trunk/2to3/tests/support.py (original) +++ sandbox/trunk/2to3/tests/support.py Mon Mar 12 19:26:00 2007 @@ -18,7 +18,7 @@ parent_dir = os.path.split(sys.path[0])[0] sys.path = [parent_dir] + sys.path - + skip_whitespace = re.compile(r"""\S""") def reformat(string): indent = re.search(skip_whitespace, string).start() From python-checkins at python.org Mon Mar 12 20:07:19 2007 From: python-checkins at python.org (erik.forsberg) Date: Mon, 12 Mar 2007 20:07:19 +0100 (CET) Subject: [Python-checkins] r54301 - tracker/roundup-src/roundup/mailgw.py Message-ID: <20070312190719.19B0F1E4003@bag.python.org> Author: erik.forsberg Date: Mon Mar 12 20:07:15 2007 New Revision: 54301 Modified: tracker/roundup-src/roundup/mailgw.py Log: Modified message about not being registered to include registration address. Fixes http://psf.upfronthosting.co.za/roundup/meta/issue90. Modified: tracker/roundup-src/roundup/mailgw.py ============================================================================== --- tracker/roundup-src/roundup/mailgw.py (original) +++ tracker/roundup-src/roundup/mailgw.py Mon Mar 12 20:07:15 2007 @@ -882,8 +882,13 @@ if author == anonid: # we're anonymous and we need to be a registered user from_address = from_list[0][1] + tracker_web = self.instance.config.TRACKER_WEB raise Unauthorized, _(""" -You are not a registered user. +You are not a registered user. Please register at: + +%(tracker_web)suser?@template=register + +...before sending mail to the tracker. Unknown address: %(from_address)s """) % locals() From buildbot at python.org Mon Mar 12 20:17:06 2007 From: buildbot at python.org (buildbot at python.org) Date: Mon, 12 Mar 2007 19:17:06 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP-2 trunk Message-ID: <20070312191706.4EC1F1E4003@bag.python.org> The Buildbot has detected a new failure of x86 XP-2 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP-2%2520trunk/builds/1 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: tim.peters Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl sincerely, -The Buildbot From python-checkins at python.org Mon Mar 12 20:51:55 2007 From: python-checkins at python.org (erik.forsberg) Date: Mon, 12 Mar 2007 20:51:55 +0100 (CET) Subject: [Python-checkins] r54302 - tracker/instances/python-dev/html/page.html tracker/instances/python-dev/html/style.css Message-ID: <20070312195155.AA0581E4003@bag.python.org> Author: erik.forsberg Date: Mon Mar 12 20:51:51 2007 New Revision: 54302 Modified: tracker/instances/python-dev/html/page.html tracker/instances/python-dev/html/style.css Log: Add warning about tracker not being in production. Fixes http://psf.upfronthosting.co.za/roundup/meta/issue86. Modified: tracker/instances/python-dev/html/page.html ============================================================================== --- tracker/instances/python-dev/html/page.html (original) +++ tracker/instances/python-dev/html/page.html Mon Mar 12 20:51:51 2007 @@ -25,7 +25,16 @@ ">

-

+ + + +
This tracker is not yet in production + use. Use SourceForge + to report bugs for the time being
+ +
Modified: tracker/instances/python-dev/html/style.css ============================================================================== --- tracker/instances/python-dev/html/style.css (original) +++ tracker/instances/python-dev/html/style.css Mon Mar 12 20:51:51 2007 @@ -452,3 +452,11 @@ } +#demowarning { + position: absolute; + top: 10px; + left: 260px; + font-weight: bold; + font-size: 110%; + color: red; +} From python-checkins at python.org Mon Mar 12 21:12:39 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 21:12:39 +0100 (CET) Subject: [Python-checkins] r54303 - in sandbox/trunk/2to3: fixes/basefix.py refactor.py tests/test_fixers.py Message-ID: <20070312201239.D03821E4006@bag.python.org> Author: collin.winter Date: Mon Mar 12 21:12:38 2007 New Revision: 54303 Modified: sandbox/trunk/2to3/fixes/basefix.py sandbox/trunk/2to3/refactor.py sandbox/trunk/2to3/tests/test_fixers.py Log: Add start_tree() and finish_tree() methods to BaseFix to make it easier for fixers to maintain tree-wide state. Also, make numbers a fixer attribute (instead of a global), using start_tree() to initialize it. This has the advantage that tests that rely on new_name() are no longer dependent on test order. Modified: sandbox/trunk/2to3/fixes/basefix.py ============================================================================== --- sandbox/trunk/2to3/fixes/basefix.py (original) +++ sandbox/trunk/2to3/fixes/basefix.py Mon Mar 12 21:12:38 2007 @@ -12,7 +12,6 @@ import pygram # For new_name() -numbers = itertools.count(1) class BaseFix(object): @@ -29,6 +28,7 @@ options = None # Options object passed to initializer filename = None # The filename (set by set_filename) logger = None # A logger (set by set_filename) + numbers = itertools.count(1) # For new_name() used_names = set() # A set of all used NAMEs # Shortcut for access to Python grammar symbols @@ -92,7 +92,7 @@ """ name = template while name in self.used_names: - name = template + str(numbers.next()) + name = template + str(self.numbers.next()) self.used_names.add(name) return name @@ -110,3 +110,23 @@ self.logger.warning(msg % (lineno, for_output)) if reason: self.logger.warning(reason) + + def start_tree(self, tree, filename): + """Some fixers need to maintain tree-wide state. + This method is called once, at the start of tree fix-up. + + tree - the root node of the tree to be processed. + filename - the name of the file the tree came from. + """ + self.used_names = tree.used_names + self.set_filename(filename) + self.numbers = itertools.count(1) + + def finish_tree(self, tree, filename): + """Some fixers need to maintain tree-wide state. + This method is called once, at the conclusion of tree fix-up. + + tree - the root node of the tree to be processed. + filename - the name of the file the tree came from. + """ + pass Modified: sandbox/trunk/2to3/refactor.py ============================================================================== --- sandbox/trunk/2to3/refactor.py (original) +++ sandbox/trunk/2to3/refactor.py Mon Mar 12 21:12:38 2007 @@ -216,8 +216,7 @@ def refactor_tree(self, tree, filename): """Refactors a parse tree (modifying the tree in place).""" for fixer in self.fixers: - fixer.set_filename(filename) - fixer.used_names = tree.used_names + fixer.start_tree(tree, filename) changes = 0 for node in tree.post_order(): for fixer in self.fixers: @@ -226,6 +225,8 @@ if new is not None and new != node: node.replace(new) changes += 1 + for fixer in self.fixers: + fixer.finish_tree(tree, filename) return changes def write_file(self, new_text, filename, old_text=None): Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Mon Mar 12 21:12:38 2007 @@ -17,7 +17,7 @@ import refactor # We wrap the RefactoringTool's fixer objects so we can intercept -# the call to set_filename() and so modify the fixers' logging objects. +# the call to start_tree() and so modify the fixers' logging objects. # This allows us to make sure that certain code chunks produce certain # warnings. class Fixer(object): @@ -27,9 +27,9 @@ def __getattr__(self, attr): return getattr(self.fixer, attr) - - def set_filename(self, filename): - self.fixer.set_filename(filename) + + def start_tree(self, tree, filename): + self.fixer.start_tree(tree, filename) self.fixer.logger.addHandler(self.handler) class Options: @@ -527,8 +527,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme1: - (a, b) = xxx_todo_changeme1.message + except Exception as xxx_todo_changeme: + (a, b) = xxx_todo_changeme.message pass""" self.check(b, a) @@ -542,8 +542,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme2: - d[5] = xxx_todo_changeme2 + except Exception as xxx_todo_changeme: + d[5] = xxx_todo_changeme pass""" self.check(b, a) @@ -557,8 +557,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme3: - a.foo = xxx_todo_changeme3 + except Exception as xxx_todo_changeme: + a.foo = xxx_todo_changeme pass""" self.check(b, a) @@ -572,8 +572,8 @@ a = """ try: pass - except Exception as xxx_todo_changeme4: - a().foo = xxx_todo_changeme4 + except Exception as xxx_todo_changeme: + a().foo = xxx_todo_changeme pass""" self.check(b, a) @@ -1134,8 +1134,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme5): - ((a, b), c) = xxx_todo_changeme5 + def foo(xxx_todo_changeme): + ((a, b), c) = xxx_todo_changeme x = 5""" self.check(b, a) @@ -1145,8 +1145,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme6, d): - ((a, b), c) = xxx_todo_changeme6 + def foo(xxx_todo_changeme, d): + ((a, b), c) = xxx_todo_changeme x = 5""" self.check(b, a) @@ -1156,8 +1156,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme7, d) -> e: - ((a, b), c) = xxx_todo_changeme7 + def foo(xxx_todo_changeme, d) -> e: + ((a, b), c) = xxx_todo_changeme x = 5""" self.check(b, a) @@ -1166,7 +1166,7 @@ def foo(((a, b), c)): x = 5; y = 7""" a = """ - def foo(xxx_todo_changeme15): ((a, b), c) = xxx_todo_changeme15; x = 5; y = 7""" + def foo(xxx_todo_changeme): ((a, b), c) = xxx_todo_changeme; x = 5; y = 7""" self.check(b, a) def test_keywords(self): @@ -1175,8 +1175,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme10, d, e=5) -> z: - ((a, b), c) = xxx_todo_changeme10 + def foo(xxx_todo_changeme, d, e=5) -> z: + ((a, b), c) = xxx_todo_changeme x = 5""" self.check(b, a) @@ -1186,8 +1186,8 @@ x = 5""" a = """ - def foo(xxx_todo_changeme16, d, *vargs, **kwargs) -> z: - ((a, b), c) = xxx_todo_changeme16 + def foo(xxx_todo_changeme, d, *vargs, **kwargs) -> z: + ((a, b), c) = xxx_todo_changeme x = 5""" self.check(b, a) @@ -1197,9 +1197,9 @@ x = 5""" a = """ - def foo(xxx_todo_changeme11, xxx_todo_changeme12) -> z: - ((a, b), c) = xxx_todo_changeme11 - (d, e, f) = xxx_todo_changeme12 + def foo(xxx_todo_changeme, xxx_todo_changeme1) -> z: + ((a, b), c) = xxx_todo_changeme + (d, e, f) = xxx_todo_changeme1 x = 5""" self.check(b, a) @@ -1209,9 +1209,9 @@ x = 5""" a = """ - def foo(x, xxx_todo_changeme13, d, xxx_todo_changeme14, y) -> z: - ((a, b), c) = xxx_todo_changeme13 - (e, f, g) = xxx_todo_changeme14 + def foo(x, xxx_todo_changeme, d, xxx_todo_changeme1, y) -> z: + ((a, b), c) = xxx_todo_changeme + (e, f, g) = xxx_todo_changeme1 x = 5""" self.check(b, a) @@ -1222,10 +1222,10 @@ x = 5""" a = """ - def foo(xxx_todo_changeme8, xxx_todo_changeme9) -> z: + def foo(xxx_todo_changeme, xxx_todo_changeme1) -> z: "foo foo foo foo" - ((a, b), c) = xxx_todo_changeme8 - (d, e, f) = xxx_todo_changeme9 + ((a, b), c) = xxx_todo_changeme + (d, e, f) = xxx_todo_changeme1 x = 5""" self.check(b, a) From python-checkins at python.org Mon Mar 12 21:14:04 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 21:14:04 +0100 (CET) Subject: [Python-checkins] r54304 - sandbox/trunk/2to3/fixes/basefix.py Message-ID: <20070312201404.C17BE1E400B@bag.python.org> Author: collin.winter Date: Mon Mar 12 21:14:03 2007 New Revision: 54304 Modified: sandbox/trunk/2to3/fixes/basefix.py Log: Add a BaseFix.warning() method to go with cannot_convert(). Modified: sandbox/trunk/2to3/fixes/basefix.py ============================================================================== --- sandbox/trunk/2to3/fixes/basefix.py (original) +++ sandbox/trunk/2to3/fixes/basefix.py Mon Mar 12 21:14:03 2007 @@ -110,6 +110,16 @@ self.logger.warning(msg % (lineno, for_output)) if reason: self.logger.warning(reason) + + def warning(self, node, reason): + """Used for warning the user about possible uncertainty in the + translation. + + First argument is the top-level node for the code in question. + Optional second argument is why it can't be converted. + """ + lineno = node.get_lineno() + self.logger.warning("At line %d: %s" % (lineno, reason)) def start_tree(self, tree, filename): """Some fixers need to maintain tree-wide state. From python-checkins at python.org Mon Mar 12 21:24:37 2007 From: python-checkins at python.org (erik.forsberg) Date: Mon, 12 Mar 2007 21:24:37 +0100 (CET) Subject: [Python-checkins] r54305 - tracker/instances/python-dev/html/page.html Message-ID: <20070312202437.409F91E4003@bag.python.org> Author: erik.forsberg Date: Mon Mar 12 21:24:32 2007 New Revision: 54305 Modified: tracker/instances/python-dev/html/page.html Log: Changed name of 'Show All' to 'Show Open', which I think is enough to fix http://psf.upfronthosting.co.za/roundup/meta/issue25. Modified: tracker/instances/python-dev/html/page.html ============================================================================== --- tracker/instances/python-dev/html/page.html (original) +++ tracker/instances/python-dev/html/page.html Mon Mar 12 21:24:32 2007 @@ -61,25 +61,25 @@ tal:attributes="href python:request.indexargs_url('issue', { '@sort': '-activity', '@group': 'severity', - '@filter': 'status,assignee', - '@columns': columns, + '@filter': 'status', + '@columns': columns_showall, '@search_text': '', 'status': status_notresolved, - 'assignee': '-1', - '@dispname': i18n.gettext('Show Unassigned'), + '@dispname': i18n.gettext('Show All'), })" - i18n:translate="">Show Unassigned + i18n:translate="">Show Open
  • Show All
  • + i18n:translate="">Show Unassigned
  • Search
  • From python-checkins at python.org Mon Mar 12 21:44:57 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 21:44:57 +0100 (CET) Subject: [Python-checkins] r54306 - sandbox/trunk/2to3/README Message-ID: <20070312204457.56E511E4003@bag.python.org> Author: collin.winter Date: Mon Mar 12 21:44:53 2007 New Revision: 54306 Modified: sandbox/trunk/2to3/README Log: Add a 'limitations' section, reformat in rest. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Mon Mar 12 21:44:53 2007 @@ -1,8 +1,13 @@ +Abstract +======== + A refactoring tool for converting Python 2.x code to 3.0. This is a work in progress! -Files: + +Files +===== README - this file refactor.py - main program; use this to @@ -11,23 +16,87 @@ pytree.py - parse tree nodes (not specific to Python, despite the name!) pygram.py - code specific to the Python grammar example.py - example input for play.py and fix_*.py -find_pattern.py - script to help determining the PATTERN for a new fix +find_pattern.py - script to help determine the PATTERN for a new fix Grammar.txt - Python grammar input (a copy of Python 2.5's Grammar/Grammar) Grammar.pickle - pickled grammar tables (generated file, not in subversion) PatternGrammar.txt - grammar for the pattern language used by patcomp.py PatternGrammar.pickle - pickled pattern grammar tables (generated file) -pgen2/ - Parser generator and driver (1) (2) +pgen2/ - Parser generator and driver ([1]_, [2]_) fixes/ - Individual transformations tests/ - Test files for pytree, fixers, grammar, etc -Notes: +Limitations +=========== + +General Limitations +------------------- + +In general, fixers that convert a function or method call will not detect +something like :: + + a = apply + a(f, *args) + +or :: + + m = d.has_key + if m(5): + ... + + +Caveats for Specific Fixers +--------------------------- + +fix_except +'''''''''' + +"except" statements like :: + + except Exception, (a, b): + ... + +are not fixed up. The ability to treat exceptions as sequences is being +removed in Python 3, so there is no straightforward, automatic way to +adjust these statements. + +This is seen frequently when dealing with OSError. + + +fix_has_key +''''''''''' + +While the primary target of this fixer is dict.has_key(), the +fixer will change any has_key() method call, regardless of what class it +belongs to. Anyone using non-dictionary classes with has_key() methods is +advised to pay close attention when using this fixer. + + +fix_raise +''''''''' + +"raise E, V" will be incorrectly translated if V is an exception instance. +The correct Python 3 idiom is :: + + raise E from V + +but since we can't detect instance-hood by syntax alone and since any client +code would have to be changed as well, we don't automate this. + + +Notes +===== + +.. [#1] I modified tokenize.py to yield a NL pseudo-token for backslash + continuations, so the original source can be reproduced exactly. + The modified version can be found at pgen2/tokenize.py. + +.. [#2] I developed pgen2 while I was at Elemental Security. I modified + it while at Google to suit the needs of this refactoring tool. + -(1) I modified tokenize.py to yield a NL pseudo-token for backslash - continuations, so the original source can be reproduced exactly. - The modified version can be found at pgen2/tokenize.py. -(2) I developed pgen2 while I was at Elemental Security. I modified - it while at Google to suit the needs of this refactoring tool. +Licensing +========= The original pgen2 module is copyrighted by Elemental Security. All new code I wrote specifically for this tool is copyrighted by Google. From python-checkins at python.org Mon Mar 12 21:53:15 2007 From: python-checkins at python.org (erik.forsberg) Date: Mon, 12 Mar 2007 21:53:15 +0100 (CET) Subject: [Python-checkins] r54307 - tracker/instances/python-dev/html/page.html Message-ID: <20070312205315.E82291E4003@bag.python.org> Author: erik.forsberg Date: Mon Mar 12 21:53:11 2007 New Revision: 54307 Modified: tracker/instances/python-dev/html/page.html Log: Added quick-search box. Resolves http://psf.upfronthosting.co.za/roundup/meta/issue89. Modified: tracker/instances/python-dev/html/page.html ============================================================================== --- tracker/instances/python-dev/html/page.html (original) +++ tracker/instances/python-dev/html/page.html Mon Mar 12 21:53:11 2007 @@ -30,10 +30,27 @@ alt="homepage" border="0" id="logo" />
    This tracker is not yet in production - use. Use SourceForge + use.
    + Use SourceForge to report bugs for the time being
    +
    + + +
    +
    From python-checkins at python.org Mon Mar 12 22:01:46 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 22:01:46 +0100 (CET) Subject: [Python-checkins] r54308 - sandbox/trunk/2to3/README Message-ID: <20070312210146.C6B141E4003@bag.python.org> Author: collin.winter Date: Mon Mar 12 22:01:45 2007 New Revision: 54308 Modified: sandbox/trunk/2to3/README Log: Add a 'capabilities' section. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Mon Mar 12 22:01:45 2007 @@ -26,6 +26,49 @@ tests/ - Test files for pytree, fixers, grammar, etc +Capabilities +============ + +A quick run-through of 2to3's current fixers: + +* **fix_apply** - convert apply() calls to real function calls. + +* **fix_dict** - fix up dict.keys(), .values(), .items() and their iterator + versions. + +* **fix_except** - adjust "except" statements to Python 3 syntax. + +* **fix_exec** - convert "exec" statements to exec() function calls. + +* **fix_has_key** - "d.has_key(x)" -> "x in d". + +* **fix_input** - "input()" -> "eval(input())". + +* **fix_intern** - "intern(x)" -> "sys.intern(x)". + +* **fix_long** - remove all usage of explicit longs in favor of ints. + +* **fix_ne** - convert the "<>" operator to "!=". + +* **fix_print** - convert "print" statements to print() function calls. + +* **fix_raise** - convert "raise" statements to Python 3 syntax. + +* **fix_raw_input** - "raw_input()" -> "input()". + +* **fix_repr** - swap backticks for repr() calls. + +* **fix_sysexcinfo** - warn on usage of sys.value, sys.type and + sys.traceback. + +* **fix_throw** - fix generator.throw() calls to be 3.0-compliant. + +* **fix_tuple_params** - remove tuple parameters from function and method + declarations. + +* **fix_xrange** - "xrange()" -> "range()". + + Limitations =========== From python-checkins at python.org Mon Mar 12 22:03:24 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 12 Mar 2007 22:03:24 +0100 (CET) Subject: [Python-checkins] r54309 - sandbox/trunk/2to3/README Message-ID: <20070312210324.53E011E4003@bag.python.org> Author: collin.winter Date: Mon Mar 12 22:03:23 2007 New Revision: 54309 Modified: sandbox/trunk/2to3/README Log: Add additional limitation info. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Mon Mar 12 22:03:23 2007 @@ -75,17 +75,23 @@ General Limitations ------------------- -In general, fixers that convert a function or method call will not detect -something like :: +* In general, fixers that convert a function or method call will not detect + something like :: - a = apply - a(f, *args) + a = apply + a(f, *args) -or :: + or :: - m = d.has_key - if m(5): - ... + m = d.has_key + if m(5): + ... + +* Fixers that look for attribute references will not detect when getattr() or + setattr() are used to access those attributes. + +* The contents of eval() calls and "exec" statements will not be checked by + 2to3. Caveats for Specific Fixers From python-checkins at python.org Mon Mar 12 22:14:27 2007 From: python-checkins at python.org (erik.forsberg) Date: Mon, 12 Mar 2007 22:14:27 +0100 (CET) Subject: [Python-checkins] r54310 - tracker/instances/python-dev/html/page.html Message-ID: <20070312211427.69D4E1E4003@bag.python.org> Author: erik.forsberg Date: Mon Mar 12 22:14:24 2007 New Revision: 54310 Modified: tracker/instances/python-dev/html/page.html Log: Don't show closed items when searching with quick-search box. Use the same grouping, sorting and columns as 'show open' and 'show all' menu items. Re-resolves http://psf.upfronthosting.co.za/roundup/meta/issue89. Modified: tracker/instances/python-dev/html/page.html ============================================================================== --- tracker/instances/python-dev/html/page.html (original) +++ tracker/instances/python-dev/html/page.html Mon Mar 12 22:14:24 2007 @@ -40,9 +40,11 @@
    -Copyright © 1990-2006, Python Software Foundation
    -Legal Statements +Copyright © 1990-2006, Python Software Foundation
    +Legal Statements
    From python-checkins at python.org Wed Mar 14 21:02:39 2007 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 14 Mar 2007 21:02:39 +0100 (CET) Subject: [Python-checkins] r54386 - in python/trunk: Lib/test/test_cmd_line.py Misc/NEWS Message-ID: <20070314200239.1E5131E400B@bag.python.org> Author: martin.v.loewis Date: Wed Mar 14 21:02:31 2007 New Revision: 54386 Modified: python/trunk/Lib/test/test_cmd_line.py python/trunk/Misc/NEWS Log: Patch #1559413: Fix test_cmd_line if sys.executable contains a space. Will backport. Modified: python/trunk/Lib/test/test_cmd_line.py ============================================================================== --- python/trunk/Lib/test/test_cmd_line.py (original) +++ python/trunk/Lib/test/test_cmd_line.py Wed Mar 14 21:02:31 2007 @@ -6,7 +6,7 @@ class CmdLineTest(unittest.TestCase): def start_python(self, cmd_line): - outfp, infp = popen2.popen4('%s %s' % (sys.executable, cmd_line)) + outfp, infp = popen2.popen4('"%s" %s' % (sys.executable, cmd_line)) infp.close() data = outfp.read() outfp.close() Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 14 21:02:31 2007 @@ -624,6 +624,8 @@ Tests ----- +- Patch #1559413: Fix test_cmd_line if sys.executable contains a space. + - Added test.test_support.TransientResource which is a context manager to surround calls to resources that are not guaranteed to work even if test.test_support.requires says that the resource should exist. From python-checkins at python.org Wed Mar 14 21:02:40 2007 From: python-checkins at python.org (martin.v.loewis) Date: Wed, 14 Mar 2007 21:02:40 +0100 (CET) Subject: [Python-checkins] r54387 - in python/branches/release25-maint: Lib/test/test_cmd_line.py Misc/NEWS Message-ID: <20070314200240.E90781E400D@bag.python.org> Author: martin.v.loewis Date: Wed Mar 14 21:02:38 2007 New Revision: 54387 Modified: python/branches/release25-maint/Lib/test/test_cmd_line.py python/branches/release25-maint/Misc/NEWS Log: Patch #1559413: Fix test_cmd_line if sys.executable contains a space. Modified: python/branches/release25-maint/Lib/test/test_cmd_line.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_cmd_line.py (original) +++ python/branches/release25-maint/Lib/test/test_cmd_line.py Wed Mar 14 21:02:38 2007 @@ -6,7 +6,7 @@ class CmdLineTest(unittest.TestCase): def start_python(self, cmd_line): - outfp, infp = popen2.popen4('%s %s' % (sys.executable, cmd_line)) + outfp, infp = popen2.popen4('"%s" %s' % (sys.executable, cmd_line)) infp.close() data = outfp.read() outfp.close() Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Wed Mar 14 21:02:38 2007 @@ -520,6 +520,8 @@ Tests ----- +- Patch #1559413: Fix test_cmd_line if sys.executable contains a space. + - Fix bsddb test_basics.test06_Transactions to check the version number properly. From python-checkins at python.org Wed Mar 14 22:00:04 2007 From: python-checkins at python.org (erik.forsberg) Date: Wed, 14 Mar 2007 22:00:04 +0100 (CET) Subject: [Python-checkins] r54388 - in tracker/instances/python-dev: detectors/severityauditor.py html/issue.item.html Message-ID: <20070314210004.AEE991E400D@bag.python.org> Author: erik.forsberg Date: Wed Mar 14 22:00:01 2007 New Revision: 54388 Added: tracker/instances/python-dev/detectors/severityauditor.py Modified: tracker/instances/python-dev/html/issue.item.html Log: Set severity to normal if not explicitly set by submitter. In web interface, do this by preselecting the normal status. Also add auditor that will set status on issues created via mail. Fixes http://psf.upfronthosting.co.za/roundup/meta/issue93. Added: tracker/instances/python-dev/detectors/severityauditor.py ============================================================================== --- (empty file) +++ tracker/instances/python-dev/detectors/severityauditor.py Wed Mar 14 22:00:01 2007 @@ -0,0 +1,11 @@ + +def init_severity(db, cl, nodeid, newvalues): + """Make sure severity is set on new issues""" + if newvalues.has_key('severity') and newvalues['severity']: + return + + normal = db.severity.lookup('normal') + newvalues['severity'] = normal + +def init(db): + db.issue.audit('create', init_severity) Modified: tracker/instances/python-dev/html/issue.item.html ============================================================================== --- tracker/instances/python-dev/html/issue.item.html (original) +++ tracker/instances/python-dev/html/issue.item.html Wed Mar 14 22:00:01 2007 @@ -58,7 +58,14 @@ : - severity + +severity> + + severity + From buildbot at python.org Wed Mar 14 22:01:15 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 14 Mar 2007 21:01:15 +0000 Subject: [Python-checkins] buildbot warnings in S-390 Debian trunk Message-ID: <20070314210116.43AD61E400F@bag.python.org> The Buildbot has detected a new failure of S-390 Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/S-390%2520Debian%2520trunk/builds/783 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket_ssl make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Wed Mar 14 22:40:14 2007 From: python-checkins at python.org (brett.cannon) Date: Wed, 14 Mar 2007 22:40:14 +0100 (CET) Subject: [Python-checkins] r54389 - python/trunk/Misc/NEWS Message-ID: <20070314214014.078561E400B@bag.python.org> Author: brett.cannon Date: Wed Mar 14 22:40:13 2007 New Revision: 54389 Modified: python/trunk/Misc/NEWS Log: Note how test_socket_ssl has various exceptions that deal with a flaky Net connection are silenced. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 14 22:40:13 2007 @@ -624,6 +624,8 @@ Tests ----- +- Capture and silence socket connection resets and timeouts in test_socket_ssl. + - Patch #1559413: Fix test_cmd_line if sys.executable contains a space. - Added test.test_support.TransientResource which is a context manager to From python-checkins at python.org Wed Mar 14 22:44:17 2007 From: python-checkins at python.org (brett.cannon) Date: Wed, 14 Mar 2007 22:44:17 +0100 (CET) Subject: [Python-checkins] r54390 - in python/trunk: Lib/test/test_urllib2net.py Misc/NEWS Message-ID: <20070314214417.B20D31E400B@bag.python.org> Author: brett.cannon Date: Wed Mar 14 22:44:15 2007 New Revision: 54390 Modified: python/trunk/Lib/test/test_urllib2net.py python/trunk/Misc/NEWS Log: Raise ResourceDenied in test_urllib2net when the Net connection goes bad. Modified: python/trunk/Lib/test/test_urllib2net.py ============================================================================== --- python/trunk/Lib/test/test_urllib2net.py (original) +++ python/trunk/Lib/test/test_urllib2net.py Wed Mar 14 22:44:15 2007 @@ -264,7 +264,8 @@ (expected_err, url, req, err)) self.assert_(isinstance(err, expected_err), msg) else: - buf = f.read() + with test_support.transient_internet(): + buf = f.read() f.close() debug("read %d bytes" % len(buf)) debug("******** next url coming up...") Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 14 22:44:15 2007 @@ -624,7 +624,8 @@ Tests ----- -- Capture and silence socket connection resets and timeouts in test_socket_ssl. +- Capture socket connection resets and timeouts in test_socket_ssl and + test_urllib2net and raise test.test_support.ResourceDenied. - Patch #1559413: Fix test_cmd_line if sys.executable contains a space. From python-checkins at python.org Thu Mar 15 05:41:26 2007 From: python-checkins at python.org (neal.norwitz) Date: Thu, 15 Mar 2007 05:41:26 +0100 (CET) Subject: [Python-checkins] r54391 - python/trunk/Misc/NEWS Message-ID: <20070315044126.5D5A71E400D@bag.python.org> Author: neal.norwitz Date: Thu Mar 15 05:41:20 2007 New Revision: 54391 Modified: python/trunk/Misc/NEWS Log: Wrap a long line and fix a typo (is -> if) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Thu Mar 15 05:41:20 2007 @@ -305,8 +305,8 @@ - Patch 1571379: Make trace's --ignore-dir facility work in the face of relative directory names. -- Bug #1600860: Search for shared python library in LIBDIR, not lib/python/config, - on "linux" and "gnu" systems. +- Bug #1600860: Search for shared python library in LIBDIR, + not lib/python/config, on "linux" and "gnu" systems. - Patch #1652681: tarfile.py: create nonexistent files in append mode and allow appending to empty files. @@ -383,7 +383,7 @@ - Patch #1604907: Fix problems in logging.handlers caused at logging shutdown when syslog handlers fail to initialize because of syslogd problems. -- Patch #1608267: fix a race condition in os.makedirs() is the directory +- Patch #1608267: fix a race condition in os.makedirs() if the directory to be created is already there. - Patch #1610437: fix a tarfile bug with long filename headers. From python-checkins at python.org Thu Mar 15 08:38:16 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 15 Mar 2007 08:38:16 +0100 (CET) Subject: [Python-checkins] r54392 - python/trunk/Doc/lib/libthreading.tex Message-ID: <20070315073816.5B8C41E400D@bag.python.org> Author: georg.brandl Date: Thu Mar 15 08:38:14 2007 New Revision: 54392 Modified: python/trunk/Doc/lib/libthreading.tex Log: Patch #1680978: consistently use "alive" instead of "active" in the thread lib doc. Modified: python/trunk/Doc/lib/libthreading.tex ============================================================================== --- python/trunk/Doc/lib/libthreading.tex (original) +++ python/trunk/Doc/lib/libthreading.tex Thu Mar 15 08:38:14 2007 @@ -15,10 +15,9 @@ This module defines the following functions and objects: \begin{funcdesc}{activeCount}{} -Return the number of currently active \class{Thread} objects. -The returned count is equal to the length of the list returned by +Return the number of \class{Thread} objects currently alive. The +returned count is equal to the length of the list returned by \function{enumerate()}. -A function that returns the number of currently active threads. \end{funcdesc} \begin{funcdesc}{Condition}{} @@ -36,10 +35,10 @@ \end{funcdesc} \begin{funcdesc}{enumerate}{} -Return a list of all currently active \class{Thread} objects. -The list includes daemonic threads, dummy thread objects created -by \function{currentThread()}, and the main thread. It excludes terminated -threads and threads that have not yet been started. +Return a list of all \class{Thread} objects currently alive. The list +includes daemonic threads, dummy thread objects created by +\function{currentThread()}, and the main thread. It excludes +terminated threads and threads that have not yet been started. \end{funcdesc} \begin{funcdesc}{Event}{} @@ -526,12 +525,9 @@ \method{run()} method in a separate thread of control. Once the thread's activity is started, the thread is considered -'alive' and 'active' (these concepts are almost, but not quite -exactly, the same; their definition is intentionally somewhat -vague). It stops being alive and active when its \method{run()} -method terminates -- either normally, or by raising an unhandled -exception. The \method{isAlive()} method tests whether the thread is -alive. +'alive'. It stops being alive when its \method{run()} method terminates +-- either normally, or by raising an unhandled exception. The +\method{isAlive()} method tests whether the thread is alive. Other threads can call a thread's \method{join()} method. This blocks the calling thread until the thread whose \method{join()} method is @@ -551,14 +547,13 @@ initial thread of control in the Python program. It is not a daemon thread. -There is the possibility that ``dummy thread objects'' are -created. These are thread objects corresponding to ``alien -threads''. These are threads of control started outside the -threading module, such as directly from C code. Dummy thread objects -have limited functionality; they are always considered alive, -active, and daemonic, and cannot be \method{join()}ed. They are never -deleted, since it is impossible to detect the termination of alien -threads. +There is the possibility that ``dummy thread objects'' are created. +These are thread objects corresponding to ``alien threads'', which +are threads of control started outside the threading module, such as +directly from C code. Dummy thread objects have limited +functionality; they are always considered alive and daemonic, and +cannot be \method{join()}ed. They are never deleted, since it is +impossible to detect the termination of alien threads. \begin{classdesc}{Thread}{group=None, target=None, name=None, @@ -646,7 +641,8 @@ Return whether the thread is alive. Roughly, a thread is alive from the moment the \method{start()} method -returns until its \method{run()} method terminates. +returns until its \method{run()} method terminates. The module +function \function{enumerate()} returns a list of all alive threads. \end{methoddesc} \begin{methoddesc}{isDaemon}{} @@ -659,8 +655,8 @@ The initial value is inherited from the creating thread. -The entire Python program exits when no active non-daemon -threads are left. +The entire Python program exits when no alive non-daemon threads are +left. \end{methoddesc} From python-checkins at python.org Thu Mar 15 08:38:22 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 15 Mar 2007 08:38:22 +0100 (CET) Subject: [Python-checkins] r54393 - python/branches/release25-maint/Doc/lib/libthreading.tex Message-ID: <20070315073822.871F01E400D@bag.python.org> Author: georg.brandl Date: Thu Mar 15 08:38:21 2007 New Revision: 54393 Modified: python/branches/release25-maint/Doc/lib/libthreading.tex Log: Patch #1680978: consistently use "alive" instead of "active" in the thread lib doc. (backport from rev. 54392) Modified: python/branches/release25-maint/Doc/lib/libthreading.tex ============================================================================== --- python/branches/release25-maint/Doc/lib/libthreading.tex (original) +++ python/branches/release25-maint/Doc/lib/libthreading.tex Thu Mar 15 08:38:21 2007 @@ -15,10 +15,9 @@ This module defines the following functions and objects: \begin{funcdesc}{activeCount}{} -Return the number of currently active \class{Thread} objects. -The returned count is equal to the length of the list returned by +Return the number of \class{Thread} objects currently alive. The +returned count is equal to the length of the list returned by \function{enumerate()}. -A function that returns the number of currently active threads. \end{funcdesc} \begin{funcdesc}{Condition}{} @@ -36,10 +35,10 @@ \end{funcdesc} \begin{funcdesc}{enumerate}{} -Return a list of all currently active \class{Thread} objects. -The list includes daemonic threads, dummy thread objects created -by \function{currentThread()}, and the main thread. It excludes terminated -threads and threads that have not yet been started. +Return a list of all \class{Thread} objects currently alive. The list +includes daemonic threads, dummy thread objects created by +\function{currentThread()}, and the main thread. It excludes +terminated threads and threads that have not yet been started. \end{funcdesc} \begin{funcdesc}{Event}{} @@ -526,12 +525,9 @@ \method{run()} method in a separate thread of control. Once the thread's activity is started, the thread is considered -'alive' and 'active' (these concepts are almost, but not quite -exactly, the same; their definition is intentionally somewhat -vague). It stops being alive and active when its \method{run()} -method terminates -- either normally, or by raising an unhandled -exception. The \method{isAlive()} method tests whether the thread is -alive. +'alive'. It stops being alive when its \method{run()} method terminates +-- either normally, or by raising an unhandled exception. The +\method{isAlive()} method tests whether the thread is alive. Other threads can call a thread's \method{join()} method. This blocks the calling thread until the thread whose \method{join()} method is @@ -551,14 +547,13 @@ initial thread of control in the Python program. It is not a daemon thread. -There is the possibility that ``dummy thread objects'' are -created. These are thread objects corresponding to ``alien -threads''. These are threads of control started outside the -threading module, such as directly from C code. Dummy thread objects -have limited functionality; they are always considered alive, -active, and daemonic, and cannot be \method{join()}ed. They are never -deleted, since it is impossible to detect the termination of alien -threads. +There is the possibility that ``dummy thread objects'' are created. +These are thread objects corresponding to ``alien threads'', which +are threads of control started outside the threading module, such as +directly from C code. Dummy thread objects have limited +functionality; they are always considered alive and daemonic, and +cannot be \method{join()}ed. They are never deleted, since it is +impossible to detect the termination of alien threads. \begin{classdesc}{Thread}{group=None, target=None, name=None, @@ -646,7 +641,8 @@ Return whether the thread is alive. Roughly, a thread is alive from the moment the \method{start()} method -returns until its \method{run()} method terminates. +returns until its \method{run()} method terminates. The module +function \function{enumerate()} returns a list of all alive threads. \end{methoddesc} \begin{methoddesc}{isDaemon}{} @@ -659,8 +655,8 @@ The initial value is inherited from the creating thread. -The entire Python program exits when no active non-daemon -threads are left. +The entire Python program exits when no alive non-daemon threads are +left. \end{methoddesc} From python-checkins at python.org Thu Mar 15 08:41:34 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 15 Mar 2007 08:41:34 +0100 (CET) Subject: [Python-checkins] r54394 - in python/trunk: Lib/wave.py Misc/NEWS Message-ID: <20070315074134.62F571E400D@bag.python.org> Author: georg.brandl Date: Thu Mar 15 08:41:30 2007 New Revision: 54394 Modified: python/trunk/Lib/wave.py python/trunk/Misc/NEWS Log: Patch #1681153: the wave module now closes a file object it opened if initialization failed. Modified: python/trunk/Lib/wave.py ============================================================================== --- python/trunk/Lib/wave.py (original) +++ python/trunk/Lib/wave.py Thu Mar 15 08:41:30 2007 @@ -159,7 +159,12 @@ f = __builtin__.open(f, 'rb') self._i_opened_the_file = f # else, assume it is an open file object already - self.initfp(f) + try: + self.initfp(f) + except: + if self._i_opened_the_file: + f.close() + raise def __del__(self): self.close() @@ -297,7 +302,12 @@ if isinstance(f, basestring): f = __builtin__.open(f, 'wb') self._i_opened_the_file = f - self.initfp(f) + try: + self.initfp(f) + except: + if self._i_opened_the_file: + f.close() + raise def initfp(self, file): self._file = file Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Thu Mar 15 08:41:30 2007 @@ -173,6 +173,9 @@ Library ------- +- Patch #1681153: the wave module now closes a file object it opened if + initialization failed. + - Bug #767111: fix long-standing bug in urllib which caused an AttributeError instead of an IOError when the server's response didn't contain a valid HTTP status line. From python-checkins at python.org Thu Mar 15 08:42:25 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 15 Mar 2007 08:42:25 +0100 (CET) Subject: [Python-checkins] r54395 - python/branches/release25-maint/Misc/NEWS Message-ID: <20070315074225.681471E400D@bag.python.org> Author: georg.brandl Date: Thu Mar 15 08:42:22 2007 New Revision: 54395 Modified: python/branches/release25-maint/Misc/NEWS Log: Patch #1681153: the wave module now closes a file object it opened if initialization failed. (backport from rev. 54394) Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Thu Mar 15 08:42:22 2007 @@ -208,6 +208,9 @@ Library ------- +- Patch #1681153: the wave module now closes a file object it opened if + initialization failed. + - Bug #767111: fix long-standing bug in urllib which caused an AttributeError instead of an IOError when the server's response didn't contain a valid HTTP status line. From python-checkins at python.org Thu Mar 15 08:43:22 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 15 Mar 2007 08:43:22 +0100 (CET) Subject: [Python-checkins] r54396 - python/branches/release25-maint/Lib/wave.py Message-ID: <20070315074322.BC1761E400D@bag.python.org> Author: georg.brandl Date: Thu Mar 15 08:43:22 2007 New Revision: 54396 Modified: python/branches/release25-maint/Lib/wave.py Log: Also commit the patch ;) Modified: python/branches/release25-maint/Lib/wave.py ============================================================================== --- python/branches/release25-maint/Lib/wave.py (original) +++ python/branches/release25-maint/Lib/wave.py Thu Mar 15 08:43:22 2007 @@ -159,7 +159,12 @@ f = __builtin__.open(f, 'rb') self._i_opened_the_file = f # else, assume it is an open file object already - self.initfp(f) + try: + self.initfp(f) + except: + if self._i_opened_the_file: + f.close() + raise def __del__(self): self.close() @@ -297,7 +302,12 @@ if isinstance(f, basestring): f = __builtin__.open(f, 'wb') self._i_opened_the_file = f - self.initfp(f) + try: + self.initfp(f) + except: + if self._i_opened_the_file: + f.close() + raise def initfp(self, file): self._file = file From python at rcn.com Thu Mar 15 08:48:08 2007 From: python at rcn.com (Raymond Hettinger) Date: Thu, 15 Mar 2007 00:48:08 -0700 Subject: [Python-checkins] r54394 - in python/trunk: Lib/wave.py Misc/NEWS References: <20070315074134.62F571E400D@bag.python.org> Message-ID: <01e401c766d6$4699d670$f001a8c0@RaymondLaptop1> > - self.initfp(f) > + try: > + self.initfp(f) > + except: > + if self._i_opened_the_file: > + f.close() > + raise Do you really want a bare except? Would a try/finally approach work here? Raymond From g.brandl at gmx.net Thu Mar 15 08:54:21 2007 From: g.brandl at gmx.net (Georg Brandl) Date: Thu, 15 Mar 2007 08:54:21 +0100 Subject: [Python-checkins] r54394 - in python/trunk: Lib/wave.py Misc/NEWS In-Reply-To: <01e401c766d6$4699d670$f001a8c0@RaymondLaptop1> References: <20070315074134.62F571E400D@bag.python.org> <01e401c766d6$4699d670$f001a8c0@RaymondLaptop1> Message-ID: Raymond Hettinger schrieb: >> - self.initfp(f) >> + try: >> + self.initfp(f) >> + except: >> + if self._i_opened_the_file: >> + f.close() >> + raise > > Do you really want a bare except? > Would a try/finally approach work here? The file shouldn't be closed if there was no exception, but the except could probably be narrowed to wave.Error and EOFError. Georg From buildbot at python.org Thu Mar 15 09:26:38 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 15 Mar 2007 08:26:38 +0000 Subject: [Python-checkins] buildbot failure in x86 XP trunk Message-ID: <20070315082638.7C78E1E400D@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/316 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl,neal.norwitz BUILD FAILED: failed failed slave lost sincerely, -The Buildbot From python-checkins at python.org Thu Mar 15 12:45:01 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Thu, 15 Mar 2007 12:45:01 +0100 (CET) Subject: [Python-checkins] r54397 - in python/trunk: Lib/test/pickletester.py Misc/NEWS Objects/typeobject.c Message-ID: <20070315114501.A64E21E400E@bag.python.org> Author: ziga.seilnacht Date: Thu Mar 15 12:44:55 2007 New Revision: 54397 Modified: python/trunk/Lib/test/pickletester.py python/trunk/Misc/NEWS python/trunk/Objects/typeobject.c Log: Patch #1462488: prevent a segfault in object_reduce_ex() by splitting the implementation for __reduce__ and __reduce_ex__ into two separate functions. Fixes bug #931877. Will backport. Modified: python/trunk/Lib/test/pickletester.py ============================================================================== --- python/trunk/Lib/test/pickletester.py (original) +++ python/trunk/Lib/test/pickletester.py Thu Mar 15 12:44:55 2007 @@ -831,6 +831,24 @@ y = self.loads(s) self.assertEqual(y._proto, None) + def test_reduce_ex_calls_base(self): + for proto in 0, 1, 2: + x = REX_four() + self.assertEqual(x._proto, None) + s = self.dumps(x, proto) + self.assertEqual(x._proto, proto) + y = self.loads(s) + self.assertEqual(y._proto, proto) + + def test_reduce_calls_base(self): + for proto in 0, 1, 2: + x = REX_five() + self.assertEqual(x._reduce_called, 0) + s = self.dumps(x, proto) + self.assertEqual(x._reduce_called, 1) + y = self.loads(s) + self.assertEqual(y._reduce_called, 1) + # Test classes for reduce_ex class REX_one(object): @@ -855,6 +873,20 @@ def __reduce__(self): raise TestFailed, "This __reduce__ shouldn't be called" +class REX_four(object): + _proto = None + def __reduce_ex__(self, proto): + self._proto = proto + return object.__reduce_ex__(self, proto) + # Calling base class method should succeed + +class REX_five(object): + _reduce_called = 0 + def __reduce__(self): + self._reduce_called = 1 + return object.__reduce__(self) + # This one used to fail with infinite recursion + # Test classes for newobj class MyInt(int): Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Thu Mar 15 12:44:55 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #1462488: Python no longer segfaults when ``object.__reduce_ex__()`` + is called with an object that is faking its type. + - Patch #1680015: Don't modify __slots__ tuple if it contains an unicode name. Modified: python/trunk/Objects/typeobject.c ============================================================================== --- python/trunk/Objects/typeobject.c (original) +++ python/trunk/Objects/typeobject.c Thu Mar 15 12:44:55 2007 @@ -2770,11 +2770,54 @@ return res; } +/* + * There were two problems when object.__reduce__ and object.__reduce_ex__ + * were implemented in the same function: + * - trying to pickle an object with a custom __reduce__ method that + * fell back to object.__reduce__ in certain circumstances led to + * infinite recursion at Python level and eventual RuntimeError. + * - Pickling objects that lied about their type by overwriting the + * __class__ descriptor could lead to infinite recursion at C level + * and eventual segfault. + * + * Because of backwards compatibility, the two methods still have to + * behave in the same way, even if this is not required by the pickle + * protocol. This common functionality was moved to the _common_reduce + * function. + */ +static PyObject * +_common_reduce(PyObject *self, int proto) +{ + PyObject *copy_reg, *res; + + if (proto >= 2) + return reduce_2(self); + + copy_reg = import_copy_reg(); + if (!copy_reg) + return NULL; + + res = PyEval_CallMethod(copy_reg, "_reduce_ex", "(Oi)", self, proto); + Py_DECREF(copy_reg); + + return res; +} + +static PyObject * +object_reduce(PyObject *self, PyObject *args) +{ + int proto = 0; + + if (!PyArg_ParseTuple(args, "|i:__reduce__", &proto)) + return NULL; + + return _common_reduce(self, proto); +} + static PyObject * object_reduce_ex(PyObject *self, PyObject *args) { - /* Call copy_reg._reduce_ex(self, proto) */ - PyObject *reduce, *copy_reg, *res; + PyObject *reduce, *res; int proto = 0; if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto)) @@ -2810,23 +2853,13 @@ Py_DECREF(reduce); } - if (proto >= 2) - return reduce_2(self); - - copy_reg = import_copy_reg(); - if (!copy_reg) - return NULL; - - res = PyEval_CallMethod(copy_reg, "_reduce_ex", "(Oi)", self, proto); - Py_DECREF(copy_reg); - - return res; + return _common_reduce(self, proto); } static PyMethodDef object_methods[] = { {"__reduce_ex__", object_reduce_ex, METH_VARARGS, PyDoc_STR("helper for pickle")}, - {"__reduce__", object_reduce_ex, METH_VARARGS, + {"__reduce__", object_reduce, METH_VARARGS, PyDoc_STR("helper for pickle")}, {0} }; From python-checkins at python.org Thu Mar 15 12:48:00 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Thu, 15 Mar 2007 12:48:00 +0100 (CET) Subject: [Python-checkins] r54398 - in python/branches/release25-maint: Lib/test/pickletester.py Misc/NEWS Objects/typeobject.c Message-ID: <20070315114800.79EE61E401C@bag.python.org> Author: ziga.seilnacht Date: Thu Mar 15 12:47:59 2007 New Revision: 54398 Modified: python/branches/release25-maint/Lib/test/pickletester.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Objects/typeobject.c Log: Patch #1462488: prevent a segfault in object_reduce_ex() by splitting the implementation for __reduce__ and __reduce_ex__ into two separate functions. Fixes bug #931877. (backport from rev. 54397) Modified: python/branches/release25-maint/Lib/test/pickletester.py ============================================================================== --- python/branches/release25-maint/Lib/test/pickletester.py (original) +++ python/branches/release25-maint/Lib/test/pickletester.py Thu Mar 15 12:47:59 2007 @@ -831,6 +831,24 @@ y = self.loads(s) self.assertEqual(y._proto, None) + def test_reduce_ex_calls_base(self): + for proto in 0, 1, 2: + x = REX_four() + self.assertEqual(x._proto, None) + s = self.dumps(x, proto) + self.assertEqual(x._proto, proto) + y = self.loads(s) + self.assertEqual(y._proto, proto) + + def test_reduce_calls_base(self): + for proto in 0, 1, 2: + x = REX_five() + self.assertEqual(x._reduce_called, 0) + s = self.dumps(x, proto) + self.assertEqual(x._reduce_called, 1) + y = self.loads(s) + self.assertEqual(y._reduce_called, 1) + # Test classes for reduce_ex class REX_one(object): @@ -855,6 +873,20 @@ def __reduce__(self): raise TestFailed, "This __reduce__ shouldn't be called" +class REX_four(object): + _proto = None + def __reduce_ex__(self, proto): + self._proto = proto + return object.__reduce_ex__(self, proto) + # Calling base class method should succeed + +class REX_five(object): + _reduce_called = 0 + def __reduce__(self): + self._reduce_called = 1 + return object.__reduce__(self) + # This one used to fail with infinite recursion + # Test classes for newobj class MyInt(int): Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Thu Mar 15 12:47:59 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #1462488: Python no longer segfaults when ``object.__reduce_ex__()`` + is called with an object that is faking its type. + - Patch #1680015: Don't modify __slots__ tuple if it contains an unicode name. Modified: python/branches/release25-maint/Objects/typeobject.c ============================================================================== --- python/branches/release25-maint/Objects/typeobject.c (original) +++ python/branches/release25-maint/Objects/typeobject.c Thu Mar 15 12:47:59 2007 @@ -2708,11 +2708,54 @@ return res; } +/* + * There were two problems when object.__reduce__ and object.__reduce_ex__ + * were implemented in the same function: + * - trying to pickle an object with a custom __reduce__ method that + * fell back to object.__reduce__ in certain circumstances led to + * infinite recursion at Python level and eventual RuntimeError. + * - Pickling objects that lied about their type by overwriting the + * __class__ descriptor could lead to infinite recursion at C level + * and eventual segfault. + * + * Because of backwards compatibility, the two methods still have to + * behave in the same way, even if this is not required by the pickle + * protocol. This common functionality was moved to the _common_reduce + * function. + */ +static PyObject * +_common_reduce(PyObject *self, int proto) +{ + PyObject *copy_reg, *res; + + if (proto >= 2) + return reduce_2(self); + + copy_reg = import_copy_reg(); + if (!copy_reg) + return NULL; + + res = PyEval_CallMethod(copy_reg, "_reduce_ex", "(Oi)", self, proto); + Py_DECREF(copy_reg); + + return res; +} + +static PyObject * +object_reduce(PyObject *self, PyObject *args) +{ + int proto = 0; + + if (!PyArg_ParseTuple(args, "|i:__reduce__", &proto)) + return NULL; + + return _common_reduce(self, proto); +} + static PyObject * object_reduce_ex(PyObject *self, PyObject *args) { - /* Call copy_reg._reduce_ex(self, proto) */ - PyObject *reduce, *copy_reg, *res; + PyObject *reduce, *res; int proto = 0; if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", &proto)) @@ -2748,23 +2791,13 @@ Py_DECREF(reduce); } - if (proto >= 2) - return reduce_2(self); - - copy_reg = import_copy_reg(); - if (!copy_reg) - return NULL; - - res = PyEval_CallMethod(copy_reg, "_reduce_ex", "(Oi)", self, proto); - Py_DECREF(copy_reg); - - return res; + return _common_reduce(self, proto); } static PyMethodDef object_methods[] = { {"__reduce_ex__", object_reduce_ex, METH_VARARGS, PyDoc_STR("helper for pickle")}, - {"__reduce__", object_reduce_ex, METH_VARARGS, + {"__reduce__", object_reduce, METH_VARARGS, PyDoc_STR("helper for pickle")}, {0} }; From buildbot at python.org Thu Mar 15 13:28:14 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 15 Mar 2007 12:28:14 +0000 Subject: [Python-checkins] buildbot failure in x86 XP 2.5 Message-ID: <20070315122814.2B0561E400D@bag.python.org> The Buildbot has detected a new failure of x86 XP 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%25202.5/builds/177 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: ziga.seilnacht BUILD FAILED: failed failed slave lost sincerely, -The Buildbot From jimjjewett at gmail.com Thu Mar 15 18:42:40 2007 From: jimjjewett at gmail.com (Jim Jewett) Date: Thu, 15 Mar 2007 13:42:40 -0400 Subject: [Python-checkins] r54394 - in python/trunk: Lib/wave.py Misc/NEWS In-Reply-To: References: <20070315074134.62F571E400D@bag.python.org> <01e401c766d6$4699d670$f001a8c0@RaymondLaptop1> Message-ID: On 3/15/07, Georg Brandl wrote: > Raymond Hettinger schrieb: > >> - self.initfp(f) > >> + try: > >> + self.initfp(f) > >> + except: > >> + if self._i_opened_the_file: > >> + f.close() > >> + raise > > Do you really want a bare except? > > Would a try/finally approach work here? > The file shouldn't be closed if there was no exception, > but the except could probably be narrowed to wave.Error and EOFError. Why should it be narrowed? Wouldn't other (unexpected) exceptions also bubble up and cause the same leak? Is there really a general problem with bare except *when it includes a bare raise*? -jJ From python-checkins at python.org Thu Mar 15 19:05:53 2007 From: python-checkins at python.org (guido.van.rossum) Date: Thu, 15 Mar 2007 19:05:53 +0100 (CET) Subject: [Python-checkins] r54399 - peps/trunk/pep-0000.txt peps/trunk/pep-3116.txt Message-ID: <20070315180553.96BC71E400D@bag.python.org> Author: guido.van.rossum Date: Thu Mar 15 19:05:48 2007 New Revision: 54399 Added: peps/trunk/pep-3116.txt (contents, props changed) Modified: peps/trunk/pep-0000.txt Log: PEP 3116 - new I/O, by Mike Verdone and Daniel Stutzbach; converted from HTML by Jason Orendorff. Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Thu Mar 15 19:05:48 2007 @@ -114,6 +114,7 @@ S 3108 Standard Library Reorganization Cannon S 3114 Renaming iterator.next() to iterator.__next__() Yee S 3115 Metaclasses in Python 3000 Talin + S 3116 New I/O Stutzbach, Verdone, GvR Finished PEPs (done, implemented in Subversion) @@ -466,6 +467,7 @@ SA 3113 Removal of Tuple Parameter Unpacking Cannon S 3114 Renaming iterator.next() to iterator.__next__() Yee S 3115 Metaclasses in Python 3000 Talin + S 3116 New I/O Stutzbach, Verdone, GvR Key @@ -568,10 +570,12 @@ Seo, Jiwon seojiwon at gmail.com Smith, Kevin D. Kevin.Smith at theMorgue.org Stein, Greg gstein at lyra.org + Stutzbach, Daniel daniel.stutzbach at gmail.com Suzi, Roman rnd at onego.ru Talin talin at acm.org Taschuk, Steven staschuk at telusplanet.net Tirosh, Oren oren at hishome.net + Verdone, Mike mike.verdone at gmail.com Warnes, Gregory R. warnes at users.sourceforge.net Warsaw, Barry barry at python.org Way, Terence terry at wayforward.net Added: peps/trunk/pep-3116.txt ============================================================================== --- (empty file) +++ peps/trunk/pep-3116.txt Thu Mar 15 19:05:48 2007 @@ -0,0 +1,460 @@ +PEP: 3116 +Title: New I/O +Version: $Revision$ +Last-Modified: $Date$ +Author: Daniel Stutzbach, Mike Verdone, Guido van Rossum +Status: Draft +Type: Standards Track +Content-type: text/x-rst +Created: 26-Feb-2007 +Post-History: 26-Feb-2007 +Python-Version: 3.0 + +Rationale and Goals +=================== + +Python allows for a variety of stream-like (a.k.a. file-like) objects +that can be used via ``read()`` and ``write()`` calls. Anything that +provides ``read()`` and ``write()`` is stream-like. However, more +exotic and extremely useful functions like ``readline()`` or +``seek()`` may or may not be available on every stream-like object. +Python needs a specification for basic byte-based I/O streams to which +we can add buffering and text-handling features. + +Once we have a defined raw byte-based I/O interface, we can add +buffering and text handling layers on top of any byte-based I/O class. +The same buffering and text handling logic can be used for files, +sockets, byte arrays, or custom I/O classes developed by Python +programmers. Developing a standard definition of a stream lets us +separate stream-based operations like ``read()`` and ``write()`` from +implementation specific operations like ``fileno()`` and ``isatty()``. +It encourages programmers to write code that uses streams as streams +and not require that all streams support file-specific or +socket-specific operations. + +The new I/O spec is intended to be similar to the Java I/O libraries, +but generally less confusing. Programmers who don't want to muck +about in the new I/O world can expect that the ``open()`` factory +method will produce an object backwards-compatible with old-style file +objects. + + +Specification +============= + +The Python I/O Library will consist of three layers: a raw I/O layer, +a buffered I/O layer, and a text I/O layer. Each layer is defined by +an abstract base class, which may have multiple implementations. The +raw I/O and buffered I/O layers deal with units of bytes, while the +text I/O layer deals with units of characters. + + +Raw I/O +======= + +The abstract base class for raw I/O is RawIOBase. It has several +methods which are wrappers around the appropriate operating system +calls. If one of these functions would not make sense on the object, +the implementation must raise an IOError exception. For example, if a +file is opened read-only, the ``.write()`` method will raise an +``IOError``. As another example, if the object represents a socket, +then ``.seek()``, ``.tell()``, and ``.truncate()`` will raise an +``IOError``. Generally, a call to one of these functions maps to +exactly one operating system call. + + ``.read(n: int) -> bytes`` + + Read up to ``n`` bytes from the object and return them. Fewer + than ``n`` bytes may be returned if the operating system call + returns fewer than ``n`` bytes. If 0 bytes are returned, this + indicates end of file. If the object is in non-blocking mode + and no bytes are available, the call returns ``None``. + + ``.readinto(b: bytes) -> int`` + + Read up to ``n`` bytes from the object and stores them in + ``b``, returning the number of bytes read. Like .read, fewer + than ``n`` bytes may be read, and 0 indicates end of file. + ``None`` is returned if a non-blocking object has no bytes + available. + + ``.write(b: bytes) -> int`` + + Returns number of bytes written, which may be ``< len(b)``. + + ``.seek(pos: int, whence: int = 0) -> None`` + + ``.tell() -> int`` + + ``.truncate(n: int = None) -> None`` + + ``.close() -> None`` + +Additionally, it defines a few other methods: + + ``.readable() -> bool`` + + Returns ``True`` if the object was opened for reading, + ``False`` otherwise. If ``False``, ``.read()`` will raise an + ``IOError`` if called. + + ``.writable() -> bool`` + + Returns ``True`` if the object was opened write writing, + ``False`` otherwise. If ``False``, ``.write()`` and + ``.truncate()`` will raise an ``IOError`` if called. + + ``.seekable() -> bool`` + + Returns ``True`` if the object supports random access (such as + disk files), or ``False`` if the object only supports + sequential access (such as sockets, pipes, and ttys). If + ``False``, ``.seek()``, ``.tell()``, and ``.truncate()`` will + raise an IOError if called. + + ``.__enter__() -> ContextManager`` + + Context management protocol. Returns ``self``. + + ``.__exit__(...) -> None`` + + Context management protocol. Same as ``.close()``. + +If and only if a ``RawIOBase`` implementation operates on an +underlying file descriptor, it must additionally provide a +``.fileno()`` member function. This could be defined specifically by +the implementation, or a mix-in class could be used (need to decide +about this). + + ``.fileno() -> int`` + + Returns the underlying file descriptor (an integer) + +Initially, three implementations will be provided that implement the +``RawIOBase`` interface: ``FileIO``, ``SocketIO``, and ``ByteIO`` +(also ``MMapIO``?). Each implementation must determine whether the +object supports random access as the information provided by the user +may not be sufficient (consider ``open("/dev/tty", "rw")`` or +``open("/tmp/named-pipe", "rw")``). As an example, ``FileIO`` can +determine this by calling the ``seek()`` system call; if it returns an +error, the object does not support random access. Each implementation +may provided additional methods appropriate to its type. The +``ByteIO`` object is analogous to Python 2's ``cStringIO`` library, +but operating on the new bytes type instead of strings. + + +Buffered I/O +============ + +The next layer is the Buffered I/O layer which provides more efficient +access to file-like objects. The abstract base class for all Buffered +I/O implementations is ``BufferedIOBase``, which provides similar methods +to RawIOBase: + + ``.read(n: int = -1) -> bytes`` + + Returns the next ``n`` bytes from the object. It may return + fewer than ``n`` bytes if end-of-file is reached or the object is + non-blocking. 0 bytes indicates end-of-file. This method may + make multiple calls to ``RawIOBase.read()`` to gather the bytes, + or may make no calls to ``RawIOBase.read()`` if all of the needed + bytes are already buffered. + + ``.readinto(b: bytes) -> int`` + + ``.write(b: bytes) -> None`` + + Write ``b`` bytes to the buffer. The bytes are not guaranteed to + be written to the Raw I/O object immediately; they may be + buffered. + + ``.seek(pos: int, whence: int = 0) -> int`` + + ``.tell() -> int`` + + ``.truncate(pos: int = None) -> None`` + + ``.flush() -> None`` + + ``.close() -> None`` + + ``.readable() -> bool`` + + ``.writable() -> bool`` + + ``.seekable() -> bool`` + + ``.__enter__() -> ContextManager`` + + ``.__exit__(...) -> None`` + +Additionally, the abstract base class provides one member variable: + + ``.raw`` + + A reference to the underlying ``RawIOBase`` object. + +The ``BufferedIOBase`` methods signatures are mostly identical to that +of ``RawIOBase`` (exceptions: ``write()`` returns ``None``, +``read()``'s argument is optional), but may have different semantics. +In particular, ``BufferedIOBase`` implementations may read more data +than requested or delay writing data using buffers. For the most +part, this will be transparent to the user (unless, for example, they +open the same file through a different descriptor). Also, raw reads +may return a short read without any particular reason; buffered reads +will only return a short read if EOF is reached; and raw writes may +return a short count (even when non-blocking I/O is not enabled!), +while buffered writes will raise ``IOError`` when not all bytes could +be written or buffered. + +There are four implementations of the ``BufferedIOBase`` abstract base +class, described below. + + +``BufferedReader`` +------------------ + +The ``BufferedReader`` implementation is for sequential-access +read-only objects. Its ``.flush()`` method is a no-op. + + +``BufferedWriter`` +------------------ + +The ``BufferedWriter`` implementation is for sequential-access +write-only objects. Its ``.flush()`` method forces all cached data to +be written to the underlying RawIOBase object. + + +``BufferedRWPair`` +------------------ + +The ``BufferedRWPair`` implementation is for sequential-access +read-write objects such as sockets and ttys. As the read and write +streams of these objects are completely independent, it could be +implemented by simply incorporating a ``BufferedReader`` and +``BufferedWriter`` instance. It provides a ``.flush()`` method that +has the same semantics as a ``BufferedWriter``'s ``.flush()`` method. + + +``BufferedRandom`` +------------------ + +The ``BufferedRandom`` implementation is for all random-access +objects, whether they are read-only, write-only, or read-write. +Compared to the previous classes that operate on sequential-access +objects, the ``BufferedRandom`` class must contend with the user +calling ``.seek()`` to reposition the stream. Therefore, an instance +of ``BufferedRandom`` must keep track of both the logical and true +position within the object. It provides a ``.flush()`` method that +forces all cached write data to be written to the underlying +``RawIOBase`` object and all cached read data to be forgotten (so that +future reads are forced to go back to the disk). + +*Q: Do we want to mandate in the specification that switching between +reading to writing on a read-write object implies a .flush()? Or is +that an implementation convenience that users should not rely on?* + +For a read-only ``BufferedRandom`` object, ``.writable()`` returns +``False`` and the ``.write()`` and ``.truncate()`` methods throw +``IOError``. + +For a write-only ``BufferedRandom`` object, ``.readable()`` returns +``False`` and the ``.read()`` method throws ``IOError``. + + +Text I/O +======== + +The text I/O layer provides functions to read and write strings from +streams. Some new features include universal newlines and character +set encoding and decoding. The Text I/O layer is defined by a +``TextIOBase`` abstract base class. It provides several methods that +are similar to the ``BufferedIOBase`` methods, but operate on a +per-character basis instead of a per-byte basis. These methods are: + + ``.read(n: int = -1) -> str`` + + ``.write(s: str) -> None`` + +``TextIOBase`` implementations also provide several methods that are +pass-throughs to the underlaying ``BufferedIOBase`` objects: + + ``.seek(pos: int, whence: int = 0) -> None`` + + ``.tell() -> int`` + + ``.truncate(pos: int = None) -> None`` + + ``.flush() -> None`` + + ``.close() -> None`` + + ``.readable() -> bool`` + + ``.writable() -> bool`` + + ``.seekable() -> bool`` + +``TextIOBase`` class implementations additionally provide the +following methods: + + ``.readline() -> str`` + + Read until newline or EOF and return the line, or ``""`` if + EOF hit immediately. + + ``.__iter__() -> Iterator`` + + Returns an iterator that returns lines from the file (which + happens to be ``self``). + + ``.next() -> str`` + + Same as ``readline()`` except raises ``StopIteration`` if EOF + hit immediately. + +Two implementations will be provided by the Python library. The +primary implementation, ``TextIOWrapper``, wraps a Buffered I/O +object. Each ``TextIOWrapper`` object has a property named +"``.buffer``" that provides a reference to the underlying +``BufferedIOBase`` object. Its initializer has the following +signature: + + ``.__init__(self, buffer, encoding=None, newline=None)`` + + ``buffer`` is a reference to the ``BufferedIOBase`` object to + be wrapped with the ``TextIOWrapper``. ``encoding`` refers to + an encoding to be used for translating between the + byte-representation and character-representation. If it is + ``None``, then the system's locale setting will be used as the + default. ``newline`` can be ``None``, ``'\n'``, or ``'\r\n'`` + (all other values are illegal); it indicates the translation + for ``'\n'`` characters written. If ``None``, a + system-specific default is chosen, i.e., ``'\r\n'`` on Windows + and ``'\n'`` on Unix/Linux. Setting ``newline='\n'`` on input + means that no CRLF translation is done; lines ending in + ``'\r\n'`` will be returned as ``'\r\n'``. + +Another implementation, ``StringIO``, creates a file-like ``TextIO`` +implementation without an underlying Buffered I/O object. While +similar functionality could be provided by wrapping a ``BytesIO`` +object in a ``TextIOWrapper``, the ``StringIO`` object allows for much +greater efficiency as it does not need to actually performing encoding +and decoding. A String I/O object can just store the encoded string +as-is. The ``StringIO`` object's ``__init__`` signature takes an +optional string specifying the initial value; the initial position is +always 0. It does not support encodings or newline translations; you +always read back exactly the characters you wrote. + + +Unicode encoding/decoding Issues +-------------------------------- + +We should allow passing an error-handling argument whenever an +encoding is accepted, and we should allow changing the error-handling +setting later. The behavior of Text I/O operations in the face of +Unicode problems and ambiguities (e.g. diacritics, surrogates, invalid +bytes in an encoding) should be the same as that of the unicode +``encode()``/``decode()`` methods. ``UnicodeError`` may be raised. + +Implementation note: we should be able to reuse much of the +infrastructure provided by the ``codecs`` module. If it doesn't +provide the exact APIs we need, we should refactor it to avoid +reinventing the wheel. + + +Non-blocking I/O +================ + +Non-blocking I/O is fully supported on the Raw I/O level only. If a +raw object is in non-blocking mode and an operation would block, then +``.read()`` and ``.readinto()`` return ``None``, while ``.write()`` +returns 0. In order to put an object in object in non-blocking mode, +the user must extract the fileno and do it by hand. + +At the Buffered I/O and Text I/O layers, if a read or write fails due +a non-blocking condition, they raise an ``IOError`` with ``errno`` set +to ``EAGAIN``. + +Originally, we considered propagating up the Raw I/O behavior, but +many corner cases and problems were raised. To address these issues, +significant changes would need to have been made to the Buffered I/O +and Text I/O layers. For example, what should ``.flush()`` do on a +Buffered non-blocking object? How would the user instruct the object +to "Write as much as you can from your buffer, but don't block"? A +non-blocking ``.flush()`` that doesn't necessarily flush all available +data is counter-intuitive. Since non-blocking and blocking objects +would have such different semantics at these layers, it was agreed to +abandon efforts to combine them into a single type. + + +The ``open()`` Built-in Function +================================ + +The ``open()`` built-in function is specified by the following +pseudo-code:: + + def open(filename, mode="r", buffering=None, *, encoding=None): + assert isinstance(filename, str) + assert isinstance(mode, str) + assert buffering is None or isinstance(buffering, int) + assert encoding is None or isinstance(encoding, str) + modes = set(mode) + if modes - set("arwb+t") or len(mode) > len(modes): + raise ValueError("invalid mode: %r" % mode) + reading = "r" in modes + writing = "w" in modes + binary = "b" in modes + appending = "a" in modes + updating = "+" in modes + text = "t" in modes or not binary + if text and binary: + raise ValueError("can't have text and binary mode at once") + if reading + writing + appending > 1: + raise ValueError("can't have read/write/append mode at once") + if not (reading or writing or appending): + raise ValueError("must have exactly one of read/write/append mode") + if binary and encoding is not None: + raise ValueError("binary modes doesn't take an encoding") + # XXX Need to spec the signature for FileIO() + raw = FileIO(filename, mode) + if buffering is None: + buffering = 8*1024 # International standard buffer size + # XXX Try setting it to fstat().st_blksize + if buffering < 0: + raise ValueError("invalid buffering size") + if buffering == 0: + if binary: + return raw + raise ValueError("can't have unbuffered text I/O") + if updating: + buffer = BufferedRandom(raw, buffering) + elif writing or appending: + buffer = BufferedWriter(raw, buffering) + else: + assert reading + buffer = BufferedReader(raw, buffering) + if binary: + return buffer + assert text + # XXX Need to do something about universal newlines? + textio = TextIOWrapper(buffer) + return textio + + +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 + coding: utf-8 + End: From dpf at creativemortgage.ca Thu Mar 15 19:01:39 2007 From: dpf at creativemortgage.ca (Lee X. Rupert) Date: Thu, 15 Mar 2007 19:01:39 +0100 Subject: [Python-checkins] ordinarily rip Message-ID: <001401c7672d$49ae56e0$2ed842d4@idb> Celebrate valentines day in style with your feeds conveying the spirit! The iPod tutorial is even designed to help advanced iPod users to take advantage of the iPods more advanced and complex features. The bundle includes RecordForAll, FeedForAll and a subscription to the RSS Scripts Directory. It also deciphers the technical jargon used on websites to explain the iPods various features and functions. The bundle includes RecordForAll, FeedForAll and a subscription to the RSS Scripts Directory. com New LOGO Templates Added to RSS2HTML Template Directory The RSS2HTML template directory is growing. Answer: There are no maximums or minimums when it comes to podcast size. It is easiest if you use the same location each time, that way the equipment can remain in place and will not require moving or setup each time you produce a show. pdf Podcasting Bundle We are running a 7 day only special on the podcasting bundle. Recording Away from Home When taking your podcast on the road it is equally important that the quality of the podcast is not compromised for the sake of portability. You don't have to be a sound engineer to get really great results with RecordForAll. Just as the second generation of search engines and directories evolved into niche topic specific portals we are seeing the same occur in the area of RSS feed directories and search engines. The details on the new RSS script versions can be viewed in the release notes of each script. The iPod however comes with very little documentation. The location should be free of external distractions and relatively quiet. The room should have a carpet or furniture that will absorb echoes and dampen the sound. Just as the second generation of search engines and directories evolved into niche topic specific portals we are seeing the same occur in the area of RSS feed directories and search engines. Answer: There are no maximums or minimums when it comes to podcast size. htmWhy Niche RSS Feeds Matter? While some directories are admittedly more niche than others the trend is obvious. Take the podcast quiz and test your knowledge. To show how much we love our customers we decided to offer a ONE DAY SALE on the Podcasting Bundle. RecordForAll is so impressive that it's truly a "Must Have Application". The free iPod tutorial explains the differences between the iPod models. Follow these tips and be on your way to a popular podcast. It is easiest if you use the same location each time, that way the equipment can remain in place and will not require moving or setup each time you produce a show. -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20070315/d67dae70/attachment-0001.html -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: image/gif Size: 25831 bytes Desc: not available Url : http://mail.python.org/pipermail/python-checkins/attachments/20070315/d67dae70/attachment-0001.gif From python-checkins at python.org Fri Mar 16 01:36:03 2007 From: python-checkins at python.org (talin) Date: Fri, 16 Mar 2007 01:36:03 +0100 (CET) Subject: [Python-checkins] r54402 - peps/trunk/pep-3115.txt Message-ID: <20070316003603.E00E21E4016@bag.python.org> Author: talin Date: Fri Mar 16 01:36:00 2007 New Revision: 54402 Modified: peps/trunk/pep-3115.txt Log: Updated the PEP in accordance with the latest discussions. Added additional rationales and use cases, and added a link to the sample implementation. Modified: peps/trunk/pep-3115.txt ============================================================================== --- peps/trunk/pep-3115.txt (original) +++ peps/trunk/pep-3115.txt Fri Mar 16 01:36:00 2007 @@ -52,6 +52,15 @@ the new system allows the ordering or other early artifacts of construction to be preserved and examined. + There proposed metaclass mechanism also supports a number of other + interesting use cases beyond preserving the ordering of declarations. + One use case is to insert symbols into the namespace of the class + body which are only valid during class construction. An example of + this might be "field constructors", small functions that are used in + the creation of class members. Another interesting possibility is + supporting forward references, i.e. references to Python + symbols that are declared further down in the class body. + The other, weaker, rationale is purely cosmetic: The current method for specifying a metaclass is by assignment to the special variable __metaclass__, which is considered by some to be aesthetically less @@ -105,12 +114,14 @@ calling it; If it is not present, then a regular dictionary is used, as illustrated in the following Python snippet. - def prepare_class(name, *bases, metaclass=type, **kwargs): - prepare = getattr(metaclass, '__prepare__', None) - if prepare is not None: - return prepare(name, bases, **kwargs) - else: - return dict() + def prepare_class(name, *bases, metaclass=None, **kwargs): + if metaclass is None: + metaclass = compute_default_metaclass(bases) + prepare = getattr(metaclass, '__prepare__', None) + if prepare is not None: + return prepare(name, bases, **kwargs) + else: + return dict() The example above illustrates how the arguments to 'class' are interpreted. The class name is the first argument, followed by @@ -127,13 +138,22 @@ (just like it is now), except that the local variables dictionary is replaced by the dictionary returned from __prepare__. This dictionary object can be a regular dictionary or a custom mapping - type. It does not need to implement the full dictionary interface; - only the ability to insert items and retrieve them are - required. (Note: double check that this is true). - - Note that __prepare__ is generally a class method, not an instance - method because it is called before the metaclass instance (i.e. the - class itself) is created. + type. + + This dictionary-like object is not required to support the full + dictionary interface. A dictionary which supports a limited set of + dictionary operations will restrict what kinds of actions can occur + during evaluation of the class body. A minimal implementation might + only support adding and retrieving values from the dictionary - most + class bodies will do no more than that during evaluation. For some + classes, it may be desirable to support deletion as well. Many + metaclasses will need to make a copy of this dictionary afterwards, + so iteration or other means for reading out the dictionary contents + may also be useful. + + The __prepare__ method will most often be implemented as a class + method rather than an instance method because it is called before + the metaclass instance (i.e. the class itself) is created. Once the class body has finished evaluating, the metaclass will be called (as a callable) with the class dictionary, which is no @@ -165,27 +185,27 @@ the names of all class members, in the order that they were declared: - # The metaclass - class OrderedClass(type): + # The custom dictionary + class member_table(dict): + def __init__(self): + self.member_names = [] + + def __setitem__(self, key, value): + # if the key is not already defined, add to the + # list of keys. + if key not in self: + self.member_names.append(key) - # The custom dictionary - class member_table(dict): - def __init__(self): - self.member_names = [] - - def __setitem__(self, key, value): - # if the key is not already defined, add to the - # list of keys. - if key not in self: - self.member_names.append(key) + # Call superclass + dict.setitem(self, key, value) - # Call superclass - dict.setitem(self, key, value) + # The metaclass + class OrderedClass(type): # The prepare function @classmethod - def __prepare__(metacls, name, bases): # No keywords in this case - return metacls.member_table() + def __prepare__(metacls, name, bases): # No keywords in this case + return member_table() # The metaclass invocation def __init__(self, name, bases, classdict): @@ -206,6 +226,13 @@ def method2(self): pass +Sample Implementation: + + Guido van Rossum has created a patch which implements the new + functionality: + + http://python.org/sf/1681101 + Alternate Proposals Josiah Carlson proposed using the name 'type' instead of @@ -232,10 +259,12 @@ classes, and skip the whole 'custom dict' mechanism. This was based on the observation that most use cases for a custom dict were for the purposes of preserving order information. However, this idea has - two drawbacks, first because it means that an ordered dict + several drawbacks, first because it means that an ordered dict implementation would have to be added to the set of built-in types in Python, and second because it would impose a slight speed (and - complexity) penalty on all class declarations. + complexity) penalty on all class declarations. Later, several people + came up with ideas for use cases for custom dictionaries other + than preserving field orderings, so this idea was dropped. Backwards Compatibility From python-checkins at python.org Fri Mar 16 01:47:17 2007 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 16 Mar 2007 01:47:17 +0100 (CET) Subject: [Python-checkins] r54403 - peps/trunk/pep-3115.txt Message-ID: <20070316004717.D4E671E400D@bag.python.org> Author: guido.van.rossum Date: Fri Mar 16 01:47:10 2007 New Revision: 54403 Modified: peps/trunk/pep-3115.txt Log: Fix layout glitch in References section. Modified: peps/trunk/pep-3115.txt ============================================================================== --- peps/trunk/pep-3115.txt (original) +++ peps/trunk/pep-3115.txt Fri Mar 16 01:47:10 2007 @@ -278,20 +278,16 @@ References [1] [Python-3000] Metaclasses in Py3K (original proposal) - -http://mail.python.org/pipermail/python-3000/2006-December/005030.html + http://mail.python.org/pipermail/python-3000/2006-December/005030.html [2] [Python-3000] Metaclasses in Py3K (Guido's suggested syntax) - -http://mail.python.org/pipermail/python-3000/2006-December/005033.html + http://mail.python.org/pipermail/python-3000/2006-December/005033.html [3] [Python-3000] Metaclasses in Py3K (Objections to two-phase init) - -http://mail.python.org/pipermail/python-3000/2006-December/005108.html + http://mail.python.org/pipermail/python-3000/2006-December/005108.html [4] [Python-3000] Metaclasses in Py3K (Always use an ordered dict) - -http://mail.python.org/pipermail/python-3000/2006-December/005118.html + http://mail.python.org/pipermail/python-3000/2006-December/005118.html [5] PEP 359: The 'make' statement - http://www.python.org/dev/peps/pep-0359/ From python-checkins at python.org Fri Mar 16 05:11:37 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 16 Mar 2007 05:11:37 +0100 (CET) Subject: [Python-checkins] r54404 - in python/trunk: Lib/test/test_syntax.py Misc/NEWS Python/ast.c Message-ID: <20070316041137.8D7791E400D@bag.python.org> Author: collin.winter Date: Fri Mar 16 05:11:30 2007 New Revision: 54404 Modified: python/trunk/Lib/test/test_syntax.py python/trunk/Misc/NEWS python/trunk/Python/ast.c Log: Patch #1642547: Fix an error/crash when encountering syntax errors in complex if statements. Will backport. Modified: python/trunk/Lib/test/test_syntax.py ============================================================================== --- python/trunk/Lib/test/test_syntax.py (original) +++ python/trunk/Lib/test/test_syntax.py Fri Mar 16 05:11:30 2007 @@ -367,6 +367,56 @@ ... SystemError: too many statically nested blocks +This tests assignment-context; there was a bug in Python 2.5 where compiling +a complex 'if' (one with 'elif') would fail to notice an invalid suite, +leading to spurious errors. + + >>> if 1: + ... x() = 1 + ... elif 1: + ... pass + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 2) + + >>> if 1: + ... pass + ... elif 1: + ... x() = 1 + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 4) + + >>> if 1: + ... x() = 1 + ... elif 1: + ... pass + ... else: + ... pass + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 2) + + >>> if 1: + ... pass + ... elif 1: + ... x() = 1 + ... else: + ... pass + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 4) + + >>> if 1: + ... pass + ... elif 1: + ... pass + ... else: + ... x() = 1 + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 6) + """ import re Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 16 05:11:30 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #1642547: Fix an error/crash when encountering syntax errors in + complex if statements. + - Patch #1462488: Python no longer segfaults when ``object.__reduce_ex__()`` is called with an object that is faking its type. Modified: python/trunk/Python/ast.c ============================================================================== --- python/trunk/Python/ast.c (original) +++ python/trunk/Python/ast.c Fri Mar 16 05:11:30 2007 @@ -1032,6 +1032,7 @@ if (NCH(ch) == 5) { int j, n_ifs; asdl_seq *ifs; + expr_ty list_for_expr; ch = CHILD(ch, 4); n_ifs = count_list_ifs(ch); @@ -1046,8 +1047,12 @@ REQ(ch, list_iter); ch = CHILD(ch, 0); REQ(ch, list_if); + + list_for_expr = ast_for_expr(c, CHILD(ch, 1)); + if (!list_for_expr) + return NULL; - asdl_seq_SET(ifs, j, ast_for_expr(c, CHILD(ch, 1))); + asdl_seq_SET(ifs, j, list_for_expr); if (NCH(ch) == 3) ch = CHILD(ch, 2); } @@ -1991,7 +1996,8 @@ "assignment"); return NULL; } - set_context(expr1, Store, ch); + if(!set_context(expr1, Store, ch)) + return NULL; ch = CHILD(n, 2); if (TYPE(ch) == testlist) @@ -2584,6 +2590,8 @@ } else if (s[2] == 'i') { int i, n_elif, has_else = 0; + expr_ty expression; + asdl_seq *suite_seq; asdl_seq *orelse = NULL; n_elif = NCH(n) - 4; /* must reference the child n_elif+1 since 'else' token is third, @@ -2596,8 +2604,7 @@ n_elif /= 4; if (has_else) { - expr_ty expression; - asdl_seq *seq1, *seq2; + asdl_seq *suite_seq2; orelse = asdl_seq_new(1, c->c_arena); if (!orelse) @@ -2605,14 +2612,14 @@ expression = ast_for_expr(c, CHILD(n, NCH(n) - 6)); if (!expression) return NULL; - seq1 = ast_for_suite(c, CHILD(n, NCH(n) - 4)); - if (!seq1) + suite_seq = ast_for_suite(c, CHILD(n, NCH(n) - 4)); + if (!suite_seq) return NULL; - seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1)); - if (!seq2) + suite_seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1)); + if (!suite_seq2) return NULL; - asdl_seq_SET(orelse, 0, If(expression, seq1, seq2, + asdl_seq_SET(orelse, 0, If(expression, suite_seq, suite_seq2, LINENO(CHILD(n, NCH(n) - 6)), CHILD(n, NCH(n) - 6)->n_col_offset, c->c_arena)); /* the just-created orelse handled the last elif */ @@ -2621,8 +2628,6 @@ for (i = 0; i < n_elif; i++) { int off = 5 + (n_elif - i - 1) * 4; - expr_ty expression; - asdl_seq *suite_seq; asdl_seq *newobj = asdl_seq_new(1, c->c_arena); if (!newobj) return NULL; @@ -2638,9 +2643,14 @@ LINENO(CHILD(n, off)), CHILD(n, off)->n_col_offset, c->c_arena)); orelse = newobj; } - return If(ast_for_expr(c, CHILD(n, 1)), - ast_for_suite(c, CHILD(n, 3)), - orelse, LINENO(n), n->n_col_offset, c->c_arena); + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, 3)); + if (!suite_seq) + return NULL; + return If(expression, suite_seq, orelse, + LINENO(n), n->n_col_offset, c->c_arena); } PyErr_Format(PyExc_SystemError, @@ -2876,6 +2886,8 @@ assert(TYPE(n) == with_stmt); context_expr = ast_for_expr(c, CHILD(n, 1)); + if (!context_expr) + return NULL; if (TYPE(CHILD(n, 2)) == with_var) { optional_vars = ast_for_with_var(c, CHILD(n, 2)); From python-checkins at python.org Fri Mar 16 05:12:56 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 16 Mar 2007 05:12:56 +0100 (CET) Subject: [Python-checkins] r54405 - in python/branches/release25-maint: Lib/test/test_syntax.py Misc/NEWS Python/ast.c Message-ID: <20070316041256.29A2E1E401D@bag.python.org> Author: collin.winter Date: Fri Mar 16 05:12:48 2007 New Revision: 54405 Modified: python/branches/release25-maint/Lib/test/test_syntax.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Python/ast.c Log: Patch #1642547: Fix an error/crash when encountering syntax errors in complex if statements. Backported from r54404. Modified: python/branches/release25-maint/Lib/test/test_syntax.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_syntax.py (original) +++ python/branches/release25-maint/Lib/test/test_syntax.py Fri Mar 16 05:12:48 2007 @@ -364,6 +364,56 @@ ... SystemError: too many statically nested blocks +This tests assignment-context; there was a bug in Python 2.5 where compiling +a complex 'if' (one with 'elif') would fail to notice an invalid suite, +leading to spurious errors. + + >>> if 1: + ... x() = 1 + ... elif 1: + ... pass + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 2) + + >>> if 1: + ... pass + ... elif 1: + ... x() = 1 + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 4) + + >>> if 1: + ... x() = 1 + ... elif 1: + ... pass + ... else: + ... pass + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 2) + + >>> if 1: + ... pass + ... elif 1: + ... x() = 1 + ... else: + ... pass + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 4) + + >>> if 1: + ... pass + ... elif 1: + ... pass + ... else: + ... x() = 1 + Traceback (most recent call last): + ... + SyntaxError: can't assign to function call (, line 6) + """ import re Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Fri Mar 16 05:12:48 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #1642547: Fix an error/crash when encountering syntax errors in + complex if statements. + - Patch #1462488: Python no longer segfaults when ``object.__reduce_ex__()`` is called with an object that is faking its type. Modified: python/branches/release25-maint/Python/ast.c ============================================================================== --- python/branches/release25-maint/Python/ast.c (original) +++ python/branches/release25-maint/Python/ast.c Fri Mar 16 05:12:48 2007 @@ -1033,6 +1033,7 @@ if (NCH(ch) == 5) { int j, n_ifs; asdl_seq *ifs; + expr_ty list_for_expr; ch = CHILD(ch, 4); n_ifs = count_list_ifs(ch); @@ -1047,8 +1048,12 @@ REQ(ch, list_iter); ch = CHILD(ch, 0); REQ(ch, list_if); + + list_for_expr = ast_for_expr(c, CHILD(ch, 1)); + if (!list_for_expr) + return NULL; - asdl_seq_SET(ifs, j, ast_for_expr(c, CHILD(ch, 1))); + asdl_seq_SET(ifs, j, list_for_expr); if (NCH(ch) == 3) ch = CHILD(ch, 2); } @@ -1992,7 +1997,8 @@ "assignment"); return NULL; } - set_context(expr1, Store, ch); + if (!set_context(expr1, Store, ch)) + return NULL; ch = CHILD(n, 2); if (TYPE(ch) == testlist) @@ -2593,6 +2599,8 @@ } else if (s[2] == 'i') { int i, n_elif, has_else = 0; + expr_ty expression; + asdl_seq *suite_seq; asdl_seq *orelse = NULL; n_elif = NCH(n) - 4; /* must reference the child n_elif+1 since 'else' token is third, @@ -2605,8 +2613,7 @@ n_elif /= 4; if (has_else) { - expr_ty expression; - asdl_seq *seq1, *seq2; + asdl_seq *suite_seq2; orelse = asdl_seq_new(1, c->c_arena); if (!orelse) @@ -2614,14 +2621,14 @@ expression = ast_for_expr(c, CHILD(n, NCH(n) - 6)); if (!expression) return NULL; - seq1 = ast_for_suite(c, CHILD(n, NCH(n) - 4)); - if (!seq1) + suite_seq = ast_for_suite(c, CHILD(n, NCH(n) - 4)); + if (!suite_seq) return NULL; - seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1)); - if (!seq2) + suite_seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1)); + if (!suite_seq2) return NULL; - asdl_seq_SET(orelse, 0, If(expression, seq1, seq2, + asdl_seq_SET(orelse, 0, If(expression, suite_seq, suite_seq2, LINENO(CHILD(n, NCH(n) - 6)), CHILD(n, NCH(n) - 6)->n_col_offset, c->c_arena)); /* the just-created orelse handled the last elif */ @@ -2630,8 +2637,6 @@ for (i = 0; i < n_elif; i++) { int off = 5 + (n_elif - i - 1) * 4; - expr_ty expression; - asdl_seq *suite_seq; asdl_seq *newobj = asdl_seq_new(1, c->c_arena); if (!newobj) return NULL; @@ -2647,9 +2652,14 @@ LINENO(CHILD(n, off)), CHILD(n, off)->n_col_offset, c->c_arena)); orelse = newobj; } - return If(ast_for_expr(c, CHILD(n, 1)), - ast_for_suite(c, CHILD(n, 3)), - orelse, LINENO(n), n->n_col_offset, c->c_arena); + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, 3)); + if (!suite_seq) + return NULL; + return If(expression, suite_seq, orelse, + LINENO(n), n->n_col_offset, c->c_arena); } PyErr_Format(PyExc_SystemError, @@ -2889,6 +2899,8 @@ assert(TYPE(n) == with_stmt); context_expr = ast_for_expr(c, CHILD(n, 1)); + if (!context_expr) + return NULL; if (TYPE(CHILD(n, 2)) == with_var) { optional_vars = ast_for_with_var(c, CHILD(n, 2)); From buildbot at python.org Fri Mar 16 06:37:59 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 16 Mar 2007 05:37:59 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070316053800.9D1BE1E4007@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/138 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From buildbot at python.org Fri Mar 16 06:44:34 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 16 Mar 2007 05:44:34 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 2.5 Message-ID: <20070316054434.7F8D01E4007@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%25202.5/builds/220 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_signal Traceback (most recent call last): File "./Lib/test/regrtest.py", line 549, in runtest_inner the_package = __import__(abstest, globals(), locals(), []) File "/net/ringneck/scratch1/nnorwitz/python/2.5.norwitz-tru64/build/Lib/test/test_signal.py", line 143, in print "KeyboardInterrupt (the alarm() went off)" File "/net/ringneck/scratch1/nnorwitz/python/2.5.norwitz-tru64/build/Lib/test/test_signal.py", line 49, in handlerB raise HandlerBCalled, args HandlerBCalled: (30, ) sincerely, -The Buildbot From buildbot at python.org Fri Mar 16 06:54:02 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 16 Mar 2007 05:54:02 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070316055403.4E8F11E4007@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/318 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings failed slave lost sincerely, -The Buildbot From python-checkins at python.org Fri Mar 16 08:55:12 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 16 Mar 2007 08:55:12 +0100 (CET) Subject: [Python-checkins] r54406 - in python/trunk: Lib/webbrowser.py Misc/NEWS Message-ID: <20070316075512.D5CB01E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 16 08:55:09 2007 New Revision: 54406 Modified: python/trunk/Lib/webbrowser.py python/trunk/Misc/NEWS Log: Bug #1681228: the webbrowser module now correctly uses the default GNOME or KDE browser, depending on whether there is a session of one of those present. Also, it tries the Windows default browser before trying Mozilla variants. (backport) Modified: python/trunk/Lib/webbrowser.py ============================================================================== --- python/trunk/Lib/webbrowser.py (original) +++ python/trunk/Lib/webbrowser.py Fri Mar 16 08:55:09 2007 @@ -437,19 +437,16 @@ # a console terminal or an X display to run. def register_X_browsers(): - # The default Gnome browser - if _iscommand("gconftool-2"): - # get the web browser string from gconftool - gc = 'gconftool-2 -g /desktop/gnome/url-handlers/http/command 2>/dev/null' - out = os.popen(gc) - commd = out.read().strip() - retncode = out.close() - - # if successful, register it - if retncode is None and commd: - register("gnome", None, BackgroundBrowser(commd.split())) - # First, the Mozilla/Netscape browsers + # The default GNOME browser + if "GNOME_DESKTOP_SESSION_ID" in os.environ and _iscommand("gnome-open"): + register("gnome-open", None, BackgroundBrowser("gnome-open")) + + # The default KDE browser + if "KDE_FULL_SESSION" in os.environ and _iscommand("kfmclient"): + register("kfmclient", Konqueror, Konqueror("kfmclient")) + + # The Mozilla/Netscape browsers for browser in ("mozilla-firefox", "firefox", "mozilla-firebird", "firebird", "seamonkey", "mozilla", "netscape"): @@ -508,17 +505,28 @@ if sys.platform[:3] == "win": class WindowsDefault(BaseBrowser): def open(self, url, new=0, autoraise=1): - os.startfile(url) - return True # Oh, my... + try: + os.startfile(url) + except WindowsError: + # [Error 22] No application is associated with the specified + # file for this operation: '' + return False + else: + return True _tryorder = [] _browsers = {} - # Prefer mozilla/netscape/opera if present + + # First try to use the default Windows browser + register("windows-default", WindowsDefault) + + # Detect some common Windows browsers, fallback to IE + iexplore = os.path.join(os.environ.get("PROGRAMFILES", "C:\\Program Files"), + "Internet Explorer\\IEXPLORE.EXE") for browser in ("firefox", "firebird", "seamonkey", "mozilla", - "netscape", "opera"): + "netscape", "opera", iexplore): if _iscommand(browser): register(browser, None, BackgroundBrowser(browser)) - register("windows-default", WindowsDefault) # # Platform support for MacOS Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 16 08:55:09 2007 @@ -179,6 +179,11 @@ Library ------- +- Bug #1681228: the webbrowser module now correctly uses the default + GNOME or KDE browser, depending on whether there is a session of one + of those present. Also, it tries the Windows default browser before + trying Mozilla variants. + - Patch #1681153: the wave module now closes a file object it opened if initialization failed. From python-checkins at python.org Fri Mar 16 09:22:42 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 16 Mar 2007 09:22:42 +0100 (CET) Subject: [Python-checkins] r54407 - in python/trunk: Doc/lib/libos.tex Lib/os.py Lib/test/test_os.py Misc/NEWS Message-ID: <20070316082242.2A24A1E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 16 09:22:40 2007 New Revision: 54407 Modified: python/trunk/Doc/lib/libos.tex python/trunk/Lib/os.py python/trunk/Lib/test/test_os.py python/trunk/Misc/NEWS Log: Patch #1273829: os.walk() now has a "followlinks" parameter. If set to True (which is not the default), it visits symlinks pointing to directories. Modified: python/trunk/Doc/lib/libos.tex ============================================================================== --- python/trunk/Doc/lib/libos.tex (original) +++ python/trunk/Doc/lib/libos.tex Fri Mar 16 09:22:40 2007 @@ -1233,7 +1233,8 @@ \end{funcdesc} \begin{funcdesc}{walk}{top\optional{, topdown\code{=True} - \optional{, onerror\code{=None}}}} + \optional{, onerror\code{=None}\optional{, + followlinks\code{=False}}}}} \index{directory!walking} \index{directory!traversal} \function{walk()} generates the file names in a directory tree, by @@ -1273,6 +1274,16 @@ to abort the walk. Note that the filename is available as the \code{filename} attribute of the exception object. +By default, \function{walk()} will not walk down into symbolic links that +resolve to directories. Set \var{followlinks} to True to visit directories +pointed to by symlinks, on systems that support them. + +\begin{notice} +Be aware that setting \var{followlinks} to true can lead to infinite recursion +if a link points to a parent directory of itself. \function{walk()} does not +keep track of the directories it visited already. +\end{notice} + \begin{notice} If you pass a relative pathname, don't change the current working directory between resumptions of \function{walk()}. \function{walk()} @@ -1280,15 +1291,6 @@ doesn't either. \end{notice} -\begin{notice} -On systems that support symbolic links, links to subdirectories appear -in \var{dirnames} lists, but \function{walk()} will not visit them -(infinite loops are hard to avoid when following symbolic links). -To visit linked directories, you can identify them with -\code{os.path.islink(\var{path})}, and invoke \code{walk(\var{path})} -on each directly. -\end{notice} - This example displays the number of bytes taken by non-directory files in each directory under the starting directory, except that it doesn't look under any CVS subdirectory: Modified: python/trunk/Lib/os.py ============================================================================== --- python/trunk/Lib/os.py (original) +++ python/trunk/Lib/os.py Fri Mar 16 09:22:40 2007 @@ -221,7 +221,7 @@ __all__.extend(["makedirs", "removedirs", "renames"]) -def walk(top, topdown=True, onerror=None): +def walk(top, topdown=True, onerror=None, followlinks=False): """Directory tree generator. For each directory in the directory tree rooted at top (including top @@ -257,6 +257,10 @@ to abort the walk. Note that the filename is available as the filename attribute of the exception object. + By default, os.walk does not follow symbolic links to subdirectories on + systems that support them. In order to get this functionality, set the + optional argument 'followlinks' to true. + Caution: if you pass a relative pathname for top, don't change the current working directory between resumptions of walk. walk never changes the current directory, and assumes that the client doesn't @@ -300,8 +304,8 @@ yield top, dirs, nondirs for name in dirs: path = join(top, name) - if not islink(path): - for x in walk(path, topdown, onerror): + if followlinks or not islink(path): + for x in walk(path, topdown, onerror, followlinks): yield x if not topdown: yield top, dirs, nondirs Modified: python/trunk/Lib/test/test_os.py ============================================================================== --- python/trunk/Lib/test/test_os.py (original) +++ python/trunk/Lib/test/test_os.py Fri Mar 16 09:22:40 2007 @@ -277,22 +277,34 @@ # SUB1/ a file kid and a directory kid # tmp2 # SUB11/ no kids - # SUB2/ just a file kid + # SUB2/ a file kid and a dirsymlink kid # tmp3 + # link/ a symlink to TESTFN.2 + # TESTFN.2/ + # tmp4 a lone file sub1_path = join(test_support.TESTFN, "SUB1") sub11_path = join(sub1_path, "SUB11") sub2_path = join(test_support.TESTFN, "SUB2") tmp1_path = join(test_support.TESTFN, "tmp1") tmp2_path = join(sub1_path, "tmp2") tmp3_path = join(sub2_path, "tmp3") + link_path = join(sub2_path, "link") + t2_path = join(test_support.TESTFN + ".2") + tmp4_path = join(test_support.TESTFN + ".2", "tmp4") # Create stuff. os.makedirs(sub11_path) os.makedirs(sub2_path) - for path in tmp1_path, tmp2_path, tmp3_path: + os.makedirs(t2_path) + for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: f = file(path, "w") f.write("I'm " + path + " and proud of it. Blame test_os.\n") f.close() + if hasattr(os, "symlink"): + os.symlink(os.path.join("..", "..", t2_path), link_path) + else: + # it must be a directory because the test expects that + os.mkdir(link_path) # Walk top-down. all = list(os.walk(test_support.TESTFN)) @@ -305,7 +317,7 @@ self.assertEqual(all[0], (test_support.TESTFN, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[1 + flipped], (sub1_path, ["SUB11"], ["tmp2"])) self.assertEqual(all[2 + flipped], (sub11_path, [], [])) - self.assertEqual(all[3 - 2 * flipped], (sub2_path, [], ["tmp3"])) + self.assertEqual(all[3 - 2 * flipped], (sub2_path, ["link"], ["tmp3"])) # Prune the search. all = [] @@ -317,7 +329,7 @@ dirs.remove('SUB1') self.assertEqual(len(all), 2) self.assertEqual(all[0], (test_support.TESTFN, ["SUB2"], ["tmp1"])) - self.assertEqual(all[1], (sub2_path, [], ["tmp3"])) + self.assertEqual(all[1], (sub2_path, ["link"], ["tmp3"])) # Walk bottom-up. all = list(os.walk(test_support.TESTFN, topdown=False)) @@ -330,7 +342,17 @@ self.assertEqual(all[3], (test_support.TESTFN, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[flipped], (sub11_path, [], [])) self.assertEqual(all[flipped + 1], (sub1_path, ["SUB11"], ["tmp2"])) - self.assertEqual(all[2 - 2 * flipped], (sub2_path, [], ["tmp3"])) + self.assertEqual(all[2 - 2 * flipped], (sub2_path, ["link"], ["tmp3"])) + + # Walk, following symlinks. + for root, dirs, files in os.walk(test_support.TESTFN, followlinks=True): + if root == link_path: + self.assertEqual(dirs, []) + self.assertEqual(files, ["tmp4"]) + break + else: + self.fail("Didn't follow symlink with followlinks=True") + # Tear everything down. This is a decent use for bottom-up on # Windows, which doesn't have a recursive delete command. The @@ -340,8 +362,14 @@ for name in files: os.remove(join(root, name)) for name in dirs: - os.rmdir(join(root, name)) + dirname = join(root, name) + if not os.path.islink(dirname): + os.rmdir(dirname) + else: + os.remove(dirname) os.rmdir(test_support.TESTFN) + os.unlink(tmp4_path) + os.rmdir(t2_path) class MakedirTests (unittest.TestCase): def setUp(self): Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 16 09:22:40 2007 @@ -179,6 +179,10 @@ Library ------- +- Patch #1273829: os.walk() now has a "followlinks" parameter. If set to + True (which is not the default), it visits symlinks pointing to + directories. + - Bug #1681228: the webbrowser module now correctly uses the default GNOME or KDE browser, depending on whether there is a session of one of those present. Also, it tries the Windows default browser before From python-checkins at python.org Fri Mar 16 09:24:23 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 16 Mar 2007 09:24:23 +0100 (CET) Subject: [Python-checkins] r54408 - python/trunk/Doc/lib/libos.tex Message-ID: <20070316082423.5996A1E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 16 09:24:21 2007 New Revision: 54408 Modified: python/trunk/Doc/lib/libos.tex Log: Add \versionadded tag. Modified: python/trunk/Doc/lib/libos.tex ============================================================================== --- python/trunk/Doc/lib/libos.tex (original) +++ python/trunk/Doc/lib/libos.tex Fri Mar 16 09:24:21 2007 @@ -1278,6 +1278,8 @@ resolve to directories. Set \var{followlinks} to True to visit directories pointed to by symlinks, on systems that support them. +\versionadded[The \var{followlinks} parameter]{2.6} + \begin{notice} Be aware that setting \var{followlinks} to true can lead to infinite recursion if a link points to a parent directory of itself. \function{walk()} does not From python-checkins at python.org Fri Mar 16 09:33:48 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 16 Mar 2007 09:33:48 +0100 (CET) Subject: [Python-checkins] r54409 - python/trunk/Doc/lib/libfuncs.tex Message-ID: <20070316083348.91B9F1E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 16 09:33:47 2007 New Revision: 54409 Modified: python/trunk/Doc/lib/libfuncs.tex Log: RFE #1670167: fix in isinstance() docs. Modified: python/trunk/Doc/lib/libfuncs.tex ============================================================================== --- python/trunk/Doc/lib/libfuncs.tex (original) +++ python/trunk/Doc/lib/libfuncs.tex Fri Mar 16 09:33:47 2007 @@ -567,8 +567,9 @@ \begin{funcdesc}{isinstance}{object, classinfo} Return true if the \var{object} argument is an instance of the \var{classinfo} argument, or of a (direct or indirect) subclass - thereof. Also return true if \var{classinfo} is a type object and - \var{object} is an object of that type. If \var{object} is not a + thereof. Also return true if \var{classinfo} is a type object + (new-style class) and \var{object} is an object of that type or of a + (direct or indirect) subclass thereof. If \var{object} is not a class instance or an object of the given type, the function always returns false. If \var{classinfo} is neither a class object nor a type object, it may be a tuple of class or type objects, or may From python-checkins at python.org Fri Mar 16 09:33:52 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 16 Mar 2007 09:33:52 +0100 (CET) Subject: [Python-checkins] r54410 - python/branches/release25-maint/Doc/lib/libfuncs.tex Message-ID: <20070316083352.03FBD1E400F@bag.python.org> Author: georg.brandl Date: Fri Mar 16 09:33:51 2007 New Revision: 54410 Modified: python/branches/release25-maint/Doc/lib/libfuncs.tex Log: RFE #1670167: fix in isinstance() docs. (backport from rev. 54409) Modified: python/branches/release25-maint/Doc/lib/libfuncs.tex ============================================================================== --- python/branches/release25-maint/Doc/lib/libfuncs.tex (original) +++ python/branches/release25-maint/Doc/lib/libfuncs.tex Fri Mar 16 09:33:51 2007 @@ -548,8 +548,9 @@ \begin{funcdesc}{isinstance}{object, classinfo} Return true if the \var{object} argument is an instance of the \var{classinfo} argument, or of a (direct or indirect) subclass - thereof. Also return true if \var{classinfo} is a type object and - \var{object} is an object of that type. If \var{object} is not a + thereof. Also return true if \var{classinfo} is a type object + (new-style class) and \var{object} is an object of that type or of a + (direct or indirect) subclass thereof. If \var{object} is not a class instance or an object of the given type, the function always returns false. If \var{classinfo} is neither a class object nor a type object, it may be a tuple of class or type objects, or may From python-checkins at python.org Fri Mar 16 09:45:34 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 16 Mar 2007 09:45:34 +0100 (CET) Subject: [Python-checkins] r54411 - peps/trunk/pep-3112.txt Message-ID: <20070316084534.1549F1E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 16 09:45:32 2007 New Revision: 54411 Modified: peps/trunk/pep-3112.txt Log: Fix ReST markup wrt. literal code blocks. Modified: peps/trunk/pep-3112.txt ============================================================================== --- peps/trunk/pep-3112.txt (original) +++ peps/trunk/pep-3112.txt Fri Mar 16 09:45:32 2007 @@ -23,22 +23,22 @@ Motivation ========== -Existing spellings of an ASCII string in Python 3000 include: +Existing spellings of an ASCII string in Python 3000 include:: bytes('Hello world', 'ascii') 'Hello world'.encode('ascii') -The proposed syntax is: +The proposed syntax is:: b'Hello world' -Existing spellings of an 8-bit binary sequence in Python 3000 include: +Existing spellings of an 8-bit binary sequence in Python 3000 include:: bytes([0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00]) bytes('\x7fELF\x01\x01\x01\0', 'latin-1') '7f454c4601010100'.decode('hex') -The proposed syntax is: +The proposed syntax is:: b'\x7f\x45\x4c\x46\x01\x01\x01\x00' b'\x7fELF\x01\x01\x01\0' @@ -46,12 +46,12 @@ In both cases, the advantages of the new syntax are brevity, some small efficiency gain, and the detection of encoding errors at compile time rather than at runtime. The brevity benefit is especially felt -when using the string-like methods of bytes objects: +when using the string-like methods of bytes objects:: lines = bdata.split(bytes('\n', 'ascii')) # existing syntax lines = bdata.split(b'\n') # proposed syntax -And when converting code from Python 2.x to Python 3000: +And when converting code from Python 2.x to Python 3000:: sok.send('EXIT\r\n') # Python 2.x sok.send('EXIT\r\n'.encode('ascii')) # Python 3000 existing From python-checkins at python.org Fri Mar 16 12:59:44 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Fri, 16 Mar 2007 12:59:44 +0100 (CET) Subject: [Python-checkins] r54412 - in python/trunk: Doc/ref/ref3.tex Lib/test/test_descr.py Misc/ACKS Misc/NEWS Objects/typeobject.c Message-ID: <20070316115944.E69DA1E400D@bag.python.org> Author: ziga.seilnacht Date: Fri Mar 16 12:59:38 2007 New Revision: 54412 Modified: python/trunk/Doc/ref/ref3.tex python/trunk/Lib/test/test_descr.py python/trunk/Misc/ACKS python/trunk/Misc/NEWS python/trunk/Objects/typeobject.c Log: Patch #1623563: allow __class__ assignment for classes with __slots__. The old and the new class are still required to have the same slot names, but the order in which they are specified is not relevant. Modified: python/trunk/Doc/ref/ref3.tex ============================================================================== --- python/trunk/Doc/ref/ref3.tex (original) +++ python/trunk/Doc/ref/ref3.tex Fri Mar 16 12:59:38 2007 @@ -1593,6 +1593,11 @@ Mappings may also be used; however, in the future, special meaning may be assigned to the values corresponding to each key. +\item \var{__class__} assignment works only if both classes have the +same \var{__slots__}. +\versionchanged[Previously, \var{__class__} assignment raised an error +if either new or old class had \var{__slots__}]{2.6} + \end{itemize} @@ -2223,3 +2228,6 @@ Python \keyword{with} statement.} \end{seealso} + + + Modified: python/trunk/Lib/test/test_descr.py ============================================================================== --- python/trunk/Lib/test/test_descr.py (original) +++ python/trunk/Lib/test/test_descr.py Fri Mar 16 12:59:38 2007 @@ -2853,6 +2853,51 @@ cant(o, type(1)) cant(o, type(None)) del o + class G(object): + __slots__ = ["a", "b"] + class H(object): + __slots__ = ["b", "a"] + try: + unicode + except NameError: + class I(object): + __slots__ = ["a", "b"] + else: + class I(object): + __slots__ = [unicode("a"), unicode("b")] + class J(object): + __slots__ = ["c", "b"] + class K(object): + __slots__ = ["a", "b", "d"] + class L(H): + __slots__ = ["e"] + class M(I): + __slots__ = ["e"] + class N(J): + __slots__ = ["__weakref__"] + class P(J): + __slots__ = ["__dict__"] + class Q(J): + pass + class R(J): + __slots__ = ["__dict__", "__weakref__"] + + for cls, cls2 in ((G, H), (G, I), (I, H), (Q, R), (R, Q)): + x = cls() + x.a = 1 + x.__class__ = cls2 + verify(x.__class__ is cls2, + "assigning %r as __class__ for %r silently failed" % (cls2, x)) + vereq(x.a, 1) + x.__class__ = cls + verify(x.__class__ is cls, + "assigning %r as __class__ for %r silently failed" % (cls, x)) + vereq(x.a, 1) + for cls in G, J, K, L, M, N, P, R, list, Int: + for cls2 in G, J, K, L, M, N, P, R, list, Int: + if cls is cls2: + continue + cant(cls(), cls2) def setdict(): if verbose: print "Testing __dict__ assignment..." Modified: python/trunk/Misc/ACKS ============================================================================== --- python/trunk/Misc/ACKS (original) +++ python/trunk/Misc/ACKS Fri Mar 16 12:59:38 2007 @@ -276,6 +276,7 @@ Ivan Herman J?rgen Hermann Gary Herron +Thomas Herve Bernhard Herzog Magnus L. Hetland Raymond Hettinger Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 16 12:59:38 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #1623563: allow __class__ assignment for classes with __slots__. + The old and the new class are still required to have the same slot names. + - Patch #1642547: Fix an error/crash when encountering syntax errors in complex if statements. Modified: python/trunk/Objects/typeobject.c ============================================================================== --- python/trunk/Objects/typeobject.c (original) +++ python/trunk/Objects/typeobject.c Fri Mar 16 12:59:38 2007 @@ -1844,8 +1844,11 @@ } } - /* Copy slots into yet another tuple, demangling names */ - newslots = PyTuple_New(nslots - add_dict - add_weak); + /* Copy slots into a list, mangle names and sort them. + Sorted names are needed for __class__ assignment. + Convert them back to tuple at the end. + */ + newslots = PyList_New(nslots - add_dict - add_weak); if (newslots == NULL) goto bad_slots; for (i = j = 0; i < nslots; i++) { @@ -1858,13 +1861,23 @@ tmp =_Py_Mangle(name, tmp); if (!tmp) goto bad_slots; - PyTuple_SET_ITEM(newslots, j, tmp); + PyList_SET_ITEM(newslots, j, tmp); j++; } assert(j == nslots - add_dict - add_weak); nslots = j; Py_DECREF(slots); - slots = newslots; + if (PyList_Sort(newslots) == -1) { + Py_DECREF(bases); + Py_DECREF(newslots); + return NULL; + } + slots = PyList_AsTuple(newslots); + Py_DECREF(newslots); + if (slots == NULL) { + Py_DECREF(bases); + return NULL; + } /* Secondary bases may provide weakrefs or dict */ if (nbases > 1 && @@ -2481,6 +2494,7 @@ { PyTypeObject *base = a->tp_base; Py_ssize_t size; + PyObject *slots_a, *slots_b; if (base != b->tp_base) return 0; @@ -2491,6 +2505,15 @@ size += sizeof(PyObject *); if (a->tp_weaklistoffset == size && b->tp_weaklistoffset == size) size += sizeof(PyObject *); + + /* Check slots compliance */ + slots_a = ((PyHeapTypeObject *)a)->ht_slots; + slots_b = ((PyHeapTypeObject *)b)->ht_slots; + if (slots_a && slots_b) { + if (PyObject_Compare(slots_a, slots_b) != 0) + return 0; + size += sizeof(PyObject *) * PyTuple_GET_SIZE(slots_a); + } return size == a->tp_basicsize && size == b->tp_basicsize; } From buildbot at python.org Fri Mar 16 13:07:44 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 16 Mar 2007 12:07:44 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 trunk Message-ID: <20070316120744.75E341E4007@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%2520trunk/builds/1542 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl,ziga.seilnacht Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Fri Mar 16 13:11:12 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Fri, 16 Mar 2007 13:11:12 +0100 (CET) Subject: [Python-checkins] r54413 - python/trunk/Doc/ref/ref3.tex Message-ID: <20070316121112.026A71E4015@bag.python.org> Author: ziga.seilnacht Date: Fri Mar 16 13:11:11 2007 New Revision: 54413 Modified: python/trunk/Doc/ref/ref3.tex Log: Whitespace cleanup. Also remove the empty lines from the previous check in. Modified: python/trunk/Doc/ref/ref3.tex ============================================================================== --- python/trunk/Doc/ref/ref3.tex (original) +++ python/trunk/Doc/ref/ref3.tex Fri Mar 16 13:11:11 2007 @@ -219,7 +219,7 @@ \indexii{integer}{representation} \item[Floating point numbers] -These represent machine-level double precision floating point numbers. +These represent machine-level double precision floating point numbers. You are at the mercy of the underlying machine architecture (and C or Java implementation) for the accepted range and handling of overflow. Python does not support single-precision floating point numbers; the @@ -471,7 +471,7 @@ \obindex{function} \obindex{user-defined function} -Special attributes: +Special attributes: \begin{tableiii}{lll}{member}{Attribute}{Meaning}{} \lineiii{func_doc}{The function's documentation string, or @@ -861,12 +861,12 @@ \begin{description} \item[Code objects] -Code objects represent \emph{byte-compiled} executable Python code, or +Code objects represent \emph{byte-compiled} executable Python code, or \emph{bytecode}. The difference between a code object and a function object is that the function object contains an explicit reference to the function's globals (the module in which it -was defined), while a code object contains no context; +was defined), while a code object contains no context; also the default argument values are stored in the function object, not in the code object (because they represent values calculated at run-time). Unlike function objects, code objects are immutable and @@ -1070,7 +1070,7 @@ %========================================================================= \section{New-style and classic classes} -Classes and instances come in two flavors: old-style or classic, and new-style. +Classes and instances come in two flavors: old-style or classic, and new-style. Up to Python 2.1, old-style classes were the only flavour available to the user. The concept of (old-style) class is unrelated to the concept of type: if @@ -1245,7 +1245,7 @@ string object. If a class defines \method{__repr__()} but not \method{__str__()}, then \method{__repr__()} is also used when an ``informal'' string -representation of instances of that class is required. +representation of instances of that class is required. This is typically used for debugging, so it is important that the representation is information-rich and unambiguous. @@ -1403,7 +1403,7 @@ dictionary). \var{name} is the attribute name, \var{value} is the value to be assigned to it. -If \method{__setattr__()} wants to assign to an instance attribute, it +If \method{__setattr__()} wants to assign to an instance attribute, it should not simply execute \samp{self.\var{name} = value} --- this would cause a recursive call to itself. Instead, it should insert the value in the dictionary of instance attributes, e.g., @@ -1426,8 +1426,8 @@ \begin{methoddesc}[object]{__getattribute__}{self, name} Called unconditionally to implement attribute accesses for instances -of the class. If the class also defines \method{__getattr__()}, the latter -will not be called unless \method{__getattribute__()} either calls it +of the class. If the class also defines \method{__getattr__()}, the latter +will not be called unless \method{__getattribute__()} either calls it explicitly or raises an \exception{AttributeError}. This method should return the (computed) attribute value or raise an \exception{AttributeError} exception. @@ -1479,7 +1479,7 @@ The default behavior for attribute access is to get, set, or delete the attribute from an object's dictionary. For instance, \code{a.x} has a lookup chain starting with \code{a.__dict__['x']}, then -\code{type(a).__dict__['x']}, and continuing +\code{type(a).__dict__['x']}, and continuing through the base classes of \code{type(a)} excluding metaclasses. However, if the looked-up value is an object defining one of the descriptor @@ -1493,14 +1493,14 @@ How the arguments are assembled depends on \code{a}: \begin{itemize} - + \item[Direct Call] The simplest and least common call is when user code directly invokes a descriptor method: \code{x.__get__(a)}. \item[Instance Binding] If binding to a new-style object instance, \code{a.x} is transformed into the call: \code{type(a).__dict__['x'].__get__(a, type(a))}. - + \item[Class Binding] If binding to a new-style class, \code{A.x} is transformed into the call: \code{A.__dict__['x'].__get__(None, A)}. @@ -1509,7 +1509,7 @@ \code{obj.__class__.__mro__} for the base class \code{A} immediately preceding \code{B} and then invokes the descriptor with the call: \code{A.__dict__['m'].__get__(obj, A)}. - + \end{itemize} For instance bindings, the precedence of descriptor invocation depends @@ -1522,7 +1522,7 @@ Python methods (including \function{staticmethod()} and \function{classmethod()}) are implemented as non-data descriptors. Accordingly, instances can redefine and override methods. This allows individual instances to acquire -behaviors that differ from other instances of the same class. +behaviors that differ from other instances of the same class. The \function{property()} function is implemented as a data descriptor. Accordingly, instances cannot override the behavior of a property. @@ -1540,14 +1540,14 @@ variables and reserves just enough space in each instance to hold a value for each variable. Space is saved because \var{__dict__} is not created for each instance. - + \begin{datadesc}{__slots__} This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances. If defined in a new-style class, \var{__slots__} reserves space for the declared variables and prevents the automatic creation of \var{__dict__} and \var{__weakref__} for each instance. -\versionadded{2.2} +\versionadded{2.2} \end{datadesc} \noindent @@ -1559,23 +1559,23 @@ variables not listed in the \var{__slots__} definition. Attempts to assign to an unlisted variable name raises \exception{AttributeError}. If dynamic assignment of new variables is desired, then add \code{'__dict__'} to the -sequence of strings in the \var{__slots__} declaration. +sequence of strings in the \var{__slots__} declaration. \versionchanged[Previously, adding \code{'__dict__'} to the \var{__slots__} declaration would not enable the assignment of new attributes not -specifically listed in the sequence of instance variable names]{2.3} +specifically listed in the sequence of instance variable names]{2.3} \item Without a \var{__weakref__} variable for each instance, classes defining \var{__slots__} do not support weak references to its instances. If weak reference support is needed, then add \code{'__weakref__'} to the -sequence of strings in the \var{__slots__} declaration. +sequence of strings in the \var{__slots__} declaration. \versionchanged[Previously, adding \code{'__weakref__'} to the \var{__slots__} -declaration would not enable support for weak references]{2.3} +declaration would not enable support for weak references]{2.3} \item \var{__slots__} are implemented at the class level by creating descriptors (\ref{descriptors}) for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by \var{__slots__}; otherwise, the class attribute would -overwrite the descriptor assignment. +overwrite the descriptor assignment. \item If a class defines a slot also defined in a base class, the instance variable defined by the base class slot is inaccessible (except by retrieving @@ -1584,14 +1584,14 @@ \item The action of a \var{__slots__} declaration is limited to the class where it is defined. As a result, subclasses will have a \var{__dict__} -unless they also define \var{__slots__}. +unless they also define \var{__slots__}. \item \var{__slots__} do not work for classes derived from ``variable-length'' -built-in types such as \class{long}, \class{str} and \class{tuple}. +built-in types such as \class{long}, \class{str} and \class{tuple}. \item Any non-string iterable may be assigned to \var{__slots__}. Mappings may also be used; however, in the future, special meaning may -be assigned to the values corresponding to each key. +be assigned to the values corresponding to each key. \item \var{__class__} assignment works only if both classes have the same \var{__slots__}. @@ -1622,7 +1622,7 @@ This variable can be any callable accepting arguments for \code{name}, \code{bases}, and \code{dict}. Upon class creation, the callable is used instead of the built-in \function{type()}. -\versionadded{2.2} +\versionadded{2.2} \end{datadesc} The appropriate metaclass is determined by the following precedence rules: @@ -1639,7 +1639,7 @@ \item Otherwise, the old-style, classic metaclass (types.ClassType) is used. -\end{itemize} +\end{itemize} The potential uses for metaclasses are boundless. Some ideas that have been explored including logging, interface checking, automatic delegation, @@ -1672,15 +1672,15 @@ that mappings provide the methods \method{keys()}, \method{values()}, \method{items()}, \method{has_key()}, \method{get()}, \method{clear()}, \method{setdefault()}, \method{iterkeys()}, \method{itervalues()}, -\method{iteritems()}, \method{pop()}, \method{popitem()}, +\method{iteritems()}, \method{pop()}, \method{popitem()}, \method{copy()}, and \method{update()} behaving similar to those for Python's standard dictionary objects. The \module{UserDict} module provides a \class{DictMixin} class to help create those methods from a base set of \method{__getitem__()}, \method{__setitem__()}, -\method{__delitem__()}, and \method{keys()}. +\method{__delitem__()}, and \method{keys()}. Mutable sequences should provide methods \method{append()}, \method{count()}, \method{index()}, -\method{extend()}, +\method{extend()}, \method{insert()}, \method{pop()}, \method{remove()}, \method{reverse()} and \method{sort()}, like Python standard list objects. Finally, sequence types should implement addition (meaning concatenation) and @@ -1703,12 +1703,12 @@ \ttindex{items()} \ttindex{iterkeys()} \ttindex{itervalues()} - \ttindex{iteritems()} + \ttindex{iteritems()} \ttindex{has_key()} \ttindex{get()} \ttindex{setdefault()} - \ttindex{pop()} - \ttindex{popitem()} + \ttindex{pop()} + \ttindex{popitem()} \ttindex{clear()} \ttindex{copy()} \ttindex{update()} @@ -1716,7 +1716,7 @@ \withsubitem{(sequence object method)}{ \ttindex{append()} \ttindex{count()} - \ttindex{extend()} + \ttindex{extend()} \ttindex{index()} \ttindex{insert()} \ttindex{pop()} @@ -1730,7 +1730,7 @@ \ttindex{__rmul__()} \ttindex{__imul__()} \ttindex{__contains__()} - \ttindex{__iter__()}} + \ttindex{__iter__()}} \withsubitem{(numeric object method)}{\ttindex{__coerce__()}} \begin{methoddesc}[container object]{__len__}{self} @@ -1753,7 +1753,7 @@ (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. +\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.} @@ -1952,7 +1952,7 @@ \methodline[numeric object]{__rmul__}{self, other} \methodline[numeric object]{__rdiv__}{self, other} \methodline[numeric object]{__rtruediv__}{self, other} -\methodline[numeric object]{__rfloordiv__}{self, other} +\methodline[numeric object]{__rfloordiv__}{self, other} \methodline[numeric object]{__rmod__}{self, other} \methodline[numeric object]{__rdivmod__}{self, other} \methodline[numeric object]{__rpow__}{self, other} @@ -1973,7 +1973,7 @@ For operands of the same type, it is assumed that if the non-reflected method (such as \method{__add__()}) fails the operation is not supported, which is why the reflected method - is not called.} + is not called.} For instance, to evaluate the expression \var{x}\code{-}\var{y}, where \var{y} is an instance of a class that has an \method{__rsub__()} method, \code{\var{y}.__rsub__(\var{x})} @@ -1998,7 +1998,7 @@ \methodline[numeric object]{__idiv__}{self, other} \methodline[numeric object]{__itruediv__}{self, other} \methodline[numeric object]{__ifloordiv__}{self, other} -\methodline[numeric object]{__imod__}{self, other} +\methodline[numeric object]{__imod__}{self, other} \methodline[numeric object]{__ipow__}{self, other\optional{, modulo}} \methodline[numeric object]{__ilshift__}{self, other} \methodline[numeric object]{__irshift__}{self, other} @@ -2228,6 +2228,3 @@ Python \keyword{with} statement.} \end{seealso} - - - From python-checkins at python.org Fri Mar 16 15:49:14 2007 From: python-checkins at python.org (jeremy.hylton) Date: Fri, 16 Mar 2007 15:49:14 +0100 (CET) Subject: [Python-checkins] r54414 - python/trunk/Objects/object.c Message-ID: <20070316144914.45BE91E4007@bag.python.org> Author: jeremy.hylton Date: Fri Mar 16 15:49:11 2007 New Revision: 54414 Modified: python/trunk/Objects/object.c Log: Remove warning: funcion declaration isn't a prototype Modified: python/trunk/Objects/object.c ============================================================================== --- python/trunk/Objects/object.c (original) +++ python/trunk/Objects/object.c Fri Mar 16 15:49:11 2007 @@ -1666,7 +1666,7 @@ /* Helper for PyObject_Dir without arguments: returns the local scope. */ static PyObject * -_dir_locals() +_dir_locals(void) { PyObject *names; PyObject *locals = PyEval_GetLocals(); @@ -2209,4 +2209,3 @@ #ifdef __cplusplus } #endif - From buildbot at python.org Fri Mar 16 16:33:22 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 16 Mar 2007 15:33:22 +0000 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk Message-ID: <20070316153322.8FE711E4007@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%2520trunk/builds/1870 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: jeremy.hylton,ziga.seilnacht Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_threadedtempfile make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Fri Mar 16 16:59:50 2007 From: python-checkins at python.org (jeremy.hylton) Date: Fri, 16 Mar 2007 16:59:50 +0100 (CET) Subject: [Python-checkins] r54415 - python/trunk/Python/ast.c Message-ID: <20070316155950.8AE821E400D@bag.python.org> Author: jeremy.hylton Date: Fri Mar 16 16:59:47 2007 New Revision: 54415 Modified: python/trunk/Python/ast.c Log: Clean up formatting of this file. The file should now follow PEP 7, except that it uses 4 space indents (in the style of Py3k). This particular code would be really hard to read with the regular tab idents. Other changes: - reflow long lines - change multi-line conditionals to have test at end of line Modified: python/trunk/Python/ast.c ============================================================================== --- python/trunk/Python/ast.c (original) +++ python/trunk/Python/ast.c Fri Mar 16 16:59:47 2007 @@ -25,7 +25,8 @@ static expr_ty ast_for_expr(struct compiling *, const node *); static stmt_ty ast_for_stmt(struct compiling *, const node *); static asdl_seq *ast_for_suite(struct compiling *, const node *); -static asdl_seq *ast_for_exprlist(struct compiling *, const node *, expr_context_ty); +static asdl_seq *ast_for_exprlist(struct compiling *, const node *, + expr_context_ty); static expr_ty ast_for_testlist(struct compiling *, const node *); static expr_ty ast_for_testlist_gexp(struct compiling *, const node *); @@ -37,7 +38,7 @@ static PyObject *parsestrplus(struct compiling *, const node *n); #ifndef LINENO -#define LINENO(n) ((n)->n_lineno) +#define LINENO(n) ((n)->n_lineno) #endif static identifier @@ -62,7 +63,7 @@ { PyObject *u = Py_BuildValue("zi", errstr, LINENO(n)); if (!u) - return 0; + return 0; PyErr_SetObject(PyExc_SyntaxError, u); Py_DECREF(u); return 0; @@ -76,36 +77,36 @@ assert(PyErr_Occurred()); if (!PyErr_ExceptionMatches(PyExc_SyntaxError)) - return; + return; PyErr_Fetch(&type, &value, &tback); errstr = PyTuple_GetItem(value, 0); if (!errstr) - return; + return; Py_INCREF(errstr); lineno = PyInt_AsLong(PyTuple_GetItem(value, 1)); if (lineno == -1) { - Py_DECREF(errstr); - return; + Py_DECREF(errstr); + return; } Py_DECREF(value); loc = PyErr_ProgramText(filename, lineno); if (!loc) { - Py_INCREF(Py_None); - loc = Py_None; + Py_INCREF(Py_None); + loc = Py_None; } tmp = Py_BuildValue("(zlOO)", filename, lineno, Py_None, loc); Py_DECREF(loc); if (!tmp) { - Py_DECREF(errstr); - return; + Py_DECREF(errstr); + return; } value = PyTuple_Pack(2, errstr, tmp); Py_DECREF(errstr); Py_DECREF(tmp); if (!value) - return; + return; PyErr_Restore(type, value, tback); } @@ -130,41 +131,41 @@ node *ch; switch (TYPE(n)) { - case single_input: - if (TYPE(CHILD(n, 0)) == NEWLINE) - return 0; - else - return num_stmts(CHILD(n, 0)); - case file_input: - l = 0; - for (i = 0; i < NCH(n); i++) { - ch = CHILD(n, i); - if (TYPE(ch) == stmt) - l += num_stmts(ch); - } - return l; - case stmt: - return num_stmts(CHILD(n, 0)); - case compound_stmt: - return 1; - case simple_stmt: - return NCH(n) / 2; /* Divide by 2 to remove count of semi-colons */ - case suite: - if (NCH(n) == 1) - return num_stmts(CHILD(n, 0)); - else { - l = 0; - for (i = 2; i < (NCH(n) - 1); i++) - l += num_stmts(CHILD(n, i)); - return l; - } - default: { - char buf[128]; - - sprintf(buf, "Non-statement found: %d %d\n", - TYPE(n), NCH(n)); - Py_FatalError(buf); - } + case single_input: + if (TYPE(CHILD(n, 0)) == NEWLINE) + return 0; + else + return num_stmts(CHILD(n, 0)); + case file_input: + l = 0; + for (i = 0; i < NCH(n); i++) { + ch = CHILD(n, i); + if (TYPE(ch) == stmt) + l += num_stmts(ch); + } + return l; + case stmt: + return num_stmts(CHILD(n, 0)); + case compound_stmt: + return 1; + case simple_stmt: + return NCH(n) / 2; /* Divide by 2 to remove count of semi-colons */ + case suite: + if (NCH(n) == 1) + return num_stmts(CHILD(n, 0)); + else { + l = 0; + for (i = 2; i < (NCH(n) - 1); i++) + l += num_stmts(CHILD(n, i)); + return l; + } + default: { + char buf[128]; + + sprintf(buf, "Non-statement found: %d %d\n", + TYPE(n), NCH(n)); + Py_FatalError(buf); + } } assert(0); return 0; @@ -175,7 +176,7 @@ mod_ty PyAST_FromNode(const node *n, PyCompilerFlags *flags, const char *filename, - PyArena *arena) + PyArena *arena) { int i, j, k, num; asdl_seq *stmts = NULL; @@ -184,96 +185,96 @@ struct compiling c; if (flags && flags->cf_flags & PyCF_SOURCE_IS_UTF8) { - c.c_encoding = "utf-8"; - if (TYPE(n) == encoding_decl) { - ast_error(n, "encoding declaration in Unicode string"); - goto error; - } + c.c_encoding = "utf-8"; + if (TYPE(n) == encoding_decl) { + ast_error(n, "encoding declaration in Unicode string"); + goto error; + } } else if (TYPE(n) == encoding_decl) { - c.c_encoding = STR(n); - n = CHILD(n, 0); + c.c_encoding = STR(n); + n = CHILD(n, 0); } else { - c.c_encoding = NULL; + c.c_encoding = NULL; } c.c_arena = arena; k = 0; switch (TYPE(n)) { - case file_input: - stmts = asdl_seq_new(num_stmts(n), arena); - if (!stmts) - return NULL; - for (i = 0; i < NCH(n) - 1; i++) { - ch = CHILD(n, i); - if (TYPE(ch) == NEWLINE) - continue; - REQ(ch, stmt); - num = num_stmts(ch); - if (num == 1) { - s = ast_for_stmt(&c, ch); - if (!s) - goto error; - asdl_seq_SET(stmts, k++, s); - } - else { - ch = CHILD(ch, 0); - REQ(ch, simple_stmt); - for (j = 0; j < num; j++) { - s = ast_for_stmt(&c, CHILD(ch, j * 2)); - if (!s) - goto error; - asdl_seq_SET(stmts, k++, s); - } - } - } - return Module(stmts, arena); - case eval_input: { - expr_ty testlist_ast; - - /* XXX Why not gen_for here? */ - testlist_ast = ast_for_testlist(&c, CHILD(n, 0)); - if (!testlist_ast) - goto error; - return Expression(testlist_ast, arena); - } - case single_input: - if (TYPE(CHILD(n, 0)) == NEWLINE) { - stmts = asdl_seq_new(1, arena); - if (!stmts) - goto error; - asdl_seq_SET(stmts, 0, Pass(n->n_lineno, n->n_col_offset, - arena)); - return Interactive(stmts, arena); - } - else { - n = CHILD(n, 0); - num = num_stmts(n); - stmts = asdl_seq_new(num, arena); - if (!stmts) - goto error; - if (num == 1) { - s = ast_for_stmt(&c, n); - if (!s) - goto error; - asdl_seq_SET(stmts, 0, s); - } - else { - /* Only a simple_stmt can contain multiple statements. */ - REQ(n, simple_stmt); - for (i = 0; i < NCH(n); i += 2) { - if (TYPE(CHILD(n, i)) == NEWLINE) - break; - s = ast_for_stmt(&c, CHILD(n, i)); - if (!s) - goto error; - asdl_seq_SET(stmts, i / 2, s); - } - } - - return Interactive(stmts, arena); - } - default: - goto error; + case file_input: + stmts = asdl_seq_new(num_stmts(n), arena); + if (!stmts) + return NULL; + for (i = 0; i < NCH(n) - 1; i++) { + ch = CHILD(n, i); + if (TYPE(ch) == NEWLINE) + continue; + REQ(ch, stmt); + num = num_stmts(ch); + if (num == 1) { + s = ast_for_stmt(&c, ch); + if (!s) + goto error; + asdl_seq_SET(stmts, k++, s); + } + else { + ch = CHILD(ch, 0); + REQ(ch, simple_stmt); + for (j = 0; j < num; j++) { + s = ast_for_stmt(&c, CHILD(ch, j * 2)); + if (!s) + goto error; + asdl_seq_SET(stmts, k++, s); + } + } + } + return Module(stmts, arena); + case eval_input: { + expr_ty testlist_ast; + + /* XXX Why not gen_for here? */ + testlist_ast = ast_for_testlist(&c, CHILD(n, 0)); + if (!testlist_ast) + goto error; + return Expression(testlist_ast, arena); + } + case single_input: + if (TYPE(CHILD(n, 0)) == NEWLINE) { + stmts = asdl_seq_new(1, arena); + if (!stmts) + goto error; + asdl_seq_SET(stmts, 0, Pass(n->n_lineno, n->n_col_offset, + arena)); + return Interactive(stmts, arena); + } + else { + n = CHILD(n, 0); + num = num_stmts(n); + stmts = asdl_seq_new(num, arena); + if (!stmts) + goto error; + if (num == 1) { + s = ast_for_stmt(&c, n); + if (!s) + goto error; + asdl_seq_SET(stmts, 0, s); + } + else { + /* Only a simple_stmt can contain multiple statements. */ + REQ(n, simple_stmt); + for (i = 0; i < NCH(n); i += 2) { + if (TYPE(CHILD(n, i)) == NEWLINE) + break; + s = ast_for_stmt(&c, CHILD(n, i)); + if (!s) + goto error; + asdl_seq_SET(stmts, i / 2, s); + } + } + + return Interactive(stmts, arena); + } + default: + goto error; } error: ast_error_finish(filename); @@ -287,30 +288,30 @@ get_operator(const node *n) { switch (TYPE(n)) { - case VBAR: - return BitOr; - case CIRCUMFLEX: - return BitXor; - case AMPER: - return BitAnd; - case LEFTSHIFT: - return LShift; - case RIGHTSHIFT: - return RShift; - case PLUS: - return Add; - case MINUS: - return Sub; - case STAR: - return Mult; - case SLASH: - return Div; - case DOUBLESLASH: - return FloorDiv; - case PERCENT: - return Mod; - default: - return (operator_ty)0; + case VBAR: + return BitOr; + case CIRCUMFLEX: + return BitXor; + case AMPER: + return BitAnd; + case LEFTSHIFT: + return LShift; + case RIGHTSHIFT: + return RShift; + case PLUS: + return Add; + case MINUS: + return Sub; + case STAR: + return Mult; + case SLASH: + return Div; + case DOUBLESLASH: + return FloorDiv; + case PERCENT: + return Mod; + default: + return (operator_ty)0; } } @@ -340,93 +341,93 @@ assert(ctx != AugStore && ctx != AugLoad); switch (e->kind) { - case Attribute_kind: - if (ctx == Store && - !strcmp(PyString_AS_STRING(e->v.Attribute.attr), "None")) { - return ast_error(n, "assignment to None"); - } - e->v.Attribute.ctx = ctx; - break; - case Subscript_kind: - e->v.Subscript.ctx = ctx; - break; - case Name_kind: - if (ctx == Store && - !strcmp(PyString_AS_STRING(e->v.Name.id), "None")) { - return ast_error(n, "assignment to None"); - } - e->v.Name.ctx = ctx; - break; - case List_kind: - e->v.List.ctx = ctx; - s = e->v.List.elts; - break; - case Tuple_kind: - if (asdl_seq_LEN(e->v.Tuple.elts) == 0) - return ast_error(n, "can't assign to ()"); - e->v.Tuple.ctx = ctx; - s = e->v.Tuple.elts; - break; - case Lambda_kind: - expr_name = "lambda"; - break; - case Call_kind: - expr_name = "function call"; - break; - case BoolOp_kind: - case BinOp_kind: - case UnaryOp_kind: - expr_name = "operator"; - break; - case GeneratorExp_kind: - expr_name = "generator expression"; - break; - case Yield_kind: - expr_name = "yield expression"; - break; - case ListComp_kind: - expr_name = "list comprehension"; - break; - case Dict_kind: - case Num_kind: - case Str_kind: - expr_name = "literal"; - break; - case Compare_kind: - expr_name = "comparison"; - break; - case Repr_kind: - expr_name = "repr"; - break; - case IfExp_kind: - expr_name = "conditional expression"; - break; - default: - PyErr_Format(PyExc_SystemError, - "unexpected expression in assignment %d (line %d)", - e->kind, e->lineno); - return 0; + case Attribute_kind: + if (ctx == Store && + !strcmp(PyString_AS_STRING(e->v.Attribute.attr), "None")) { + return ast_error(n, "assignment to None"); + } + e->v.Attribute.ctx = ctx; + break; + case Subscript_kind: + e->v.Subscript.ctx = ctx; + break; + case Name_kind: + if (ctx == Store && + !strcmp(PyString_AS_STRING(e->v.Name.id), "None")) { + return ast_error(n, "assignment to None"); + } + e->v.Name.ctx = ctx; + break; + case List_kind: + e->v.List.ctx = ctx; + s = e->v.List.elts; + break; + case Tuple_kind: + if (asdl_seq_LEN(e->v.Tuple.elts) == 0) + return ast_error(n, "can't assign to ()"); + e->v.Tuple.ctx = ctx; + s = e->v.Tuple.elts; + break; + case Lambda_kind: + expr_name = "lambda"; + break; + case Call_kind: + expr_name = "function call"; + break; + case BoolOp_kind: + case BinOp_kind: + case UnaryOp_kind: + expr_name = "operator"; + break; + case GeneratorExp_kind: + expr_name = "generator expression"; + break; + case Yield_kind: + expr_name = "yield expression"; + break; + case ListComp_kind: + expr_name = "list comprehension"; + break; + case Dict_kind: + case Num_kind: + case Str_kind: + expr_name = "literal"; + break; + case Compare_kind: + expr_name = "comparison"; + break; + case Repr_kind: + expr_name = "repr"; + break; + case IfExp_kind: + expr_name = "conditional expression"; + break; + default: + PyErr_Format(PyExc_SystemError, + "unexpected expression in assignment %d (line %d)", + e->kind, e->lineno); + return 0; } /* Check for error string set by switch */ if (expr_name) { - char buf[300]; - PyOS_snprintf(buf, sizeof(buf), - "can't %s %s", - ctx == Store ? "assign to" : "delete", - expr_name); - return ast_error(n, buf); + char buf[300]; + PyOS_snprintf(buf, sizeof(buf), + "can't %s %s", + ctx == Store ? "assign to" : "delete", + expr_name); + return ast_error(n, buf); } /* If the LHS is a list or tuple, we need to set the assignment - context for all the contained elements. + context for all the contained elements. */ if (s) { - int i; + int i; - for (i = 0; i < asdl_seq_LEN(s); i++) { - if (!set_context((expr_ty)asdl_seq_GET(s, i), ctx, n)) - return 0; - } + for (i = 0; i < asdl_seq_LEN(s); i++) { + if (!set_context((expr_ty)asdl_seq_GET(s, i), ctx, n)) + return 0; + } } return 1; } @@ -437,35 +438,35 @@ REQ(n, augassign); n = CHILD(n, 0); switch (STR(n)[0]) { - case '+': - return Add; - case '-': - return Sub; - case '/': - if (STR(n)[1] == '/') - return FloorDiv; - else - return Div; - case '%': - return Mod; - case '<': - return LShift; - case '>': - return RShift; - case '&': - return BitAnd; - case '^': - return BitXor; - case '|': - return BitOr; - case '*': - if (STR(n)[1] == '*') - return Pow; - else - return Mult; - default: - PyErr_Format(PyExc_SystemError, "invalid augassign: %s", STR(n)); - return (operator_ty)0; + case '+': + return Add; + case '-': + return Sub; + case '/': + if (STR(n)[1] == '/') + return FloorDiv; + else + return Div; + case '%': + return Mod; + case '<': + return LShift; + case '>': + return RShift; + case '&': + return BitAnd; + case '^': + return BitXor; + case '|': + return BitOr; + case '*': + if (STR(n)[1] == '*') + return Pow; + else + return Mult; + default: + PyErr_Format(PyExc_SystemError, "invalid augassign: %s", STR(n)); + return (operator_ty)0; } } @@ -473,51 +474,51 @@ ast_for_comp_op(const node *n) { /* comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is' - |'is' 'not' + |'is' 'not' */ REQ(n, comp_op); if (NCH(n) == 1) { - n = CHILD(n, 0); - switch (TYPE(n)) { - case LESS: - return Lt; - case GREATER: - return Gt; - case EQEQUAL: /* == */ - return Eq; - case LESSEQUAL: - return LtE; - case GREATEREQUAL: - return GtE; - case NOTEQUAL: - return NotEq; - case NAME: - if (strcmp(STR(n), "in") == 0) - return In; - if (strcmp(STR(n), "is") == 0) - return Is; - default: - PyErr_Format(PyExc_SystemError, "invalid comp_op: %s", - STR(n)); - return (cmpop_ty)0; - } + n = CHILD(n, 0); + switch (TYPE(n)) { + case LESS: + return Lt; + case GREATER: + return Gt; + case EQEQUAL: /* == */ + return Eq; + case LESSEQUAL: + return LtE; + case GREATEREQUAL: + return GtE; + case NOTEQUAL: + return NotEq; + case NAME: + if (strcmp(STR(n), "in") == 0) + return In; + if (strcmp(STR(n), "is") == 0) + return Is; + default: + PyErr_Format(PyExc_SystemError, "invalid comp_op: %s", + STR(n)); + return (cmpop_ty)0; + } } else if (NCH(n) == 2) { - /* handle "not in" and "is not" */ - switch (TYPE(CHILD(n, 0))) { - case NAME: - if (strcmp(STR(CHILD(n, 1)), "in") == 0) - return NotIn; - if (strcmp(STR(CHILD(n, 0)), "is") == 0) - return IsNot; - default: - PyErr_Format(PyExc_SystemError, "invalid comp_op: %s %s", - STR(CHILD(n, 0)), STR(CHILD(n, 1))); - return (cmpop_ty)0; - } + /* handle "not in" and "is not" */ + switch (TYPE(CHILD(n, 0))) { + case NAME: + if (strcmp(STR(CHILD(n, 1)), "in") == 0) + return NotIn; + if (strcmp(STR(CHILD(n, 0)), "is") == 0) + return IsNot; + default: + PyErr_Format(PyExc_SystemError, "invalid comp_op: %s %s", + STR(CHILD(n, 0)), STR(CHILD(n, 1))); + return (cmpop_ty)0; + } } PyErr_Format(PyExc_SystemError, "invalid comp_op: has %d children", - NCH(n)); + NCH(n)); return (cmpop_ty)0; } @@ -528,26 +529,25 @@ asdl_seq *seq; expr_ty expression; int i; - assert(TYPE(n) == testlist - || TYPE(n) == listmaker - || TYPE(n) == testlist_gexp - || TYPE(n) == testlist_safe - || TYPE(n) == testlist1 - ); + assert(TYPE(n) == testlist || + TYPE(n) == listmaker || + TYPE(n) == testlist_gexp || + TYPE(n) == testlist_safe || + TYPE(n) == testlist1); seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); if (!seq) - return NULL; + return NULL; for (i = 0; i < NCH(n); i += 2) { - assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == old_test); + assert(TYPE(CHILD(n, i)) == test || TYPE(CHILD(n, i)) == old_test); - expression = ast_for_expr(c, CHILD(n, i)); - if (!expression) - return NULL; + expression = ast_for_expr(c, CHILD(n, i)); + if (!expression) + return NULL; - assert(i / 2 < seq->size); - asdl_seq_SET(seq, i / 2, expression); + assert(i / 2 < seq->size); + asdl_seq_SET(seq, i / 2, expression); } return seq; } @@ -559,46 +559,46 @@ expr_ty result; asdl_seq *args = asdl_seq_new(len, c->c_arena); if (!args) - return NULL; + return NULL; /* fpdef: NAME | '(' fplist ')' fplist: fpdef (',' fpdef)* [','] */ REQ(n, fplist); for (i = 0; i < len; i++) { - const node *fpdef_node = CHILD(n, 2*i); - const node *child; - expr_ty arg; + const node *fpdef_node = CHILD(n, 2*i); + const node *child; + expr_ty arg; set_name: - /* fpdef_node is either a NAME or an fplist */ - child = CHILD(fpdef_node, 0); - if (TYPE(child) == NAME) { - if (!strcmp(STR(child), "None")) { - ast_error(child, "assignment to None"); - return NULL; - } - arg = Name(NEW_IDENTIFIER(child), Store, LINENO(child), - child->n_col_offset, c->c_arena); - } - else { - assert(TYPE(fpdef_node) == fpdef); - /* fpdef_node[0] is not a name, so it must be a '(', get CHILD[1] */ - child = CHILD(fpdef_node, 1); - assert(TYPE(child) == fplist); - /* NCH == 1 means we have (x), we need to elide the extra parens */ - if (NCH(child) == 1) { - fpdef_node = CHILD(child, 0); - assert(TYPE(fpdef_node) == fpdef); - goto set_name; - } - arg = compiler_complex_args(c, child); - } - asdl_seq_SET(args, i, arg); + /* fpdef_node is either a NAME or an fplist */ + child = CHILD(fpdef_node, 0); + if (TYPE(child) == NAME) { + if (!strcmp(STR(child), "None")) { + ast_error(child, "assignment to None"); + return NULL; + } + arg = Name(NEW_IDENTIFIER(child), Store, LINENO(child), + child->n_col_offset, c->c_arena); + } + else { + assert(TYPE(fpdef_node) == fpdef); + /* fpdef_node[0] is not a name, so it must be '(', get CHILD[1] */ + child = CHILD(fpdef_node, 1); + assert(TYPE(child) == fplist); + /* NCH == 1 means we have (x), we need to elide the extra parens */ + if (NCH(child) == 1) { + fpdef_node = CHILD(child, 0); + assert(TYPE(fpdef_node) == fpdef); + goto set_name; + } + arg = compiler_complex_args(c, child); + } + asdl_seq_SET(args, i, arg); } result = Tuple(args, Store, LINENO(n), n->n_col_offset, c->c_arena); if (!set_context(result, Store, n)) - return NULL; + return NULL; return result; } @@ -610,7 +610,7 @@ { /* parameters: '(' [varargslist] ')' varargslist: (fpdef ['=' test] ',')* ('*' NAME [',' '**' NAME] - | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [','] + | '**' NAME) | fpdef ['=' test] (',' fpdef ['=' test])* [','] */ int i, j, k, n_args = 0, n_defaults = 0, found_default = 0; asdl_seq *args, *defaults; @@ -618,26 +618,26 @@ node *ch; if (TYPE(n) == parameters) { - if (NCH(n) == 2) /* () as argument list */ - return arguments(NULL, NULL, NULL, NULL, c->c_arena); - n = CHILD(n, 1); + if (NCH(n) == 2) /* () as argument list */ + return arguments(NULL, NULL, NULL, NULL, c->c_arena); + n = CHILD(n, 1); } REQ(n, varargslist); /* first count the number of normal args & defaults */ for (i = 0; i < NCH(n); i++) { - ch = CHILD(n, i); - if (TYPE(ch) == fpdef) - n_args++; - if (TYPE(ch) == EQUAL) - n_defaults++; + ch = CHILD(n, i); + if (TYPE(ch) == fpdef) + n_args++; + if (TYPE(ch) == EQUAL) + n_defaults++; } args = (n_args ? asdl_seq_new(n_args, c->c_arena) : NULL); if (!args && n_args) - return NULL; /* Don't need to goto error; no objects allocated */ + return NULL; /* Don't need to goto error; no objects allocated */ defaults = (n_defaults ? asdl_seq_new(n_defaults, c->c_arena) : NULL); if (!defaults && n_defaults) - return NULL; /* Don't need to goto error; no objects allocated */ + return NULL; /* Don't need to goto error; no objects allocated */ /* fpdef: NAME | '(' fplist ')' fplist: fpdef (',' fpdef)* [','] @@ -646,80 +646,80 @@ j = 0; /* index for defaults */ k = 0; /* index for args */ while (i < NCH(n)) { - ch = CHILD(n, i); - switch (TYPE(ch)) { - case fpdef: - handle_fpdef: - /* XXX Need to worry about checking if TYPE(CHILD(n, i+1)) is - anything other than EQUAL or a comma? */ - /* XXX Should NCH(n) check be made a separate check? */ - if (i + 1 < NCH(n) && TYPE(CHILD(n, i + 1)) == EQUAL) { - expr_ty expression = ast_for_expr(c, CHILD(n, i + 2)); - if (!expression) - goto error; - assert(defaults != NULL); - asdl_seq_SET(defaults, j++, expression); - i += 2; - found_default = 1; - } - else if (found_default) { - ast_error(n, - "non-default argument follows default argument"); - goto error; - } - if (NCH(ch) == 3) { - ch = CHILD(ch, 1); - /* def foo((x)): is not complex, special case. */ - if (NCH(ch) != 1) { - /* We have complex arguments, setup for unpacking. */ - asdl_seq_SET(args, k++, compiler_complex_args(c, ch)); - } else { - /* def foo((x)): setup for checking NAME below. */ - /* Loop because there can be many parens and tuple - unpacking mixed in. */ - ch = CHILD(ch, 0); - assert(TYPE(ch) == fpdef); - goto handle_fpdef; - } - } - if (TYPE(CHILD(ch, 0)) == NAME) { - expr_ty name; - if (!strcmp(STR(CHILD(ch, 0)), "None")) { - ast_error(CHILD(ch, 0), "assignment to None"); - goto error; - } - name = Name(NEW_IDENTIFIER(CHILD(ch, 0)), - Param, LINENO(ch), ch->n_col_offset, - c->c_arena); - if (!name) - goto error; - asdl_seq_SET(args, k++, name); - - } - i += 2; /* the name and the comma */ - break; - case STAR: - if (!strcmp(STR(CHILD(n, i+1)), "None")) { - ast_error(CHILD(n, i+1), "assignment to None"); - goto error; - } - vararg = NEW_IDENTIFIER(CHILD(n, i+1)); - i += 3; - break; - case DOUBLESTAR: - if (!strcmp(STR(CHILD(n, i+1)), "None")) { - ast_error(CHILD(n, i+1), "assignment to None"); - goto error; - } - kwarg = NEW_IDENTIFIER(CHILD(n, i+1)); - i += 3; - break; - default: - PyErr_Format(PyExc_SystemError, - "unexpected node in varargslist: %d @ %d", - TYPE(ch), i); - goto error; - } + ch = CHILD(n, i); + switch (TYPE(ch)) { + case fpdef: + handle_fpdef: + /* XXX Need to worry about checking if TYPE(CHILD(n, i+1)) is + anything other than EQUAL or a comma? */ + /* XXX Should NCH(n) check be made a separate check? */ + if (i + 1 < NCH(n) && TYPE(CHILD(n, i + 1)) == EQUAL) { + expr_ty expression = ast_for_expr(c, CHILD(n, i + 2)); + if (!expression) + goto error; + assert(defaults != NULL); + asdl_seq_SET(defaults, j++, expression); + i += 2; + found_default = 1; + } + else if (found_default) { + ast_error(n, + "non-default argument follows default argument"); + goto error; + } + if (NCH(ch) == 3) { + ch = CHILD(ch, 1); + /* def foo((x)): is not complex, special case. */ + if (NCH(ch) != 1) { + /* We have complex arguments, setup for unpacking. */ + asdl_seq_SET(args, k++, compiler_complex_args(c, ch)); + } else { + /* def foo((x)): setup for checking NAME below. */ + /* Loop because there can be many parens and tuple + unpacking mixed in. */ + ch = CHILD(ch, 0); + assert(TYPE(ch) == fpdef); + goto handle_fpdef; + } + } + if (TYPE(CHILD(ch, 0)) == NAME) { + expr_ty name; + if (!strcmp(STR(CHILD(ch, 0)), "None")) { + ast_error(CHILD(ch, 0), "assignment to None"); + goto error; + } + name = Name(NEW_IDENTIFIER(CHILD(ch, 0)), + Param, LINENO(ch), ch->n_col_offset, + c->c_arena); + if (!name) + goto error; + asdl_seq_SET(args, k++, name); + + } + i += 2; /* the name and the comma */ + break; + case STAR: + if (!strcmp(STR(CHILD(n, i+1)), "None")) { + ast_error(CHILD(n, i+1), "assignment to None"); + goto error; + } + vararg = NEW_IDENTIFIER(CHILD(n, i+1)); + i += 3; + break; + case DOUBLESTAR: + if (!strcmp(STR(CHILD(n, i+1)), "None")) { + ast_error(CHILD(n, i+1), "assignment to None"); + goto error; + } + kwarg = NEW_IDENTIFIER(CHILD(n, i+1)); + i += 3; + break; + default: + PyErr_Format(PyExc_SystemError, + "unexpected node in varargslist: %d @ %d", + TYPE(ch), i); + goto error; + } } return arguments(args, vararg, kwarg, defaults, c->c_arena); @@ -745,18 +745,18 @@ id = NEW_IDENTIFIER(CHILD(n, 0)); if (!id) - return NULL; + return NULL; e = Name(id, Load, lineno, col_offset, c->c_arena); if (!e) - return NULL; + return NULL; for (i = 2; i < NCH(n); i+=2) { - id = NEW_IDENTIFIER(CHILD(n, i)); - if (!id) - return NULL; - e = Attribute(e, id, Load, lineno, col_offset, c->c_arena); - if (!e) - return NULL; + id = NEW_IDENTIFIER(CHILD(n, i)); + if (!id) + return NULL; + e = Attribute(e, id, Load, lineno, col_offset, c->c_arena); + if (!e) + return NULL; } return e; @@ -775,24 +775,24 @@ name_expr = ast_for_dotted_name(c, CHILD(n, 1)); if (!name_expr) - return NULL; - + return NULL; + if (NCH(n) == 3) { /* No arguments */ - d = name_expr; - name_expr = NULL; + d = name_expr; + name_expr = NULL; } else if (NCH(n) == 5) { /* Call with no arguments */ - d = Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n), - n->n_col_offset, c->c_arena); - if (!d) - return NULL; - name_expr = NULL; + d = Call(name_expr, NULL, NULL, NULL, NULL, LINENO(n), + n->n_col_offset, c->c_arena); + if (!d) + return NULL; + name_expr = NULL; } else { - d = ast_for_call(c, CHILD(n, 3), name_expr); - if (!d) - return NULL; - name_expr = NULL; + d = ast_for_call(c, CHILD(n, 3), name_expr); + if (!d) + return NULL; + name_expr = NULL; } return d; @@ -808,13 +808,13 @@ REQ(n, decorators); decorator_seq = asdl_seq_new(NCH(n), c->c_arena); if (!decorator_seq) - return NULL; - + return NULL; + for (i = 0; i < NCH(n); i++) { - d = ast_for_decorator(c, CHILD(n, i)); - if (!d) - return NULL; - asdl_seq_SET(decorator_seq, i, d); + d = ast_for_decorator(c, CHILD(n, i)); + if (!d) + return NULL; + asdl_seq_SET(decorator_seq, i, d); } return decorator_seq; } @@ -832,31 +832,31 @@ REQ(n, funcdef); if (NCH(n) == 6) { /* decorators are present */ - decorator_seq = ast_for_decorators(c, CHILD(n, 0)); - if (!decorator_seq) - return NULL; - name_i = 2; + decorator_seq = ast_for_decorators(c, CHILD(n, 0)); + if (!decorator_seq) + return NULL; + name_i = 2; } else { - name_i = 1; + name_i = 1; } name = NEW_IDENTIFIER(CHILD(n, name_i)); if (!name) - return NULL; + return NULL; else if (!strcmp(STR(CHILD(n, name_i)), "None")) { - ast_error(CHILD(n, name_i), "assignment to None"); - return NULL; + ast_error(CHILD(n, name_i), "assignment to None"); + return NULL; } args = ast_for_arguments(c, CHILD(n, name_i + 1)); if (!args) - return NULL; + return NULL; body = ast_for_suite(c, CHILD(n, name_i + 3)); if (!body) - return NULL; + return NULL; return FunctionDef(name, args, body, decorator_seq, LINENO(n), - n->n_col_offset, c->c_arena); + n->n_col_offset, c->c_arena); } static expr_ty @@ -867,20 +867,20 @@ expr_ty expression; if (NCH(n) == 3) { - args = arguments(NULL, NULL, NULL, NULL, c->c_arena); - if (!args) - return NULL; - expression = ast_for_expr(c, CHILD(n, 2)); - if (!expression) - return NULL; + args = arguments(NULL, NULL, NULL, NULL, c->c_arena); + if (!args) + return NULL; + expression = ast_for_expr(c, CHILD(n, 2)); + if (!expression) + return NULL; } else { - args = ast_for_arguments(c, CHILD(n, 1)); - if (!args) - return NULL; - expression = ast_for_expr(c, CHILD(n, 3)); - if (!expression) - return NULL; + args = ast_for_arguments(c, CHILD(n, 1)); + if (!args) + return NULL; + expression = ast_for_expr(c, CHILD(n, 3)); + if (!expression) + return NULL; } return Lambda(args, expression, LINENO(n), n->n_col_offset, c->c_arena); @@ -895,15 +895,15 @@ assert(NCH(n) == 5); body = ast_for_expr(c, CHILD(n, 0)); if (!body) - return NULL; + return NULL; expression = ast_for_expr(c, CHILD(n, 2)); if (!expression) - return NULL; + return NULL; orelse = ast_for_expr(c, CHILD(n, 4)); if (!orelse) - return NULL; + return NULL; return IfExp(expression, body, orelse, LINENO(n), n->n_col_offset, - c->c_arena); + c->c_arena); } /* XXX(nnorwitz): the listcomp and genexpr code should be refactored @@ -926,21 +926,21 @@ n_fors++; REQ(ch, list_for); if (NCH(ch) == 5) - ch = CHILD(ch, 4); + ch = CHILD(ch, 4); else - return n_fors; + return n_fors; count_list_iter: REQ(ch, list_iter); ch = CHILD(ch, 0); if (TYPE(ch) == list_for) - goto count_list_for; + goto count_list_for; else if (TYPE(ch) == list_if) { - if (NCH(ch) == 3) { - ch = CHILD(ch, 2); - goto count_list_iter; - } - else - return n_fors; + if (NCH(ch) == 3) { + ch = CHILD(ch, 2); + goto count_list_iter; + } + else + return n_fors; } /* Should never be reached */ @@ -961,12 +961,12 @@ count_list_iter: REQ(n, list_iter); if (TYPE(CHILD(n, 0)) == list_for) - return n_ifs; + return n_ifs; n = CHILD(n, 0); REQ(n, list_if); n_ifs++; if (NCH(n) == 2) - return n_ifs; + return n_ifs; n = CHILD(n, 2); goto count_list_iter; } @@ -990,85 +990,85 @@ elt = ast_for_expr(c, CHILD(n, 0)); if (!elt) - return NULL; + return NULL; n_fors = count_list_fors(n); if (n_fors == -1) - return NULL; + return NULL; listcomps = asdl_seq_new(n_fors, c->c_arena); if (!listcomps) - return NULL; + return NULL; ch = CHILD(n, 1); for (i = 0; i < n_fors; i++) { - comprehension_ty lc; - asdl_seq *t; - expr_ty expression; - node *for_ch; - - REQ(ch, list_for); - - for_ch = CHILD(ch, 1); - t = ast_for_exprlist(c, for_ch, Store); - if (!t) - return NULL; - expression = ast_for_testlist(c, CHILD(ch, 3)); - if (!expression) - return NULL; - - /* Check the # of children rather than the length of t, since - [x for x, in ... ] has 1 element in t, but still requires a Tuple. */ - if (NCH(for_ch) == 1) - lc = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, NULL, - c->c_arena); - else - lc = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, - c->c_arena), - expression, NULL, c->c_arena); - if (!lc) - return NULL; - - if (NCH(ch) == 5) { - int j, n_ifs; - asdl_seq *ifs; - expr_ty list_for_expr; - - ch = CHILD(ch, 4); - n_ifs = count_list_ifs(ch); - if (n_ifs == -1) - return NULL; - - ifs = asdl_seq_new(n_ifs, c->c_arena); - if (!ifs) - return NULL; - - for (j = 0; j < n_ifs; j++) { - REQ(ch, list_iter); - ch = CHILD(ch, 0); - REQ(ch, list_if); - - list_for_expr = ast_for_expr(c, CHILD(ch, 1)); - if (!list_for_expr) - return NULL; - - asdl_seq_SET(ifs, j, list_for_expr); - if (NCH(ch) == 3) - ch = CHILD(ch, 2); - } - /* on exit, must guarantee that ch is a list_for */ - if (TYPE(ch) == list_iter) - ch = CHILD(ch, 0); - lc->ifs = ifs; - } - asdl_seq_SET(listcomps, i, lc); + comprehension_ty lc; + asdl_seq *t; + expr_ty expression; + node *for_ch; + + REQ(ch, list_for); + + for_ch = CHILD(ch, 1); + t = ast_for_exprlist(c, for_ch, Store); + if (!t) + return NULL; + expression = ast_for_testlist(c, CHILD(ch, 3)); + if (!expression) + return NULL; + + /* Check the # of children rather than the length of t, since + [x for x, in ... ] has 1 element in t, but still requires a Tuple. + */ + if (NCH(for_ch) == 1) + lc = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, NULL, + c->c_arena); + else + lc = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, + c->c_arena), + expression, NULL, c->c_arena); + if (!lc) + return NULL; + + if (NCH(ch) == 5) { + int j, n_ifs; + asdl_seq *ifs; + expr_ty list_for_expr; + + ch = CHILD(ch, 4); + n_ifs = count_list_ifs(ch); + if (n_ifs == -1) + return NULL; + + ifs = asdl_seq_new(n_ifs, c->c_arena); + if (!ifs) + return NULL; + + for (j = 0; j < n_ifs; j++) { + REQ(ch, list_iter); + ch = CHILD(ch, 0); + REQ(ch, list_if); + + list_for_expr = ast_for_expr(c, CHILD(ch, 1)); + if (!list_for_expr) + return NULL; + + asdl_seq_SET(ifs, j, list_for_expr); + if (NCH(ch) == 3) + ch = CHILD(ch, 2); + } + /* on exit, must guarantee that ch is a list_for */ + if (TYPE(ch) == list_iter) + ch = CHILD(ch, 0); + lc->ifs = ifs; + } + asdl_seq_SET(listcomps, i, lc); } return ListComp(elt, listcomps, LINENO(n), n->n_col_offset, c->c_arena); } -/* - Count the number of 'for' loops in a generator expression. +/* Count the number of 'for' loops in a generator expression. Helper for ast_for_genexp(). */ @@ -1076,34 +1076,34 @@ static int count_gen_fors(const node *n) { - int n_fors = 0; - node *ch = CHILD(n, 1); + int n_fors = 0; + node *ch = CHILD(n, 1); count_gen_for: - n_fors++; - REQ(ch, gen_for); - if (NCH(ch) == 5) - ch = CHILD(ch, 4); - else - return n_fors; + n_fors++; + REQ(ch, gen_for); + if (NCH(ch) == 5) + ch = CHILD(ch, 4); + else + return n_fors; count_gen_iter: - REQ(ch, gen_iter); - ch = CHILD(ch, 0); - if (TYPE(ch) == gen_for) - goto count_gen_for; - else if (TYPE(ch) == gen_if) { - if (NCH(ch) == 3) { - ch = CHILD(ch, 2); - goto count_gen_iter; - } - else - return n_fors; - } - - /* Should never be reached */ - PyErr_SetString(PyExc_SystemError, - "logic error in count_gen_fors"); - return -1; + REQ(ch, gen_iter); + ch = CHILD(ch, 0); + if (TYPE(ch) == gen_for) + goto count_gen_for; + else if (TYPE(ch) == gen_if) { + if (NCH(ch) == 3) { + ch = CHILD(ch, 2); + goto count_gen_iter; + } + else + return n_fors; + } + + /* Should never be reached */ + PyErr_SetString(PyExc_SystemError, + "logic error in count_gen_fors"); + return -1; } /* Count the number of 'if' statements in a generator expression. @@ -1114,19 +1114,19 @@ static int count_gen_ifs(const node *n) { - int n_ifs = 0; + int n_ifs = 0; - while (1) { - REQ(n, gen_iter); - if (TYPE(CHILD(n, 0)) == gen_for) - return n_ifs; - n = CHILD(n, 0); - REQ(n, gen_if); - n_ifs++; - if (NCH(n) == 2) - return n_ifs; - n = CHILD(n, 2); - } + while (1) { + REQ(n, gen_iter); + if (TYPE(CHILD(n, 0)) == gen_for) + return n_ifs; + n = CHILD(n, 0); + REQ(n, gen_if); + n_ifs++; + if (NCH(n) == 2) + return n_ifs; + n = CHILD(n, 2); + } } /* TODO(jhylton): Combine with list comprehension code? */ @@ -1134,7 +1134,7 @@ ast_for_genexp(struct compiling *c, const node *n) { /* testlist_gexp: test ( gen_for | (',' test)* [','] ) - argument: [test '='] test [gen_for] # Really [keyword '='] test */ + argument: [test '='] test [gen_for] # Really [keyword '='] test */ expr_ty elt; asdl_seq *genexps; int i, n_fors; @@ -1145,77 +1145,77 @@ elt = ast_for_expr(c, CHILD(n, 0)); if (!elt) - return NULL; + return NULL; n_fors = count_gen_fors(n); if (n_fors == -1) - return NULL; + return NULL; genexps = asdl_seq_new(n_fors, c->c_arena); if (!genexps) - return NULL; + return NULL; ch = CHILD(n, 1); for (i = 0; i < n_fors; i++) { - comprehension_ty ge; - asdl_seq *t; - expr_ty expression; - node *for_ch; - - REQ(ch, gen_for); - - for_ch = CHILD(ch, 1); - t = ast_for_exprlist(c, for_ch, Store); - if (!t) - return NULL; - expression = ast_for_expr(c, CHILD(ch, 3)); - if (!expression) - return NULL; - - /* Check the # of children rather than the length of t, since - (x for x, in ...) has 1 element in t, but still requires a Tuple. */ - if (NCH(for_ch) == 1) - ge = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, - NULL, c->c_arena); - else - ge = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, - c->c_arena), - expression, NULL, c->c_arena); - - if (!ge) - return NULL; - - if (NCH(ch) == 5) { - int j, n_ifs; - asdl_seq *ifs; - - ch = CHILD(ch, 4); - n_ifs = count_gen_ifs(ch); - if (n_ifs == -1) - return NULL; - - ifs = asdl_seq_new(n_ifs, c->c_arena); - if (!ifs) - return NULL; - - for (j = 0; j < n_ifs; j++) { - REQ(ch, gen_iter); - ch = CHILD(ch, 0); - REQ(ch, gen_if); - - expression = ast_for_expr(c, CHILD(ch, 1)); - if (!expression) - return NULL; - asdl_seq_SET(ifs, j, expression); - if (NCH(ch) == 3) - ch = CHILD(ch, 2); - } - /* on exit, must guarantee that ch is a gen_for */ - if (TYPE(ch) == gen_iter) - ch = CHILD(ch, 0); - ge->ifs = ifs; - } - asdl_seq_SET(genexps, i, ge); + comprehension_ty ge; + asdl_seq *t; + expr_ty expression; + node *for_ch; + + REQ(ch, gen_for); + + for_ch = CHILD(ch, 1); + t = ast_for_exprlist(c, for_ch, Store); + if (!t) + return NULL; + expression = ast_for_expr(c, CHILD(ch, 3)); + if (!expression) + return NULL; + + /* Check the # of children rather than the length of t, since + (x for x, in ...) has 1 element in t, but still requires a Tuple. */ + if (NCH(for_ch) == 1) + ge = comprehension((expr_ty)asdl_seq_GET(t, 0), expression, + NULL, c->c_arena); + else + ge = comprehension(Tuple(t, Store, LINENO(ch), ch->n_col_offset, + c->c_arena), + expression, NULL, c->c_arena); + + if (!ge) + return NULL; + + if (NCH(ch) == 5) { + int j, n_ifs; + asdl_seq *ifs; + + ch = CHILD(ch, 4); + n_ifs = count_gen_ifs(ch); + if (n_ifs == -1) + return NULL; + + ifs = asdl_seq_new(n_ifs, c->c_arena); + if (!ifs) + return NULL; + + for (j = 0; j < n_ifs; j++) { + REQ(ch, gen_iter); + ch = CHILD(ch, 0); + REQ(ch, gen_if); + + expression = ast_for_expr(c, CHILD(ch, 1)); + if (!expression) + return NULL; + asdl_seq_SET(ifs, j, expression); + if (NCH(ch) == 3) + ch = CHILD(ch, 2); + } + /* on exit, must guarantee that ch is a gen_for */ + if (TYPE(ch) == gen_iter) + ch = CHILD(ch, 0); + ge->ifs = ifs; + } + asdl_seq_SET(genexps, i, ge); } return GeneratorExp(elt, genexps, LINENO(n), n->n_col_offset, c->c_arena); @@ -1231,96 +1231,97 @@ switch (TYPE(ch)) { case NAME: - /* All names start in Load context, but may later be - changed. */ - return Name(NEW_IDENTIFIER(ch), Load, LINENO(n), n->n_col_offset, c->c_arena); + /* All names start in Load context, but may later be + changed. */ + return Name(NEW_IDENTIFIER(ch), Load, LINENO(n), n->n_col_offset, + c->c_arena); case STRING: { - PyObject *str = parsestrplus(c, n); - if (!str) - return NULL; + PyObject *str = parsestrplus(c, n); + if (!str) + return NULL; - PyArena_AddPyObject(c->c_arena, str); - return Str(str, LINENO(n), n->n_col_offset, c->c_arena); + PyArena_AddPyObject(c->c_arena, str); + return Str(str, LINENO(n), n->n_col_offset, c->c_arena); } case NUMBER: { - PyObject *pynum = parsenumber(STR(ch)); - if (!pynum) - return NULL; + PyObject *pynum = parsenumber(STR(ch)); + if (!pynum) + return NULL; - PyArena_AddPyObject(c->c_arena, pynum); - return Num(pynum, LINENO(n), n->n_col_offset, c->c_arena); + PyArena_AddPyObject(c->c_arena, pynum); + return Num(pynum, LINENO(n), n->n_col_offset, c->c_arena); } case LPAR: /* some parenthesized expressions */ - ch = CHILD(n, 1); - - if (TYPE(ch) == RPAR) - return Tuple(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena); - - if (TYPE(ch) == yield_expr) - return ast_for_expr(c, ch); - - if ((NCH(ch) > 1) && (TYPE(CHILD(ch, 1)) == gen_for)) - return ast_for_genexp(c, ch); - - return ast_for_testlist_gexp(c, ch); + ch = CHILD(n, 1); + + if (TYPE(ch) == RPAR) + return Tuple(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena); + + if (TYPE(ch) == yield_expr) + return ast_for_expr(c, ch); + + if ((NCH(ch) > 1) && (TYPE(CHILD(ch, 1)) == gen_for)) + return ast_for_genexp(c, ch); + + return ast_for_testlist_gexp(c, ch); case LSQB: /* list (or list comprehension) */ - ch = CHILD(n, 1); - - if (TYPE(ch) == RSQB) - return List(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena); - - REQ(ch, listmaker); - if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) { - asdl_seq *elts = seq_for_testlist(c, ch); - if (!elts) - return NULL; - - return List(elts, Load, LINENO(n), n->n_col_offset, c->c_arena); - } - else - return ast_for_listcomp(c, ch); + ch = CHILD(n, 1); + + if (TYPE(ch) == RSQB) + return List(NULL, Load, LINENO(n), n->n_col_offset, c->c_arena); + + REQ(ch, listmaker); + if (NCH(ch) == 1 || TYPE(CHILD(ch, 1)) == COMMA) { + asdl_seq *elts = seq_for_testlist(c, ch); + if (!elts) + return NULL; + + return List(elts, Load, LINENO(n), n->n_col_offset, c->c_arena); + } + else + return ast_for_listcomp(c, ch); case LBRACE: { - /* dictmaker: test ':' test (',' test ':' test)* [','] */ - int i, size; - asdl_seq *keys, *values; - - ch = CHILD(n, 1); - size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */ - keys = asdl_seq_new(size, c->c_arena); - if (!keys) - return NULL; - - values = asdl_seq_new(size, c->c_arena); - if (!values) - return NULL; - - for (i = 0; i < NCH(ch); i += 4) { - expr_ty expression; - - expression = ast_for_expr(c, CHILD(ch, i)); - if (!expression) - return NULL; - - asdl_seq_SET(keys, i / 4, expression); - - expression = ast_for_expr(c, CHILD(ch, i + 2)); - if (!expression) - return NULL; - - asdl_seq_SET(values, i / 4, expression); - } - return Dict(keys, values, LINENO(n), n->n_col_offset, c->c_arena); + /* dictmaker: test ':' test (',' test ':' test)* [','] */ + int i, size; + asdl_seq *keys, *values; + + ch = CHILD(n, 1); + size = (NCH(ch) + 1) / 4; /* +1 in case no trailing comma */ + keys = asdl_seq_new(size, c->c_arena); + if (!keys) + return NULL; + + values = asdl_seq_new(size, c->c_arena); + if (!values) + return NULL; + + for (i = 0; i < NCH(ch); i += 4) { + expr_ty expression; + + expression = ast_for_expr(c, CHILD(ch, i)); + if (!expression) + return NULL; + + asdl_seq_SET(keys, i / 4, expression); + + expression = ast_for_expr(c, CHILD(ch, i + 2)); + if (!expression) + return NULL; + + asdl_seq_SET(values, i / 4, expression); + } + return Dict(keys, values, LINENO(n), n->n_col_offset, c->c_arena); } case BACKQUOTE: { /* repr */ - expr_ty expression = ast_for_testlist(c, CHILD(n, 1)); - if (!expression) - return NULL; + expr_ty expression = ast_for_testlist(c, CHILD(n, 1)); + if (!expression) + return NULL; - return Repr(expression, LINENO(n), n->n_col_offset, c->c_arena); + return Repr(expression, LINENO(n), n->n_col_offset, c->c_arena); } default: - PyErr_Format(PyExc_SystemError, "unhandled atom %d", TYPE(ch)); - return NULL; + PyErr_Format(PyExc_SystemError, "unhandled atom %d", TYPE(ch)); + return NULL; } } @@ -1338,62 +1339,62 @@ */ ch = CHILD(n, 0); if (TYPE(ch) == DOT) - return Ellipsis(c->c_arena); + return Ellipsis(c->c_arena); if (NCH(n) == 1 && TYPE(ch) == test) { - /* 'step' variable hold no significance in terms of being used over - other vars */ - step = ast_for_expr(c, ch); - if (!step) - return NULL; - - return Index(step, c->c_arena); + /* 'step' variable hold no significance in terms of being used over + other vars */ + step = ast_for_expr(c, ch); + if (!step) + return NULL; + + return Index(step, c->c_arena); } if (TYPE(ch) == test) { - lower = ast_for_expr(c, ch); - if (!lower) - return NULL; + lower = ast_for_expr(c, ch); + if (!lower) + return NULL; } /* If there's an upper bound it's in the second or third position. */ if (TYPE(ch) == COLON) { - if (NCH(n) > 1) { - node *n2 = CHILD(n, 1); + if (NCH(n) > 1) { + node *n2 = CHILD(n, 1); - if (TYPE(n2) == test) { - upper = ast_for_expr(c, n2); - if (!upper) - return NULL; - } - } + if (TYPE(n2) == test) { + upper = ast_for_expr(c, n2); + if (!upper) + return NULL; + } + } } else if (NCH(n) > 2) { - node *n2 = CHILD(n, 2); + node *n2 = CHILD(n, 2); - if (TYPE(n2) == test) { - upper = ast_for_expr(c, n2); - if (!upper) - return NULL; - } + if (TYPE(n2) == test) { + upper = ast_for_expr(c, n2); + if (!upper) + return NULL; + } } ch = CHILD(n, NCH(n) - 1); if (TYPE(ch) == sliceop) { - if (NCH(ch) == 1) { - /* No expression, so step is None */ - ch = CHILD(ch, 0); - step = Name(new_identifier("None", c->c_arena), Load, - LINENO(ch), ch->n_col_offset, c->c_arena); - if (!step) - return NULL; - } else { - ch = CHILD(ch, 1); - if (TYPE(ch) == test) { - step = ast_for_expr(c, ch); - if (!step) - return NULL; - } - } + if (NCH(ch) == 1) { + /* No expression, so step is None */ + ch = CHILD(ch, 0); + step = Name(new_identifier("None", c->c_arena), Load, + LINENO(ch), ch->n_col_offset, c->c_arena); + if (!step) + return NULL; + } else { + ch = CHILD(ch, 1); + if (TYPE(ch) == test) { + step = ast_for_expr(c, ch); + if (!step) + return NULL; + } + } } return Slice(lower, upper, step, c->c_arena); @@ -1402,53 +1403,53 @@ static expr_ty ast_for_binop(struct compiling *c, const node *n) { - /* Must account for a sequence of expressions. - How should A op B op C by represented? - BinOp(BinOp(A, op, B), op, C). - */ - - int i, nops; - expr_ty expr1, expr2, result; - operator_ty newoperator; - - expr1 = ast_for_expr(c, CHILD(n, 0)); - if (!expr1) - return NULL; - - expr2 = ast_for_expr(c, CHILD(n, 2)); - if (!expr2) - return NULL; - - newoperator = get_operator(CHILD(n, 1)); - if (!newoperator) - return NULL; - - result = BinOp(expr1, newoperator, expr2, LINENO(n), n->n_col_offset, - c->c_arena); - if (!result) - return NULL; - - nops = (NCH(n) - 1) / 2; - for (i = 1; i < nops; i++) { - expr_ty tmp_result, tmp; - const node* next_oper = CHILD(n, i * 2 + 1); - - newoperator = get_operator(next_oper); - if (!newoperator) - return NULL; - - tmp = ast_for_expr(c, CHILD(n, i * 2 + 2)); - if (!tmp) - return NULL; - - tmp_result = BinOp(result, newoperator, tmp, - LINENO(next_oper), next_oper->n_col_offset, - c->c_arena); - if (!tmp) - return NULL; - result = tmp_result; - } - return result; + /* Must account for a sequence of expressions. + How should A op B op C by represented? + BinOp(BinOp(A, op, B), op, C). + */ + + int i, nops; + expr_ty expr1, expr2, result; + operator_ty newoperator; + + expr1 = ast_for_expr(c, CHILD(n, 0)); + if (!expr1) + return NULL; + + expr2 = ast_for_expr(c, CHILD(n, 2)); + if (!expr2) + return NULL; + + newoperator = get_operator(CHILD(n, 1)); + if (!newoperator) + return NULL; + + result = BinOp(expr1, newoperator, expr2, LINENO(n), n->n_col_offset, + c->c_arena); + if (!result) + return NULL; + + nops = (NCH(n) - 1) / 2; + for (i = 1; i < nops; i++) { + expr_ty tmp_result, tmp; + const node* next_oper = CHILD(n, i * 2 + 1); + + newoperator = get_operator(next_oper); + if (!newoperator) + return NULL; + + tmp = ast_for_expr(c, CHILD(n, i * 2 + 2)); + if (!tmp) + return NULL; + + tmp_result = BinOp(result, newoperator, tmp, + LINENO(next_oper), next_oper->n_col_offset, + c->c_arena); + if (!tmp) + return NULL; + result = tmp_result; + } + return result; } static expr_ty @@ -1460,67 +1461,67 @@ */ REQ(n, trailer); if (TYPE(CHILD(n, 0)) == LPAR) { - if (NCH(n) == 2) - return Call(left_expr, NULL, NULL, NULL, NULL, LINENO(n), - n->n_col_offset, c->c_arena); - else - return ast_for_call(c, CHILD(n, 1), left_expr); + if (NCH(n) == 2) + return Call(left_expr, NULL, NULL, NULL, NULL, LINENO(n), + n->n_col_offset, c->c_arena); + else + return ast_for_call(c, CHILD(n, 1), left_expr); } else if (TYPE(CHILD(n, 0)) == DOT ) { - return Attribute(left_expr, NEW_IDENTIFIER(CHILD(n, 1)), Load, - LINENO(n), n->n_col_offset, c->c_arena); + return Attribute(left_expr, NEW_IDENTIFIER(CHILD(n, 1)), Load, + LINENO(n), n->n_col_offset, c->c_arena); } else { - REQ(CHILD(n, 0), LSQB); - REQ(CHILD(n, 2), RSQB); - n = CHILD(n, 1); - if (NCH(n) == 1) { - slice_ty slc = ast_for_slice(c, CHILD(n, 0)); - if (!slc) - return NULL; - return Subscript(left_expr, slc, Load, LINENO(n), n->n_col_offset, - c->c_arena); - } - else { - /* The grammar is ambiguous here. The ambiguity is resolved - by treating the sequence as a tuple literal if there are - no slice features. - */ - int j; - slice_ty slc; - expr_ty e; - bool simple = true; - asdl_seq *slices, *elts; - slices = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); - if (!slices) - return NULL; - for (j = 0; j < NCH(n); j += 2) { - slc = ast_for_slice(c, CHILD(n, j)); - if (!slc) - return NULL; - if (slc->kind != Index_kind) - simple = false; - asdl_seq_SET(slices, j / 2, slc); - } - if (!simple) { - return Subscript(left_expr, ExtSlice(slices, c->c_arena), - Load, LINENO(n), n->n_col_offset, c->c_arena); - } - /* extract Index values and put them in a Tuple */ - elts = asdl_seq_new(asdl_seq_LEN(slices), c->c_arena); - if (!elts) - return NULL; - for (j = 0; j < asdl_seq_LEN(slices); ++j) { - slc = (slice_ty)asdl_seq_GET(slices, j); - assert(slc->kind == Index_kind && slc->v.Index.value); - asdl_seq_SET(elts, j, slc->v.Index.value); - } - e = Tuple(elts, Load, LINENO(n), n->n_col_offset, c->c_arena); - if (!e) - return NULL; - return Subscript(left_expr, Index(e, c->c_arena), - Load, LINENO(n), n->n_col_offset, c->c_arena); - } + REQ(CHILD(n, 0), LSQB); + REQ(CHILD(n, 2), RSQB); + n = CHILD(n, 1); + if (NCH(n) == 1) { + slice_ty slc = ast_for_slice(c, CHILD(n, 0)); + if (!slc) + return NULL; + return Subscript(left_expr, slc, Load, LINENO(n), n->n_col_offset, + c->c_arena); + } + else { + /* The grammar is ambiguous here. The ambiguity is resolved + by treating the sequence as a tuple literal if there are + no slice features. + */ + int j; + slice_ty slc; + expr_ty e; + bool simple = true; + asdl_seq *slices, *elts; + slices = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); + if (!slices) + return NULL; + for (j = 0; j < NCH(n); j += 2) { + slc = ast_for_slice(c, CHILD(n, j)); + if (!slc) + return NULL; + if (slc->kind != Index_kind) + simple = false; + asdl_seq_SET(slices, j / 2, slc); + } + if (!simple) { + return Subscript(left_expr, ExtSlice(slices, c->c_arena), + Load, LINENO(n), n->n_col_offset, c->c_arena); + } + /* extract Index values and put them in a Tuple */ + elts = asdl_seq_new(asdl_seq_LEN(slices), c->c_arena); + if (!elts) + return NULL; + for (j = 0; j < asdl_seq_LEN(slices); ++j) { + slc = (slice_ty)asdl_seq_GET(slices, j); + assert(slc->kind == Index_kind && slc->v.Index.value); + asdl_seq_SET(elts, j, slc->v.Index.value); + } + e = Tuple(elts, Load, LINENO(n), n->n_col_offset, c->c_arena); + if (!e) + return NULL; + return Subscript(left_expr, Index(e, c->c_arena), + Load, LINENO(n), n->n_col_offset, c->c_arena); + } } } @@ -1531,47 +1532,47 @@ expr_ty expression; /* If the unary - operator is applied to a constant, don't generate - a UNARY_NEGATIVE opcode. Just store the approriate value as a + a UNARY_NEGATIVE opcode. Just store the approriate value as a constant. The peephole optimizer already does something like this but it doesn't handle the case where the constant is (sys.maxint - 1). In that case, we want a PyIntObject, not a PyLongObject. */ - if (TYPE(CHILD(n, 0)) == MINUS - && NCH(n) == 2 - && TYPE((pfactor = CHILD(n, 1))) == factor - && NCH(pfactor) == 1 - && TYPE((ppower = CHILD(pfactor, 0))) == power - && NCH(ppower) == 1 - && TYPE((patom = CHILD(ppower, 0))) == atom - && TYPE((pnum = CHILD(patom, 0))) == NUMBER) { - char *s = PyObject_MALLOC(strlen(STR(pnum)) + 2); - if (s == NULL) - return NULL; - s[0] = '-'; - strcpy(s + 1, STR(pnum)); - PyObject_FREE(STR(pnum)); - STR(pnum) = s; - return ast_for_atom(c, patom); + if (TYPE(CHILD(n, 0)) == MINUS && + NCH(n) == 2 && + TYPE((pfactor = CHILD(n, 1))) == factor && + NCH(pfactor) == 1 && + TYPE((ppower = CHILD(pfactor, 0))) == power && + NCH(ppower) == 1 && + TYPE((patom = CHILD(ppower, 0))) == atom && + TYPE((pnum = CHILD(patom, 0))) == NUMBER) { + char *s = PyObject_MALLOC(strlen(STR(pnum)) + 2); + if (s == NULL) + return NULL; + s[0] = '-'; + strcpy(s + 1, STR(pnum)); + PyObject_FREE(STR(pnum)); + STR(pnum) = s; + return ast_for_atom(c, patom); } expression = ast_for_expr(c, CHILD(n, 1)); if (!expression) - return NULL; + return NULL; switch (TYPE(CHILD(n, 0))) { - case PLUS: - return UnaryOp(UAdd, expression, LINENO(n), n->n_col_offset, - c->c_arena); - case MINUS: - return UnaryOp(USub, expression, LINENO(n), n->n_col_offset, - c->c_arena); - case TILDE: - return UnaryOp(Invert, expression, LINENO(n), - n->n_col_offset, c->c_arena); + case PLUS: + return UnaryOp(UAdd, expression, LINENO(n), n->n_col_offset, + c->c_arena); + case MINUS: + return UnaryOp(USub, expression, LINENO(n), n->n_col_offset, + c->c_arena); + case TILDE: + return UnaryOp(Invert, expression, LINENO(n), + n->n_col_offset, c->c_arena); } PyErr_Format(PyExc_SystemError, "unhandled factor: %d", - TYPE(CHILD(n, 0))); + TYPE(CHILD(n, 0))); return NULL; } @@ -1585,28 +1586,28 @@ REQ(n, power); e = ast_for_atom(c, CHILD(n, 0)); if (!e) - return NULL; + return NULL; if (NCH(n) == 1) - return e; + return e; for (i = 1; i < NCH(n); i++) { - node *ch = CHILD(n, i); - if (TYPE(ch) != trailer) - break; - tmp = ast_for_trailer(c, ch, e); - if (!tmp) - return NULL; - tmp->lineno = e->lineno; - tmp->col_offset = e->col_offset; - e = tmp; + node *ch = CHILD(n, i); + if (TYPE(ch) != trailer) + break; + tmp = ast_for_trailer(c, ch, e); + if (!tmp) + return NULL; + tmp->lineno = e->lineno; + tmp->col_offset = e->col_offset; + e = tmp; } if (TYPE(CHILD(n, NCH(n) - 1)) == factor) { - expr_ty f = ast_for_expr(c, CHILD(n, NCH(n) - 1)); - if (!f) - return NULL; - tmp = BinOp(e, Pow, f, LINENO(n), n->n_col_offset, c->c_arena); - if (!tmp) - return NULL; - e = tmp; + expr_ty f = ast_for_expr(c, CHILD(n, NCH(n) - 1)); + if (!f) + return NULL; + tmp = BinOp(e, Pow, f, LINENO(n), n->n_col_offset, c->c_arena); + if (!tmp) + return NULL; + e = tmp; } return e; } @@ -1647,124 +1648,124 @@ loop: switch (TYPE(n)) { - case test: - case old_test: - if (TYPE(CHILD(n, 0)) == lambdef || - TYPE(CHILD(n, 0)) == old_lambdef) - return ast_for_lambdef(c, CHILD(n, 0)); - else if (NCH(n) > 1) - return ast_for_ifexpr(c, n); - /* Fallthrough */ - case or_test: - case and_test: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto loop; - } - seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); - if (!seq) - return NULL; - for (i = 0; i < NCH(n); i += 2) { - expr_ty e = ast_for_expr(c, CHILD(n, i)); - if (!e) - return NULL; - asdl_seq_SET(seq, i / 2, e); - } - if (!strcmp(STR(CHILD(n, 1)), "and")) - return BoolOp(And, seq, LINENO(n), n->n_col_offset, - c->c_arena); - assert(!strcmp(STR(CHILD(n, 1)), "or")); - return BoolOp(Or, seq, LINENO(n), n->n_col_offset, c->c_arena); - case not_test: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto loop; - } - else { - expr_ty expression = ast_for_expr(c, CHILD(n, 1)); - if (!expression) - return NULL; - - return UnaryOp(Not, expression, LINENO(n), n->n_col_offset, - c->c_arena); - } - case comparison: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto loop; - } - else { - expr_ty expression; - asdl_int_seq *ops; - asdl_seq *cmps; - ops = asdl_int_seq_new(NCH(n) / 2, c->c_arena); - if (!ops) - return NULL; - cmps = asdl_seq_new(NCH(n) / 2, c->c_arena); - if (!cmps) { - return NULL; - } - for (i = 1; i < NCH(n); i += 2) { - cmpop_ty newoperator; - - newoperator = ast_for_comp_op(CHILD(n, i)); - if (!newoperator) { - return NULL; - } - - expression = ast_for_expr(c, CHILD(n, i + 1)); - if (!expression) { - return NULL; - } - - asdl_seq_SET(ops, i / 2, newoperator); - asdl_seq_SET(cmps, i / 2, expression); - } - expression = ast_for_expr(c, CHILD(n, 0)); - if (!expression) { - return NULL; - } - - return Compare(expression, ops, cmps, LINENO(n), - n->n_col_offset, c->c_arena); - } - break; - - /* The next five cases all handle BinOps. The main body of code - is the same in each case, but the switch turned inside out to - reuse the code for each type of operator. - */ - case expr: - case xor_expr: - case and_expr: - case shift_expr: - case arith_expr: - case term: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto loop; - } - return ast_for_binop(c, n); - case yield_expr: { - expr_ty exp = NULL; - if (NCH(n) == 2) { - exp = ast_for_testlist(c, CHILD(n, 1)); - if (!exp) - return NULL; - } - return Yield(exp, LINENO(n), n->n_col_offset, c->c_arena); - } - case factor: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto loop; - } - return ast_for_factor(c, n); - case power: - return ast_for_power(c, n); - default: - PyErr_Format(PyExc_SystemError, "unhandled expr: %d", TYPE(n)); - return NULL; + case test: + case old_test: + if (TYPE(CHILD(n, 0)) == lambdef || + TYPE(CHILD(n, 0)) == old_lambdef) + return ast_for_lambdef(c, CHILD(n, 0)); + else if (NCH(n) > 1) + return ast_for_ifexpr(c, n); + /* Fallthrough */ + case or_test: + case and_test: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); + if (!seq) + return NULL; + for (i = 0; i < NCH(n); i += 2) { + expr_ty e = ast_for_expr(c, CHILD(n, i)); + if (!e) + return NULL; + asdl_seq_SET(seq, i / 2, e); + } + if (!strcmp(STR(CHILD(n, 1)), "and")) + return BoolOp(And, seq, LINENO(n), n->n_col_offset, + c->c_arena); + assert(!strcmp(STR(CHILD(n, 1)), "or")); + return BoolOp(Or, seq, LINENO(n), n->n_col_offset, c->c_arena); + case not_test: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + else { + expr_ty expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + + return UnaryOp(Not, expression, LINENO(n), n->n_col_offset, + c->c_arena); + } + case comparison: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + else { + expr_ty expression; + asdl_int_seq *ops; + asdl_seq *cmps; + ops = asdl_int_seq_new(NCH(n) / 2, c->c_arena); + if (!ops) + return NULL; + cmps = asdl_seq_new(NCH(n) / 2, c->c_arena); + if (!cmps) { + return NULL; + } + for (i = 1; i < NCH(n); i += 2) { + cmpop_ty newoperator; + + newoperator = ast_for_comp_op(CHILD(n, i)); + if (!newoperator) { + return NULL; + } + + expression = ast_for_expr(c, CHILD(n, i + 1)); + if (!expression) { + return NULL; + } + + asdl_seq_SET(ops, i / 2, newoperator); + asdl_seq_SET(cmps, i / 2, expression); + } + expression = ast_for_expr(c, CHILD(n, 0)); + if (!expression) { + return NULL; + } + + return Compare(expression, ops, cmps, LINENO(n), + n->n_col_offset, c->c_arena); + } + break; + + /* The next five cases all handle BinOps. The main body of code + is the same in each case, but the switch turned inside out to + reuse the code for each type of operator. + */ + case expr: + case xor_expr: + case and_expr: + case shift_expr: + case arith_expr: + case term: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + return ast_for_binop(c, n); + case yield_expr: { + expr_ty exp = NULL; + if (NCH(n) == 2) { + exp = ast_for_testlist(c, CHILD(n, 1)); + if (!exp) + return NULL; + } + return Yield(exp, LINENO(n), n->n_col_offset, c->c_arena); + } + case factor: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + return ast_for_factor(c, n); + case power: + return ast_for_power(c, n); + default: + PyErr_Format(PyExc_SystemError, "unhandled expr: %d", TYPE(n)); + return NULL; } /* should never get here unless if error is set */ return NULL; @@ -1775,8 +1776,8 @@ { /* arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] - | '**' test) - argument: [test '='] test [gen_for] # Really [keyword '='] test + | '**' test) + argument: [test '='] test [gen_for] # Really [keyword '='] test */ int i, nargs, nkeywords, ngens; @@ -1790,20 +1791,20 @@ nkeywords = 0; ngens = 0; for (i = 0; i < NCH(n); i++) { - node *ch = CHILD(n, i); - if (TYPE(ch) == argument) { - if (NCH(ch) == 1) - nargs++; - else if (TYPE(CHILD(ch, 1)) == gen_for) - ngens++; - else - nkeywords++; - } + node *ch = CHILD(n, i); + if (TYPE(ch) == argument) { + if (NCH(ch) == 1) + nargs++; + else if (TYPE(CHILD(ch, 1)) == gen_for) + ngens++; + else + nkeywords++; + } } if (ngens > 1 || (ngens && (nargs || nkeywords))) { - ast_error(n, "Generator expression must be parenthesized " - "if not sole argument"); - return NULL; + ast_error(n, "Generator expression must be parenthesized " + "if not sole argument"); + return NULL; } if (nargs + nkeywords + ngens > 255) { @@ -1813,74 +1814,76 @@ args = asdl_seq_new(nargs + ngens, c->c_arena); if (!args) - return NULL; + return NULL; keywords = asdl_seq_new(nkeywords, c->c_arena); if (!keywords) - return NULL; + return NULL; nargs = 0; nkeywords = 0; for (i = 0; i < NCH(n); i++) { - node *ch = CHILD(n, i); - if (TYPE(ch) == argument) { - expr_ty e; - if (NCH(ch) == 1) { - if (nkeywords) { - ast_error(CHILD(ch, 0), - "non-keyword arg after keyword arg"); - return NULL; - } - e = ast_for_expr(c, CHILD(ch, 0)); - if (!e) - return NULL; - asdl_seq_SET(args, nargs++, e); - } - else if (TYPE(CHILD(ch, 1)) == gen_for) { - e = ast_for_genexp(c, ch); - if (!e) - return NULL; - asdl_seq_SET(args, nargs++, e); - } - else { - keyword_ty kw; - identifier key; - - /* CHILD(ch, 0) is test, but must be an identifier? */ - e = ast_for_expr(c, CHILD(ch, 0)); - if (!e) - return NULL; - /* f(lambda x: x[0] = 3) ends up getting parsed with - * LHS test = lambda x: x[0], and RHS test = 3. - * SF bug 132313 points out that complaining about a keyword - * then is very confusing. - */ - if (e->kind == Lambda_kind) { - ast_error(CHILD(ch, 0), "lambda cannot contain assignment"); - return NULL; - } else if (e->kind != Name_kind) { - ast_error(CHILD(ch, 0), "keyword can't be an expression"); - return NULL; - } - key = e->v.Name.id; - e = ast_for_expr(c, CHILD(ch, 2)); - if (!e) - return NULL; - kw = keyword(key, e, c->c_arena); - if (!kw) - return NULL; - asdl_seq_SET(keywords, nkeywords++, kw); - } - } - else if (TYPE(ch) == STAR) { - vararg = ast_for_expr(c, CHILD(n, i+1)); - i++; - } - else if (TYPE(ch) == DOUBLESTAR) { - kwarg = ast_for_expr(c, CHILD(n, i+1)); - i++; - } + node *ch = CHILD(n, i); + if (TYPE(ch) == argument) { + expr_ty e; + if (NCH(ch) == 1) { + if (nkeywords) { + ast_error(CHILD(ch, 0), + "non-keyword arg after keyword arg"); + return NULL; + } + e = ast_for_expr(c, CHILD(ch, 0)); + if (!e) + return NULL; + asdl_seq_SET(args, nargs++, e); + } + else if (TYPE(CHILD(ch, 1)) == gen_for) { + e = ast_for_genexp(c, ch); + if (!e) + return NULL; + asdl_seq_SET(args, nargs++, e); + } + else { + keyword_ty kw; + identifier key; + + /* CHILD(ch, 0) is test, but must be an identifier? */ + e = ast_for_expr(c, CHILD(ch, 0)); + if (!e) + return NULL; + /* f(lambda x: x[0] = 3) ends up getting parsed with + * LHS test = lambda x: x[0], and RHS test = 3. + * SF bug 132313 points out that complaining about a keyword + * then is very confusing. + */ + if (e->kind == Lambda_kind) { + ast_error(CHILD(ch, 0), + "lambda cannot contain assignment"); + return NULL; + } else if (e->kind != Name_kind) { + ast_error(CHILD(ch, 0), "keyword can't be an expression"); + return NULL; + } + key = e->v.Name.id; + e = ast_for_expr(c, CHILD(ch, 2)); + if (!e) + return NULL; + kw = keyword(key, e, c->c_arena); + if (!kw) + return NULL; + asdl_seq_SET(keywords, nkeywords++, kw); + } + } + else if (TYPE(ch) == STAR) { + vararg = ast_for_expr(c, CHILD(n, i+1)); + i++; + } + else if (TYPE(ch) == DOUBLESTAR) { + kwarg = ast_for_expr(c, CHILD(n, i+1)); + i++; + } } - return Call(func, args, keywords, vararg, kwarg, func->lineno, func->col_offset, c->c_arena); + return Call(func, args, keywords, vararg, kwarg, func->lineno, + func->col_offset, c->c_arena); } static expr_ty @@ -1892,21 +1895,21 @@ /* testlist1: test (',' test)* */ assert(NCH(n) > 0); if (TYPE(n) == testlist_gexp) { - if (NCH(n) > 1) - assert(TYPE(CHILD(n, 1)) != gen_for); + if (NCH(n) > 1) + assert(TYPE(CHILD(n, 1)) != gen_for); } else { - assert(TYPE(n) == testlist || - TYPE(n) == testlist_safe || - TYPE(n) == testlist1); + assert(TYPE(n) == testlist || + TYPE(n) == testlist_safe || + TYPE(n) == testlist1); } if (NCH(n) == 1) - return ast_for_expr(c, CHILD(n, 0)); + return ast_for_expr(c, CHILD(n, 0)); else { - asdl_seq *tmp = seq_for_testlist(c, n); - if (!tmp) - return NULL; - return Tuple(tmp, Load, LINENO(n), n->n_col_offset, c->c_arena); + asdl_seq *tmp = seq_for_testlist(c, n); + if (!tmp) + return NULL; + return Tuple(tmp, Load, LINENO(n), n->n_col_offset, c->c_arena); } } @@ -1917,7 +1920,7 @@ /* argument: test [ gen_for ] */ assert(TYPE(n) == testlist_gexp || TYPE(n) == argument); if (NCH(n) > 1 && TYPE(CHILD(n, 1)) == gen_for) - return ast_for_genexp(c, n); + return ast_for_genexp(c, n); return ast_for_testlist(c, n); } @@ -1929,15 +1932,15 @@ assert(NCH(n) > 0); REQ(n, testlist); if (NCH(n) == 1) { - expr_ty base; - asdl_seq *bases = asdl_seq_new(1, c->c_arena); - if (!bases) - return NULL; - base = ast_for_expr(c, CHILD(n, 0)); - if (!base) - return NULL; - asdl_seq_SET(bases, 0, base); - return bases; + expr_ty base; + asdl_seq *bases = asdl_seq_new(1, c->c_arena); + if (!bases) + return NULL; + base = ast_for_expr(c, CHILD(n, 0)); + if (!base) + return NULL; + asdl_seq_SET(bases, 0, base); + return bases; } return seq_for_testlist(c, n); @@ -1948,108 +1951,110 @@ { REQ(n, expr_stmt); /* expr_stmt: testlist (augassign (yield_expr|testlist) - | ('=' (yield_expr|testlist))*) + | ('=' (yield_expr|testlist))*) testlist: test (',' test)* [','] augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' - | '<<=' | '>>=' | '**=' | '//=' + | '<<=' | '>>=' | '**=' | '//=' test: ... here starts the operator precendence dance */ if (NCH(n) == 1) { - expr_ty e = ast_for_testlist(c, CHILD(n, 0)); - if (!e) - return NULL; + expr_ty e = ast_for_testlist(c, CHILD(n, 0)); + if (!e) + return NULL; - return Expr(e, LINENO(n), n->n_col_offset, c->c_arena); + return Expr(e, LINENO(n), n->n_col_offset, c->c_arena); } else if (TYPE(CHILD(n, 1)) == augassign) { - expr_ty expr1, expr2; - operator_ty newoperator; - node *ch = CHILD(n, 0); - - expr1 = ast_for_testlist(c, ch); - if (!expr1) - return NULL; - /* TODO(nas): Remove duplicated error checks (set_context does it) */ - switch (expr1->kind) { - case GeneratorExp_kind: - ast_error(ch, "augmented assignment to generator " - "expression not possible"); - return NULL; - case Yield_kind: - ast_error(ch, "augmented assignment to yield " - "expression not possible"); - return NULL; - case Name_kind: { - const char *var_name = PyString_AS_STRING(expr1->v.Name.id); - if (var_name[0] == 'N' && !strcmp(var_name, "None")) { - ast_error(ch, "assignment to None"); - return NULL; - } - break; - } - case Attribute_kind: - case Subscript_kind: - break; - default: - ast_error(ch, "illegal expression for augmented " - "assignment"); - return NULL; - } - if(!set_context(expr1, Store, ch)) - return NULL; - - ch = CHILD(n, 2); - if (TYPE(ch) == testlist) - expr2 = ast_for_testlist(c, ch); - else - expr2 = ast_for_expr(c, ch); - if (!expr2) - return NULL; - - newoperator = ast_for_augassign(CHILD(n, 1)); - if (!newoperator) - return NULL; + expr_ty expr1, expr2; + operator_ty newoperator; + node *ch = CHILD(n, 0); + + expr1 = ast_for_testlist(c, ch); + if (!expr1) + return NULL; + /* TODO(nas): Remove duplicated error checks (set_context does it) */ + switch (expr1->kind) { + case GeneratorExp_kind: + ast_error(ch, "augmented assignment to generator " + "expression not possible"); + return NULL; + case Yield_kind: + ast_error(ch, "augmented assignment to yield " + "expression not possible"); + return NULL; + case Name_kind: { + const char *var_name = PyString_AS_STRING(expr1->v.Name.id); + if (var_name[0] == 'N' && !strcmp(var_name, "None")) { + ast_error(ch, "assignment to None"); + return NULL; + } + break; + } + case Attribute_kind: + case Subscript_kind: + break; + default: + ast_error(ch, "illegal expression for augmented " + "assignment"); + return NULL; + } + if(!set_context(expr1, Store, ch)) + return NULL; + + ch = CHILD(n, 2); + if (TYPE(ch) == testlist) + expr2 = ast_for_testlist(c, ch); + else + expr2 = ast_for_expr(c, ch); + if (!expr2) + return NULL; + + newoperator = ast_for_augassign(CHILD(n, 1)); + if (!newoperator) + return NULL; - return AugAssign(expr1, newoperator, expr2, LINENO(n), n->n_col_offset, c->c_arena); + return AugAssign(expr1, newoperator, expr2, LINENO(n), n->n_col_offset, + c->c_arena); } else { - int i; - asdl_seq *targets; - node *value; - expr_ty expression; - - /* a normal assignment */ - REQ(CHILD(n, 1), EQUAL); - targets = asdl_seq_new(NCH(n) / 2, c->c_arena); - if (!targets) - return NULL; - for (i = 0; i < NCH(n) - 2; i += 2) { - expr_ty e; - node *ch = CHILD(n, i); - if (TYPE(ch) == yield_expr) { - ast_error(ch, "assignment to yield expression not possible"); - return NULL; - } - e = ast_for_testlist(c, ch); - - /* set context to assign */ - if (!e) - return NULL; - - if (!set_context(e, Store, CHILD(n, i))) - return NULL; - - asdl_seq_SET(targets, i / 2, e); - } - value = CHILD(n, NCH(n) - 1); - if (TYPE(value) == testlist) - expression = ast_for_testlist(c, value); - else - expression = ast_for_expr(c, value); - if (!expression) - return NULL; - return Assign(targets, expression, LINENO(n), n->n_col_offset, c->c_arena); + int i; + asdl_seq *targets; + node *value; + expr_ty expression; + + /* a normal assignment */ + REQ(CHILD(n, 1), EQUAL); + targets = asdl_seq_new(NCH(n) / 2, c->c_arena); + if (!targets) + return NULL; + for (i = 0; i < NCH(n) - 2; i += 2) { + expr_ty e; + node *ch = CHILD(n, i); + if (TYPE(ch) == yield_expr) { + ast_error(ch, "assignment to yield expression not possible"); + return NULL; + } + e = ast_for_testlist(c, ch); + + /* set context to assign */ + if (!e) + return NULL; + + if (!set_context(e, Store, CHILD(n, i))) + return NULL; + + asdl_seq_SET(targets, i / 2, e); + } + value = CHILD(n, NCH(n) - 1); + if (TYPE(value) == testlist) + expression = ast_for_testlist(c, value); + else + expression = ast_for_expr(c, value); + if (!expression) + return NULL; + return Assign(targets, expression, LINENO(n), n->n_col_offset, + c->c_arena); } } @@ -2057,7 +2062,7 @@ ast_for_print_stmt(struct compiling *c, const node *n) { /* print_stmt: 'print' ( [ test (',' test)* [','] ] - | '>>' test [ (',' test)+ [','] ] ) + | '>>' test [ (',' test)+ [','] ] ) */ expr_ty dest = NULL, expression; asdl_seq *seq; @@ -2066,19 +2071,19 @@ REQ(n, print_stmt); if (NCH(n) >= 2 && TYPE(CHILD(n, 1)) == RIGHTSHIFT) { - dest = ast_for_expr(c, CHILD(n, 2)); - if (!dest) - return NULL; - start = 4; + dest = ast_for_expr(c, CHILD(n, 2)); + if (!dest) + return NULL; + start = 4; } seq = asdl_seq_new((NCH(n) + 1 - start) / 2, c->c_arena); if (!seq) - return NULL; + return NULL; for (i = start, j = 0; i < NCH(n); i += 2, ++j) { - expression = ast_for_expr(c, CHILD(n, i)); - if (!expression) - return NULL; - asdl_seq_SET(seq, j, expression); + expression = ast_for_expr(c, CHILD(n, i)); + if (!expression) + return NULL; + asdl_seq_SET(seq, j, expression); } nl = (TYPE(CHILD(n, NCH(n) - 1)) == COMMA) ? false : true; return Print(dest, seq, nl, LINENO(n), n->n_col_offset, c->c_arena); @@ -2095,14 +2100,14 @@ seq = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); if (!seq) - return NULL; + return NULL; for (i = 0; i < NCH(n); i += 2) { - e = ast_for_expr(c, CHILD(n, i)); - if (!e) - return NULL; - asdl_seq_SET(seq, i / 2, e); - if (context && !set_context(e, context, CHILD(n, i))) - return NULL; + e = ast_for_expr(c, CHILD(n, i)); + if (!e) + return NULL; + asdl_seq_SET(seq, i / 2, e); + if (context && !set_context(e, context, CHILD(n, i))) + return NULL; } return seq; } @@ -2117,7 +2122,7 @@ expr_list = ast_for_exprlist(c, CHILD(n, 1), Del); if (!expr_list) - return NULL; + return NULL; return Delete(expr_list, LINENO(n), n->n_col_offset, c->c_arena); } @@ -2126,7 +2131,7 @@ { /* flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt - | yield_stmt + | yield_stmt break_stmt: 'break' continue_stmt: 'continue' return_stmt: 'return' [testlist] @@ -2139,65 +2144,70 @@ REQ(n, flow_stmt); ch = CHILD(n, 0); switch (TYPE(ch)) { - case break_stmt: - return Break(LINENO(n), n->n_col_offset, c->c_arena); - case continue_stmt: - return Continue(LINENO(n), n->n_col_offset, c->c_arena); - case yield_stmt: { /* will reduce to yield_expr */ - expr_ty exp = ast_for_expr(c, CHILD(ch, 0)); - if (!exp) - return NULL; - return Expr(exp, LINENO(n), n->n_col_offset, c->c_arena); - } - case return_stmt: - if (NCH(ch) == 1) - return Return(NULL, LINENO(n), n->n_col_offset, c->c_arena); - else { - expr_ty expression = ast_for_testlist(c, CHILD(ch, 1)); - if (!expression) - return NULL; - return Return(expression, LINENO(n), n->n_col_offset, c->c_arena); - } - case raise_stmt: - if (NCH(ch) == 1) - return Raise(NULL, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); - else if (NCH(ch) == 2) { - expr_ty expression = ast_for_expr(c, CHILD(ch, 1)); - if (!expression) - return NULL; - return Raise(expression, NULL, NULL, LINENO(n), n->n_col_offset, c->c_arena); - } - else if (NCH(ch) == 4) { - expr_ty expr1, expr2; - - expr1 = ast_for_expr(c, CHILD(ch, 1)); - if (!expr1) - return NULL; - expr2 = ast_for_expr(c, CHILD(ch, 3)); - if (!expr2) - return NULL; - - return Raise(expr1, expr2, NULL, LINENO(n), n->n_col_offset, c->c_arena); - } - else if (NCH(ch) == 6) { - expr_ty expr1, expr2, expr3; - - expr1 = ast_for_expr(c, CHILD(ch, 1)); - if (!expr1) - return NULL; - expr2 = ast_for_expr(c, CHILD(ch, 3)); - if (!expr2) - return NULL; - expr3 = ast_for_expr(c, CHILD(ch, 5)); - if (!expr3) - return NULL; - - return Raise(expr1, expr2, expr3, LINENO(n), n->n_col_offset, c->c_arena); - } - default: - PyErr_Format(PyExc_SystemError, - "unexpected flow_stmt: %d", TYPE(ch)); - return NULL; + case break_stmt: + return Break(LINENO(n), n->n_col_offset, c->c_arena); + case continue_stmt: + return Continue(LINENO(n), n->n_col_offset, c->c_arena); + case yield_stmt: { /* will reduce to yield_expr */ + expr_ty exp = ast_for_expr(c, CHILD(ch, 0)); + if (!exp) + return NULL; + return Expr(exp, LINENO(n), n->n_col_offset, c->c_arena); + } + case return_stmt: + if (NCH(ch) == 1) + return Return(NULL, LINENO(n), n->n_col_offset, c->c_arena); + else { + expr_ty expression = ast_for_testlist(c, CHILD(ch, 1)); + if (!expression) + return NULL; + return Return(expression, LINENO(n), n->n_col_offset, + c->c_arena); + } + case raise_stmt: + if (NCH(ch) == 1) + return Raise(NULL, NULL, NULL, LINENO(n), n->n_col_offset, + c->c_arena); + else if (NCH(ch) == 2) { + expr_ty expression = ast_for_expr(c, CHILD(ch, 1)); + if (!expression) + return NULL; + return Raise(expression, NULL, NULL, LINENO(n), + n->n_col_offset, c->c_arena); + } + else if (NCH(ch) == 4) { + expr_ty expr1, expr2; + + expr1 = ast_for_expr(c, CHILD(ch, 1)); + if (!expr1) + return NULL; + expr2 = ast_for_expr(c, CHILD(ch, 3)); + if (!expr2) + return NULL; + + return Raise(expr1, expr2, NULL, LINENO(n), n->n_col_offset, + c->c_arena); + } + else if (NCH(ch) == 6) { + expr_ty expr1, expr2, expr3; + + expr1 = ast_for_expr(c, CHILD(ch, 1)); + if (!expr1) + return NULL; + expr2 = ast_for_expr(c, CHILD(ch, 3)); + if (!expr2) + return NULL; + expr3 = ast_for_expr(c, CHILD(ch, 5)); + if (!expr3) + return NULL; + + return Raise(expr1, expr2, expr3, LINENO(n), n->n_col_offset, + c->c_arena); + } + default: + PyErr_Format(PyExc_SystemError, + "unexpected flow_stmt: %d", TYPE(ch)); + return NULL; } PyErr_SetString(PyExc_SystemError, "unhandled flow statement"); @@ -2216,67 +2226,67 @@ loop: switch (TYPE(n)) { - case import_as_name: - str = NULL; - if (NCH(n) == 3) { - str = NEW_IDENTIFIER(CHILD(n, 2)); - } - return alias(NEW_IDENTIFIER(CHILD(n, 0)), str, c->c_arena); - case dotted_as_name: - if (NCH(n) == 1) { - n = CHILD(n, 0); - goto loop; - } - else { - alias_ty a = alias_for_import_name(c, CHILD(n, 0)); - if (!a) - return NULL; - assert(!a->asname); - a->asname = NEW_IDENTIFIER(CHILD(n, 2)); - return a; - } - break; - case dotted_name: - if (NCH(n) == 1) - return alias(NEW_IDENTIFIER(CHILD(n, 0)), NULL, c->c_arena); - else { - /* Create a string of the form "a.b.c" */ - int i; - size_t len; - char *s; - - len = 0; - for (i = 0; i < NCH(n); i += 2) - /* length of string plus one for the dot */ - len += strlen(STR(CHILD(n, i))) + 1; - len--; /* the last name doesn't have a dot */ - str = PyString_FromStringAndSize(NULL, len); - if (!str) - return NULL; - s = PyString_AS_STRING(str); - if (!s) - return NULL; - for (i = 0; i < NCH(n); i += 2) { - char *sch = STR(CHILD(n, i)); - strcpy(s, STR(CHILD(n, i))); - s += strlen(sch); - *s++ = '.'; - } - --s; - *s = '\0'; - PyString_InternInPlace(&str); - PyArena_AddPyObject(c->c_arena, str); - return alias(str, NULL, c->c_arena); - } - break; - case STAR: - str = PyString_InternFromString("*"); - PyArena_AddPyObject(c->c_arena, str); - return alias(str, NULL, c->c_arena); - default: - PyErr_Format(PyExc_SystemError, - "unexpected import name: %d", TYPE(n)); - return NULL; + case import_as_name: + str = NULL; + if (NCH(n) == 3) { + str = NEW_IDENTIFIER(CHILD(n, 2)); + } + return alias(NEW_IDENTIFIER(CHILD(n, 0)), str, c->c_arena); + case dotted_as_name: + if (NCH(n) == 1) { + n = CHILD(n, 0); + goto loop; + } + else { + alias_ty a = alias_for_import_name(c, CHILD(n, 0)); + if (!a) + return NULL; + assert(!a->asname); + a->asname = NEW_IDENTIFIER(CHILD(n, 2)); + return a; + } + break; + case dotted_name: + if (NCH(n) == 1) + return alias(NEW_IDENTIFIER(CHILD(n, 0)), NULL, c->c_arena); + else { + /* Create a string of the form "a.b.c" */ + int i; + size_t len; + char *s; + + len = 0; + for (i = 0; i < NCH(n); i += 2) + /* length of string plus one for the dot */ + len += strlen(STR(CHILD(n, i))) + 1; + len--; /* the last name doesn't have a dot */ + str = PyString_FromStringAndSize(NULL, len); + if (!str) + return NULL; + s = PyString_AS_STRING(str); + if (!s) + return NULL; + for (i = 0; i < NCH(n); i += 2) { + char *sch = STR(CHILD(n, i)); + strcpy(s, STR(CHILD(n, i))); + s += strlen(sch); + *s++ = '.'; + } + --s; + *s = '\0'; + PyString_InternInPlace(&str); + PyArena_AddPyObject(c->c_arena, str); + return alias(str, NULL, c->c_arena); + } + break; + case STAR: + str = PyString_InternFromString("*"); + PyArena_AddPyObject(c->c_arena, str); + return alias(str, NULL, c->c_arena); + default: + PyErr_Format(PyExc_SystemError, + "unexpected import name: %d", TYPE(n)); + return NULL; } PyErr_SetString(PyExc_SystemError, "unhandled import name condition"); @@ -2290,7 +2300,7 @@ import_stmt: import_name | import_from import_name: 'import' dotted_as_names import_from: 'from' ('.'* dotted_name | '.') 'import' - ('*' | '(' import_as_names ')' | import_as_names) + ('*' | '(' import_as_names ')' | import_as_names) */ int lineno; int col_offset; @@ -2302,97 +2312,97 @@ col_offset = n->n_col_offset; n = CHILD(n, 0); if (TYPE(n) == import_name) { - n = CHILD(n, 1); - REQ(n, dotted_as_names); - aliases = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); - if (!aliases) - return NULL; - for (i = 0; i < NCH(n); i += 2) { - alias_ty import_alias = alias_for_import_name(c, CHILD(n, i)); - if (!import_alias) - return NULL; - asdl_seq_SET(aliases, i / 2, import_alias); - } - return Import(aliases, lineno, col_offset, c->c_arena); + n = CHILD(n, 1); + REQ(n, dotted_as_names); + aliases = asdl_seq_new((NCH(n) + 1) / 2, c->c_arena); + if (!aliases) + return NULL; + for (i = 0; i < NCH(n); i += 2) { + alias_ty import_alias = alias_for_import_name(c, CHILD(n, i)); + if (!import_alias) + return NULL; + asdl_seq_SET(aliases, i / 2, import_alias); + } + return Import(aliases, lineno, col_offset, c->c_arena); } else if (TYPE(n) == import_from) { - int n_children; - int idx, ndots = 0; - alias_ty mod = NULL; - identifier modname; - + int n_children; + int idx, ndots = 0; + alias_ty mod = NULL; + identifier modname; + /* Count the number of dots (for relative imports) and check for the - optional module name */ - for (idx = 1; idx < NCH(n); idx++) { - if (TYPE(CHILD(n, idx)) == dotted_name) { - mod = alias_for_import_name(c, CHILD(n, idx)); - idx++; - break; - } else if (TYPE(CHILD(n, idx)) != DOT) { - break; - } - ndots++; - } - idx++; /* skip over the 'import' keyword */ - switch (TYPE(CHILD(n, idx))) { - case STAR: - /* from ... import * */ - n = CHILD(n, idx); - n_children = 1; - if (ndots) { - ast_error(n, "'import *' not allowed with 'from .'"); - return NULL; - } - break; - case LPAR: - /* from ... import (x, y, z) */ - n = CHILD(n, idx + 1); - n_children = NCH(n); - break; - case import_as_names: - /* from ... import x, y, z */ - n = CHILD(n, idx); - n_children = NCH(n); - if (n_children % 2 == 0) { - ast_error(n, "trailing comma not allowed without" - " surrounding parentheses"); - return NULL; - } - break; - default: - ast_error(n, "Unexpected node-type in from-import"); - return NULL; - } - - aliases = asdl_seq_new((n_children + 1) / 2, c->c_arena); - if (!aliases) - return NULL; - - /* handle "from ... import *" special b/c there's no children */ - if (TYPE(n) == STAR) { - alias_ty import_alias = alias_for_import_name(c, n); - if (!import_alias) - return NULL; - asdl_seq_SET(aliases, 0, import_alias); - } - else { - for (i = 0; i < NCH(n); i += 2) { - alias_ty import_alias = alias_for_import_name(c, CHILD(n, i)); - if (!import_alias) - return NULL; - asdl_seq_SET(aliases, i / 2, import_alias); - } - } - if (mod != NULL) - modname = mod->name; - else - modname = new_identifier("", c->c_arena); - return ImportFrom(modname, aliases, ndots, lineno, col_offset, - c->c_arena); + optional module name */ + for (idx = 1; idx < NCH(n); idx++) { + if (TYPE(CHILD(n, idx)) == dotted_name) { + mod = alias_for_import_name(c, CHILD(n, idx)); + idx++; + break; + } else if (TYPE(CHILD(n, idx)) != DOT) { + break; + } + ndots++; + } + idx++; /* skip over the 'import' keyword */ + switch (TYPE(CHILD(n, idx))) { + case STAR: + /* from ... import * */ + n = CHILD(n, idx); + n_children = 1; + if (ndots) { + ast_error(n, "'import *' not allowed with 'from .'"); + return NULL; + } + break; + case LPAR: + /* from ... import (x, y, z) */ + n = CHILD(n, idx + 1); + n_children = NCH(n); + break; + case import_as_names: + /* from ... import x, y, z */ + n = CHILD(n, idx); + n_children = NCH(n); + if (n_children % 2 == 0) { + ast_error(n, "trailing comma not allowed without" + " surrounding parentheses"); + return NULL; + } + break; + default: + ast_error(n, "Unexpected node-type in from-import"); + return NULL; + } + + aliases = asdl_seq_new((n_children + 1) / 2, c->c_arena); + if (!aliases) + return NULL; + + /* handle "from ... import *" special b/c there's no children */ + if (TYPE(n) == STAR) { + alias_ty import_alias = alias_for_import_name(c, n); + if (!import_alias) + return NULL; + asdl_seq_SET(aliases, 0, import_alias); + } + else { + for (i = 0; i < NCH(n); i += 2) { + alias_ty import_alias = alias_for_import_name(c, CHILD(n, i)); + if (!import_alias) + return NULL; + asdl_seq_SET(aliases, i / 2, import_alias); + } + } + if (mod != NULL) + modname = mod->name; + else + modname = new_identifier("", c->c_arena); + return ImportFrom(modname, aliases, ndots, lineno, col_offset, + c->c_arena); } PyErr_Format(PyExc_SystemError, - "unknown import statement: starts with command '%s'", - STR(CHILD(n, 0))); + "unknown import statement: starts with command '%s'", + STR(CHILD(n, 0))); return NULL; } @@ -2407,12 +2417,12 @@ REQ(n, global_stmt); s = asdl_seq_new(NCH(n) / 2, c->c_arena); if (!s) - return NULL; + return NULL; for (i = 1; i < NCH(n); i += 2) { - name = NEW_IDENTIFIER(CHILD(n, i)); - if (!name) - return NULL; - asdl_seq_SET(s, i / 2, name); + name = NEW_IDENTIFIER(CHILD(n, i)); + if (!name) + return NULL; + asdl_seq_SET(s, i / 2, name); } return Global(s, LINENO(n), n->n_col_offset, c->c_arena); } @@ -2423,29 +2433,30 @@ expr_ty expr1, globals = NULL, locals = NULL; int n_children = NCH(n); if (n_children != 2 && n_children != 4 && n_children != 6) { - PyErr_Format(PyExc_SystemError, - "poorly formed 'exec' statement: %d parts to statement", - n_children); - return NULL; + PyErr_Format(PyExc_SystemError, + "poorly formed 'exec' statement: %d parts to statement", + n_children); + return NULL; } /* exec_stmt: 'exec' expr ['in' test [',' test]] */ REQ(n, exec_stmt); expr1 = ast_for_expr(c, CHILD(n, 1)); if (!expr1) - return NULL; + return NULL; if (n_children >= 4) { - globals = ast_for_expr(c, CHILD(n, 3)); - if (!globals) - return NULL; + globals = ast_for_expr(c, CHILD(n, 3)); + if (!globals) + return NULL; } if (n_children == 6) { - locals = ast_for_expr(c, CHILD(n, 5)); - if (!locals) - return NULL; + locals = ast_for_expr(c, CHILD(n, 5)); + if (!locals) + return NULL; } - return Exec(expr1, globals, locals, LINENO(n), n->n_col_offset, c->c_arena); + return Exec(expr1, globals, locals, LINENO(n), n->n_col_offset, + c->c_arena); } static stmt_ty @@ -2454,26 +2465,27 @@ /* assert_stmt: 'assert' test [',' test] */ REQ(n, assert_stmt); if (NCH(n) == 2) { - expr_ty expression = ast_for_expr(c, CHILD(n, 1)); - if (!expression) - return NULL; - return Assert(expression, NULL, LINENO(n), n->n_col_offset, c->c_arena); + expr_ty expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + return Assert(expression, NULL, LINENO(n), n->n_col_offset, + c->c_arena); } else if (NCH(n) == 4) { - expr_ty expr1, expr2; + expr_ty expr1, expr2; - expr1 = ast_for_expr(c, CHILD(n, 1)); - if (!expr1) - return NULL; - expr2 = ast_for_expr(c, CHILD(n, 3)); - if (!expr2) - return NULL; - - return Assert(expr1, expr2, LINENO(n), n->n_col_offset, c->c_arena); + expr1 = ast_for_expr(c, CHILD(n, 1)); + if (!expr1) + return NULL; + expr2 = ast_for_expr(c, CHILD(n, 3)); + if (!expr2) + return NULL; + + return Assert(expr1, expr2, LINENO(n), n->n_col_offset, c->c_arena); } PyErr_Format(PyExc_SystemError, - "improper number of parts to 'assert' statement: %d", - NCH(n)); + "improper number of parts to 'assert' statement: %d", + NCH(n)); return NULL; } @@ -2491,53 +2503,53 @@ total = num_stmts(n); seq = asdl_seq_new(total, c->c_arena); if (!seq) - return NULL; + return NULL; if (TYPE(CHILD(n, 0)) == simple_stmt) { - n = CHILD(n, 0); - /* simple_stmt always ends with a NEWLINE, - and may have a trailing SEMI - */ - end = NCH(n) - 1; - if (TYPE(CHILD(n, end - 1)) == SEMI) - end--; - /* loop by 2 to skip semi-colons */ - for (i = 0; i < end; i += 2) { - ch = CHILD(n, i); - s = ast_for_stmt(c, ch); - if (!s) - return NULL; - asdl_seq_SET(seq, pos++, s); - } + n = CHILD(n, 0); + /* simple_stmt always ends with a NEWLINE, + and may have a trailing SEMI + */ + end = NCH(n) - 1; + if (TYPE(CHILD(n, end - 1)) == SEMI) + end--; + /* loop by 2 to skip semi-colons */ + for (i = 0; i < end; i += 2) { + ch = CHILD(n, i); + s = ast_for_stmt(c, ch); + if (!s) + return NULL; + asdl_seq_SET(seq, pos++, s); + } } else { - for (i = 2; i < (NCH(n) - 1); i++) { - ch = CHILD(n, i); - REQ(ch, stmt); - num = num_stmts(ch); - if (num == 1) { - /* small_stmt or compound_stmt with only one child */ - s = ast_for_stmt(c, ch); - if (!s) - return NULL; - asdl_seq_SET(seq, pos++, s); - } - else { - int j; - ch = CHILD(ch, 0); - REQ(ch, simple_stmt); - for (j = 0; j < NCH(ch); j += 2) { - /* statement terminates with a semi-colon ';' */ - if (NCH(CHILD(ch, j)) == 0) { - assert((j + 1) == NCH(ch)); - break; - } - s = ast_for_stmt(c, CHILD(ch, j)); - if (!s) - return NULL; - asdl_seq_SET(seq, pos++, s); - } - } - } + for (i = 2; i < (NCH(n) - 1); i++) { + ch = CHILD(n, i); + REQ(ch, stmt); + num = num_stmts(ch); + if (num == 1) { + /* small_stmt or compound_stmt with only one child */ + s = ast_for_stmt(c, ch); + if (!s) + return NULL; + asdl_seq_SET(seq, pos++, s); + } + else { + int j; + ch = CHILD(ch, 0); + REQ(ch, simple_stmt); + for (j = 0; j < NCH(ch); j += 2) { + /* statement terminates with a semi-colon ';' */ + if (NCH(CHILD(ch, j)) == 0) { + assert((j + 1) == NCH(ch)); + break; + } + s = ast_for_stmt(c, CHILD(ch, j)); + if (!s) + return NULL; + asdl_seq_SET(seq, pos++, s); + } + } + } } assert(pos == seq->size); return seq; @@ -2554,17 +2566,18 @@ REQ(n, if_stmt); if (NCH(n) == 4) { - expr_ty expression; - asdl_seq *suite_seq; + expr_ty expression; + asdl_seq *suite_seq; - expression = ast_for_expr(c, CHILD(n, 1)); - if (!expression) - return NULL; - suite_seq = ast_for_suite(c, CHILD(n, 3)); - if (!suite_seq) - return NULL; - - return If(expression, suite_seq, NULL, LINENO(n), n->n_col_offset, c->c_arena); + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, 3)); + if (!suite_seq) + return NULL; + + return If(expression, suite_seq, NULL, LINENO(n), n->n_col_offset, + c->c_arena); } s = STR(CHILD(n, 4)); @@ -2573,88 +2586,92 @@ 'i' for el_i_f */ if (s[2] == 's') { - expr_ty expression; - asdl_seq *seq1, *seq2; + expr_ty expression; + asdl_seq *seq1, *seq2; - expression = ast_for_expr(c, CHILD(n, 1)); - if (!expression) - return NULL; - seq1 = ast_for_suite(c, CHILD(n, 3)); - if (!seq1) - return NULL; - seq2 = ast_for_suite(c, CHILD(n, 6)); - if (!seq2) - return NULL; + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + seq1 = ast_for_suite(c, CHILD(n, 3)); + if (!seq1) + return NULL; + seq2 = ast_for_suite(c, CHILD(n, 6)); + if (!seq2) + return NULL; - return If(expression, seq1, seq2, LINENO(n), n->n_col_offset, c->c_arena); + return If(expression, seq1, seq2, LINENO(n), n->n_col_offset, + c->c_arena); } else if (s[2] == 'i') { - int i, n_elif, has_else = 0; - expr_ty expression; - asdl_seq *suite_seq; - asdl_seq *orelse = NULL; - n_elif = NCH(n) - 4; - /* must reference the child n_elif+1 since 'else' token is third, - not fourth, child from the end. */ - if (TYPE(CHILD(n, (n_elif + 1))) == NAME - && STR(CHILD(n, (n_elif + 1)))[2] == 's') { - has_else = 1; - n_elif -= 3; - } - n_elif /= 4; - - if (has_else) { - asdl_seq *suite_seq2; - - orelse = asdl_seq_new(1, c->c_arena); - if (!orelse) - return NULL; - expression = ast_for_expr(c, CHILD(n, NCH(n) - 6)); - if (!expression) - return NULL; - suite_seq = ast_for_suite(c, CHILD(n, NCH(n) - 4)); - if (!suite_seq) - return NULL; - suite_seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1)); - if (!suite_seq2) - return NULL; - - asdl_seq_SET(orelse, 0, If(expression, suite_seq, suite_seq2, - LINENO(CHILD(n, NCH(n) - 6)), CHILD(n, NCH(n) - 6)->n_col_offset, - c->c_arena)); - /* the just-created orelse handled the last elif */ - n_elif--; - } - - for (i = 0; i < n_elif; i++) { - int off = 5 + (n_elif - i - 1) * 4; - asdl_seq *newobj = asdl_seq_new(1, c->c_arena); - if (!newobj) - return NULL; - expression = ast_for_expr(c, CHILD(n, off)); - if (!expression) - return NULL; - suite_seq = ast_for_suite(c, CHILD(n, off + 2)); - if (!suite_seq) - return NULL; - - asdl_seq_SET(newobj, 0, - If(expression, suite_seq, orelse, - LINENO(CHILD(n, off)), CHILD(n, off)->n_col_offset, c->c_arena)); - orelse = newobj; - } - expression = ast_for_expr(c, CHILD(n, 1)); - if (!expression) - return NULL; - suite_seq = ast_for_suite(c, CHILD(n, 3)); - if (!suite_seq) - return NULL; - return If(expression, suite_seq, orelse, - LINENO(n), n->n_col_offset, c->c_arena); + int i, n_elif, has_else = 0; + expr_ty expression; + asdl_seq *suite_seq; + asdl_seq *orelse = NULL; + n_elif = NCH(n) - 4; + /* must reference the child n_elif+1 since 'else' token is third, + not fourth, child from the end. */ + if (TYPE(CHILD(n, (n_elif + 1))) == NAME + && STR(CHILD(n, (n_elif + 1)))[2] == 's') { + has_else = 1; + n_elif -= 3; + } + n_elif /= 4; + + if (has_else) { + asdl_seq *suite_seq2; + + orelse = asdl_seq_new(1, c->c_arena); + if (!orelse) + return NULL; + expression = ast_for_expr(c, CHILD(n, NCH(n) - 6)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, NCH(n) - 4)); + if (!suite_seq) + return NULL; + suite_seq2 = ast_for_suite(c, CHILD(n, NCH(n) - 1)); + if (!suite_seq2) + return NULL; + + asdl_seq_SET(orelse, 0, + If(expression, suite_seq, suite_seq2, + LINENO(CHILD(n, NCH(n) - 6)), + CHILD(n, NCH(n) - 6)->n_col_offset, + c->c_arena)); + /* the just-created orelse handled the last elif */ + n_elif--; + } + + for (i = 0; i < n_elif; i++) { + int off = 5 + (n_elif - i - 1) * 4; + asdl_seq *newobj = asdl_seq_new(1, c->c_arena); + if (!newobj) + return NULL; + expression = ast_for_expr(c, CHILD(n, off)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, off + 2)); + if (!suite_seq) + return NULL; + + asdl_seq_SET(newobj, 0, + If(expression, suite_seq, orelse, + LINENO(CHILD(n, off)), + CHILD(n, off)->n_col_offset, c->c_arena)); + orelse = newobj; + } + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, 3)); + if (!suite_seq) + return NULL; + return If(expression, suite_seq, orelse, + LINENO(n), n->n_col_offset, c->c_arena); } PyErr_Format(PyExc_SystemError, - "unexpected token in 'if' statement: %s", s); + "unexpected token in 'if' statement: %s", s); return NULL; } @@ -2665,37 +2682,39 @@ REQ(n, while_stmt); if (NCH(n) == 4) { - expr_ty expression; - asdl_seq *suite_seq; + expr_ty expression; + asdl_seq *suite_seq; - expression = ast_for_expr(c, CHILD(n, 1)); - if (!expression) - return NULL; - suite_seq = ast_for_suite(c, CHILD(n, 3)); - if (!suite_seq) - return NULL; - return While(expression, suite_seq, NULL, LINENO(n), n->n_col_offset, c->c_arena); + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, CHILD(n, 3)); + if (!suite_seq) + return NULL; + return While(expression, suite_seq, NULL, LINENO(n), n->n_col_offset, + c->c_arena); } else if (NCH(n) == 7) { - expr_ty expression; - asdl_seq *seq1, *seq2; + expr_ty expression; + asdl_seq *seq1, *seq2; - expression = ast_for_expr(c, CHILD(n, 1)); - if (!expression) - return NULL; - seq1 = ast_for_suite(c, CHILD(n, 3)); - if (!seq1) - return NULL; - seq2 = ast_for_suite(c, CHILD(n, 6)); - if (!seq2) - return NULL; + expression = ast_for_expr(c, CHILD(n, 1)); + if (!expression) + return NULL; + seq1 = ast_for_suite(c, CHILD(n, 3)); + if (!seq1) + return NULL; + seq2 = ast_for_suite(c, CHILD(n, 6)); + if (!seq2) + return NULL; - return While(expression, seq1, seq2, LINENO(n), n->n_col_offset, c->c_arena); + return While(expression, seq1, seq2, LINENO(n), n->n_col_offset, + c->c_arena); } PyErr_Format(PyExc_SystemError, - "wrong number of tokens for 'while' statement: %d", - NCH(n)); + "wrong number of tokens for 'while' statement: %d", + NCH(n)); return NULL; } @@ -2710,31 +2729,31 @@ REQ(n, for_stmt); if (NCH(n) == 9) { - seq = ast_for_suite(c, CHILD(n, 8)); - if (!seq) - return NULL; + seq = ast_for_suite(c, CHILD(n, 8)); + if (!seq) + return NULL; } node_target = CHILD(n, 1); _target = ast_for_exprlist(c, node_target, Store); if (!_target) - return NULL; + return NULL; /* Check the # of children rather than the length of _target, since for x, in ... has 1 element in _target, but still requires a Tuple. */ if (NCH(node_target) == 1) - target = (expr_ty)asdl_seq_GET(_target, 0); + target = (expr_ty)asdl_seq_GET(_target, 0); else - target = Tuple(_target, Store, LINENO(n), n->n_col_offset, c->c_arena); + target = Tuple(_target, Store, LINENO(n), n->n_col_offset, c->c_arena); expression = ast_for_testlist(c, CHILD(n, 3)); if (!expression) - return NULL; + return NULL; suite_seq = ast_for_suite(c, CHILD(n, 5)); if (!suite_seq) - return NULL; + return NULL; return For(target, expression, suite_seq, seq, LINENO(n), n->n_col_offset, - c->c_arena); + c->c_arena); } static excepthandler_ty @@ -2745,49 +2764,49 @@ REQ(body, suite); if (NCH(exc) == 1) { - asdl_seq *suite_seq = ast_for_suite(c, body); - if (!suite_seq) - return NULL; + asdl_seq *suite_seq = ast_for_suite(c, body); + if (!suite_seq) + return NULL; - return excepthandler(NULL, NULL, suite_seq, LINENO(exc), - exc->n_col_offset, c->c_arena); + return excepthandler(NULL, NULL, suite_seq, LINENO(exc), + exc->n_col_offset, c->c_arena); } else if (NCH(exc) == 2) { - expr_ty expression; - asdl_seq *suite_seq; + expr_ty expression; + asdl_seq *suite_seq; - expression = ast_for_expr(c, CHILD(exc, 1)); - if (!expression) - return NULL; - suite_seq = ast_for_suite(c, body); - if (!suite_seq) - return NULL; + expression = ast_for_expr(c, CHILD(exc, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, body); + if (!suite_seq) + return NULL; - return excepthandler(expression, NULL, suite_seq, LINENO(exc), - exc->n_col_offset, c->c_arena); + return excepthandler(expression, NULL, suite_seq, LINENO(exc), + exc->n_col_offset, c->c_arena); } else if (NCH(exc) == 4) { - asdl_seq *suite_seq; - expr_ty expression; - expr_ty e = ast_for_expr(c, CHILD(exc, 3)); - if (!e) - return NULL; - if (!set_context(e, Store, CHILD(exc, 3))) - return NULL; - expression = ast_for_expr(c, CHILD(exc, 1)); - if (!expression) - return NULL; - suite_seq = ast_for_suite(c, body); - if (!suite_seq) - return NULL; + asdl_seq *suite_seq; + expr_ty expression; + expr_ty e = ast_for_expr(c, CHILD(exc, 3)); + if (!e) + return NULL; + if (!set_context(e, Store, CHILD(exc, 3))) + return NULL; + expression = ast_for_expr(c, CHILD(exc, 1)); + if (!expression) + return NULL; + suite_seq = ast_for_suite(c, body); + if (!suite_seq) + return NULL; - return excepthandler(expression, e, suite_seq, LINENO(exc), - exc->n_col_offset, c->c_arena); + return excepthandler(expression, e, suite_seq, LINENO(exc), + exc->n_col_offset, c->c_arena); } PyErr_Format(PyExc_SystemError, - "wrong number of children for 'except' clause: %d", - NCH(exc)); + "wrong number of children for 'except' clause: %d", + NCH(exc)); return NULL; } @@ -2802,66 +2821,66 @@ body = ast_for_suite(c, CHILD(n, 2)); if (body == NULL) - return NULL; + return NULL; if (TYPE(CHILD(n, nch - 3)) == NAME) { - if (strcmp(STR(CHILD(n, nch - 3)), "finally") == 0) { - if (nch >= 9 && TYPE(CHILD(n, nch - 6)) == NAME) { - /* we can assume it's an "else", - because nch >= 9 for try-else-finally and - it would otherwise have a type of except_clause */ - orelse = ast_for_suite(c, CHILD(n, nch - 4)); - if (orelse == NULL) - return NULL; - n_except--; - } - - finally = ast_for_suite(c, CHILD(n, nch - 1)); - if (finally == NULL) - return NULL; - n_except--; - } - else { - /* we can assume it's an "else", - otherwise it would have a type of except_clause */ - orelse = ast_for_suite(c, CHILD(n, nch - 1)); - if (orelse == NULL) - return NULL; - n_except--; - } + if (strcmp(STR(CHILD(n, nch - 3)), "finally") == 0) { + if (nch >= 9 && TYPE(CHILD(n, nch - 6)) == NAME) { + /* we can assume it's an "else", + because nch >= 9 for try-else-finally and + it would otherwise have a type of except_clause */ + orelse = ast_for_suite(c, CHILD(n, nch - 4)); + if (orelse == NULL) + return NULL; + n_except--; + } + + finally = ast_for_suite(c, CHILD(n, nch - 1)); + if (finally == NULL) + return NULL; + n_except--; + } + else { + /* we can assume it's an "else", + otherwise it would have a type of except_clause */ + orelse = ast_for_suite(c, CHILD(n, nch - 1)); + if (orelse == NULL) + return NULL; + n_except--; + } } else if (TYPE(CHILD(n, nch - 3)) != except_clause) { - ast_error(n, "malformed 'try' statement"); - return NULL; + ast_error(n, "malformed 'try' statement"); + return NULL; } if (n_except > 0) { - int i; - stmt_ty except_st; - /* process except statements to create a try ... except */ - asdl_seq *handlers = asdl_seq_new(n_except, c->c_arena); - if (handlers == NULL) - return NULL; - - for (i = 0; i < n_except; i++) { - excepthandler_ty e = ast_for_except_clause(c, CHILD(n, 3 + i * 3), - CHILD(n, 5 + i * 3)); - if (!e) - return NULL; - asdl_seq_SET(handlers, i, e); - } - - except_st = TryExcept(body, handlers, orelse, LINENO(n), - n->n_col_offset, c->c_arena); - if (!finally) - return except_st; - - /* if a 'finally' is present too, we nest the TryExcept within a - TryFinally to emulate try ... except ... finally */ - body = asdl_seq_new(1, c->c_arena); - if (body == NULL) - return NULL; - asdl_seq_SET(body, 0, except_st); + int i; + stmt_ty except_st; + /* process except statements to create a try ... except */ + asdl_seq *handlers = asdl_seq_new(n_except, c->c_arena); + if (handlers == NULL) + return NULL; + + for (i = 0; i < n_except; i++) { + excepthandler_ty e = ast_for_except_clause(c, CHILD(n, 3 + i * 3), + CHILD(n, 5 + i * 3)); + if (!e) + return NULL; + asdl_seq_SET(handlers, i, e); + } + + except_st = TryExcept(body, handlers, orelse, LINENO(n), + n->n_col_offset, c->c_arena); + if (!finally) + return except_st; + + /* if a 'finally' is present too, we nest the TryExcept within a + TryFinally to emulate try ... except ... finally */ + body = asdl_seq_new(1, c->c_arena); + if (body == NULL) + return NULL; + asdl_seq_SET(body, 0, except_st); } /* must be a try ... finally (except clauses are in body, if any exist) */ @@ -2889,23 +2908,23 @@ if (!context_expr) return NULL; if (TYPE(CHILD(n, 2)) == with_var) { - optional_vars = ast_for_with_var(c, CHILD(n, 2)); + optional_vars = ast_for_with_var(c, CHILD(n, 2)); - if (!optional_vars) { - return NULL; - } - if (!set_context(optional_vars, Store, n)) { - return NULL; - } - suite_index = 4; + if (!optional_vars) { + return NULL; + } + if (!set_context(optional_vars, Store, n)) { + return NULL; + } + suite_index = 4; } suite_seq = ast_for_suite(c, CHILD(n, suite_index)); if (!suite_seq) { - return NULL; + return NULL; } return With(context_expr, optional_vars, suite_seq, LINENO(n), - n->n_col_offset, c->c_arena); + n->n_col_offset, c->c_arena); } static stmt_ty @@ -2917,246 +2936,246 @@ REQ(n, classdef); if (!strcmp(STR(CHILD(n, 1)), "None")) { - ast_error(n, "assignment to None"); - return NULL; + ast_error(n, "assignment to None"); + return NULL; } if (NCH(n) == 4) { - s = ast_for_suite(c, CHILD(n, 3)); - if (!s) - return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), - n->n_col_offset, c->c_arena); + s = ast_for_suite(c, CHILD(n, 3)); + if (!s) + return NULL; + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), + n->n_col_offset, c->c_arena); } /* check for empty base list */ if (TYPE(CHILD(n,3)) == RPAR) { - s = ast_for_suite(c, CHILD(n,5)); - if (!s) - return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), - n->n_col_offset, c->c_arena); + s = ast_for_suite(c, CHILD(n,5)); + if (!s) + return NULL; + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), + n->n_col_offset, c->c_arena); } /* else handle the base class list */ bases = ast_for_class_bases(c, CHILD(n, 3)); if (!bases) - return NULL; + return NULL; s = ast_for_suite(c, CHILD(n, 6)); if (!s) - return NULL; + return NULL; return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), bases, s, LINENO(n), - n->n_col_offset, c->c_arena); + n->n_col_offset, c->c_arena); } static stmt_ty ast_for_stmt(struct compiling *c, const node *n) { if (TYPE(n) == stmt) { - assert(NCH(n) == 1); - n = CHILD(n, 0); + assert(NCH(n) == 1); + n = CHILD(n, 0); } if (TYPE(n) == simple_stmt) { - assert(num_stmts(n) == 1); - n = CHILD(n, 0); + assert(num_stmts(n) == 1); + n = CHILD(n, 0); } if (TYPE(n) == small_stmt) { - REQ(n, small_stmt); - n = CHILD(n, 0); - /* small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt - | flow_stmt | import_stmt | global_stmt | exec_stmt - | assert_stmt - */ - switch (TYPE(n)) { - case expr_stmt: - return ast_for_expr_stmt(c, n); - case print_stmt: - return ast_for_print_stmt(c, n); - case del_stmt: - return ast_for_del_stmt(c, n); - case pass_stmt: - return Pass(LINENO(n), n->n_col_offset, c->c_arena); - case flow_stmt: - return ast_for_flow_stmt(c, n); - case import_stmt: - return ast_for_import_stmt(c, n); - case global_stmt: - return ast_for_global_stmt(c, n); - case exec_stmt: - return ast_for_exec_stmt(c, n); - case assert_stmt: - return ast_for_assert_stmt(c, n); - default: - PyErr_Format(PyExc_SystemError, - "unhandled small_stmt: TYPE=%d NCH=%d\n", - TYPE(n), NCH(n)); - return NULL; - } + REQ(n, small_stmt); + n = CHILD(n, 0); + /* small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt + | flow_stmt | import_stmt | global_stmt | exec_stmt + | assert_stmt + */ + switch (TYPE(n)) { + case expr_stmt: + return ast_for_expr_stmt(c, n); + case print_stmt: + return ast_for_print_stmt(c, n); + case del_stmt: + return ast_for_del_stmt(c, n); + case pass_stmt: + return Pass(LINENO(n), n->n_col_offset, c->c_arena); + case flow_stmt: + return ast_for_flow_stmt(c, n); + case import_stmt: + return ast_for_import_stmt(c, n); + case global_stmt: + return ast_for_global_stmt(c, n); + case exec_stmt: + return ast_for_exec_stmt(c, n); + case assert_stmt: + return ast_for_assert_stmt(c, n); + default: + PyErr_Format(PyExc_SystemError, + "unhandled small_stmt: TYPE=%d NCH=%d\n", + TYPE(n), NCH(n)); + return NULL; + } } else { - /* compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt - | funcdef | classdef - */ - node *ch = CHILD(n, 0); - REQ(n, compound_stmt); - switch (TYPE(ch)) { - case if_stmt: - return ast_for_if_stmt(c, ch); - case while_stmt: - return ast_for_while_stmt(c, ch); - case for_stmt: - return ast_for_for_stmt(c, ch); - case try_stmt: - return ast_for_try_stmt(c, ch); - case with_stmt: - return ast_for_with_stmt(c, ch); - case funcdef: - return ast_for_funcdef(c, ch); - case classdef: - return ast_for_classdef(c, ch); - default: - PyErr_Format(PyExc_SystemError, - "unhandled small_stmt: TYPE=%d NCH=%d\n", - TYPE(n), NCH(n)); - return NULL; - } + /* compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt + | funcdef | classdef + */ + node *ch = CHILD(n, 0); + REQ(n, compound_stmt); + switch (TYPE(ch)) { + case if_stmt: + return ast_for_if_stmt(c, ch); + case while_stmt: + return ast_for_while_stmt(c, ch); + case for_stmt: + return ast_for_for_stmt(c, ch); + case try_stmt: + return ast_for_try_stmt(c, ch); + case with_stmt: + return ast_for_with_stmt(c, ch); + case funcdef: + return ast_for_funcdef(c, ch); + case classdef: + return ast_for_classdef(c, ch); + default: + PyErr_Format(PyExc_SystemError, + "unhandled small_stmt: TYPE=%d NCH=%d\n", + TYPE(n), NCH(n)); + return NULL; + } } } static PyObject * parsenumber(const char *s) { - const char *end; - long x; - double dx; + const char *end; + long x; + double dx; #ifndef WITHOUT_COMPLEX - Py_complex c; - int imflag; + Py_complex c; + int imflag; #endif - errno = 0; - end = s + strlen(s) - 1; + errno = 0; + end = s + strlen(s) - 1; #ifndef WITHOUT_COMPLEX - imflag = *end == 'j' || *end == 'J'; + imflag = *end == 'j' || *end == 'J'; #endif - if (*end == 'l' || *end == 'L') - return PyLong_FromString((char *)s, (char **)0, 0); - if (s[0] == '0') { - x = (long) PyOS_strtoul((char *)s, (char **)&end, 0); - if (x < 0 && errno == 0) { - return PyLong_FromString((char *)s, - (char **)0, - 0); - } - } - else - x = PyOS_strtol((char *)s, (char **)&end, 0); - if (*end == '\0') { - if (errno != 0) - return PyLong_FromString((char *)s, (char **)0, 0); - return PyInt_FromLong(x); - } - /* XXX Huge floats may silently fail */ + if (*end == 'l' || *end == 'L') + return PyLong_FromString((char *)s, (char **)0, 0); + if (s[0] == '0') { + x = (long) PyOS_strtoul((char *)s, (char **)&end, 0); + if (x < 0 && errno == 0) { + return PyLong_FromString((char *)s, + (char **)0, + 0); + } + } + else + x = PyOS_strtol((char *)s, (char **)&end, 0); + if (*end == '\0') { + if (errno != 0) + return PyLong_FromString((char *)s, (char **)0, 0); + return PyInt_FromLong(x); + } + /* XXX Huge floats may silently fail */ #ifndef WITHOUT_COMPLEX - if (imflag) { - c.real = 0.; - PyFPE_START_PROTECT("atof", return 0) - c.imag = PyOS_ascii_atof(s); - PyFPE_END_PROTECT(c) - return PyComplex_FromCComplex(c); - } - else + if (imflag) { + c.real = 0.; + PyFPE_START_PROTECT("atof", return 0) + c.imag = PyOS_ascii_atof(s); + PyFPE_END_PROTECT(c) + return PyComplex_FromCComplex(c); + } + else #endif - { - PyFPE_START_PROTECT("atof", return 0) - dx = PyOS_ascii_atof(s); - PyFPE_END_PROTECT(dx) - return PyFloat_FromDouble(dx); - } + { + PyFPE_START_PROTECT("atof", return 0) + dx = PyOS_ascii_atof(s); + PyFPE_END_PROTECT(dx) + return PyFloat_FromDouble(dx); + } } static PyObject * decode_utf8(const char **sPtr, const char *end, char* encoding) { #ifndef Py_USING_UNICODE - Py_FatalError("decode_utf8 should not be called in this build."); - return NULL; + Py_FatalError("decode_utf8 should not be called in this build."); + return NULL; #else - PyObject *u, *v; - char *s, *t; - t = s = (char *)*sPtr; - /* while (s < end && *s != '\\') s++; */ /* inefficient for u".." */ - while (s < end && (*s & 0x80)) s++; - *sPtr = s; - u = PyUnicode_DecodeUTF8(t, s - t, NULL); - if (u == NULL) - return NULL; - v = PyUnicode_AsEncodedString(u, encoding, NULL); - Py_DECREF(u); - return v; + PyObject *u, *v; + char *s, *t; + t = s = (char *)*sPtr; + /* while (s < end && *s != '\\') s++; */ /* inefficient for u".." */ + while (s < end && (*s & 0x80)) s++; + *sPtr = s; + u = PyUnicode_DecodeUTF8(t, s - t, NULL); + if (u == NULL) + return NULL; + v = PyUnicode_AsEncodedString(u, encoding, NULL); + Py_DECREF(u); + return v; #endif } static PyObject * decode_unicode(const char *s, size_t len, int rawmode, const char *encoding) { - PyObject *v, *u; - char *buf; - char *p; - const char *end; - if (encoding == NULL) { - buf = (char *)s; - u = NULL; - } else if (strcmp(encoding, "iso-8859-1") == 0) { - buf = (char *)s; - u = NULL; - } else { - /* "\XX" may become "\u005c\uHHLL" (12 bytes) */ - u = PyString_FromStringAndSize((char *)NULL, len * 4); - if (u == NULL) - return NULL; - p = buf = PyString_AsString(u); - end = s + len; - while (s < end) { - if (*s == '\\') { - *p++ = *s++; - if (*s & 0x80) { - strcpy(p, "u005c"); - p += 5; - } - } - if (*s & 0x80) { /* XXX inefficient */ - PyObject *w; - char *r; - Py_ssize_t rn, i; - w = decode_utf8(&s, end, "utf-16-be"); - if (w == NULL) { - Py_DECREF(u); - return NULL; - } - r = PyString_AsString(w); - rn = PyString_Size(w); - assert(rn % 2 == 0); - for (i = 0; i < rn; i += 2) { - sprintf(p, "\\u%02x%02x", - r[i + 0] & 0xFF, - r[i + 1] & 0xFF); - p += 6; - } - Py_DECREF(w); - } else { - *p++ = *s++; - } - } - len = p - buf; - s = buf; - } - if (rawmode) - v = PyUnicode_DecodeRawUnicodeEscape(s, len, NULL); - else - v = PyUnicode_DecodeUnicodeEscape(s, len, NULL); - Py_XDECREF(u); - return v; + PyObject *v, *u; + char *buf; + char *p; + const char *end; + if (encoding == NULL) { + buf = (char *)s; + u = NULL; + } else if (strcmp(encoding, "iso-8859-1") == 0) { + buf = (char *)s; + u = NULL; + } else { + /* "\XX" may become "\u005c\uHHLL" (12 bytes) */ + u = PyString_FromStringAndSize((char *)NULL, len * 4); + if (u == NULL) + return NULL; + p = buf = PyString_AsString(u); + end = s + len; + while (s < end) { + if (*s == '\\') { + *p++ = *s++; + if (*s & 0x80) { + strcpy(p, "u005c"); + p += 5; + } + } + if (*s & 0x80) { /* XXX inefficient */ + PyObject *w; + char *r; + Py_ssize_t rn, i; + w = decode_utf8(&s, end, "utf-16-be"); + if (w == NULL) { + Py_DECREF(u); + return NULL; + } + r = PyString_AsString(w); + rn = PyString_Size(w); + assert(rn % 2 == 0); + for (i = 0; i < rn; i += 2) { + sprintf(p, "\\u%02x%02x", + r[i + 0] & 0xFF, + r[i + 1] & 0xFF); + p += 6; + } + Py_DECREF(w); + } else { + *p++ = *s++; + } + } + len = p - buf; + s = buf; + } + if (rawmode) + v = PyUnicode_DecodeRawUnicodeEscape(s, len, NULL); + else + v = PyUnicode_DecodeUnicodeEscape(s, len, NULL); + Py_XDECREF(u); + return v; } /* s is a Python string literal, including the bracketing quote characters, @@ -3166,75 +3185,75 @@ static PyObject * parsestr(const char *s, const char *encoding) { - size_t len; - int quote = Py_CHARMASK(*s); - int rawmode = 0; - int need_encoding; - int unicode = 0; - - if (isalpha(quote) || quote == '_') { - if (quote == 'u' || quote == 'U') { - quote = *++s; - unicode = 1; - } - if (quote == 'r' || quote == 'R') { - quote = *++s; - rawmode = 1; - } - } - if (quote != '\'' && quote != '\"') { - PyErr_BadInternalCall(); - return NULL; - } - s++; - len = strlen(s); - if (len > INT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "string to parse is too long"); - return NULL; - } - if (s[--len] != quote) { - PyErr_BadInternalCall(); - return NULL; - } - if (len >= 4 && s[0] == quote && s[1] == quote) { - s += 2; - len -= 2; - if (s[--len] != quote || s[--len] != quote) { - PyErr_BadInternalCall(); - return NULL; - } - } + size_t len; + int quote = Py_CHARMASK(*s); + int rawmode = 0; + int need_encoding; + int unicode = 0; + + if (isalpha(quote) || quote == '_') { + if (quote == 'u' || quote == 'U') { + quote = *++s; + unicode = 1; + } + if (quote == 'r' || quote == 'R') { + quote = *++s; + rawmode = 1; + } + } + if (quote != '\'' && quote != '\"') { + PyErr_BadInternalCall(); + return NULL; + } + s++; + len = strlen(s); + if (len > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "string to parse is too long"); + return NULL; + } + if (s[--len] != quote) { + PyErr_BadInternalCall(); + return NULL; + } + if (len >= 4 && s[0] == quote && s[1] == quote) { + s += 2; + len -= 2; + if (s[--len] != quote || s[--len] != quote) { + PyErr_BadInternalCall(); + return NULL; + } + } #ifdef Py_USING_UNICODE - if (unicode || Py_UnicodeFlag) { - return decode_unicode(s, len, rawmode, encoding); - } + if (unicode || Py_UnicodeFlag) { + return decode_unicode(s, len, rawmode, encoding); + } #endif - need_encoding = (encoding != NULL && - strcmp(encoding, "utf-8") != 0 && - strcmp(encoding, "iso-8859-1") != 0); - if (rawmode || strchr(s, '\\') == NULL) { - if (need_encoding) { + need_encoding = (encoding != NULL && + strcmp(encoding, "utf-8") != 0 && + strcmp(encoding, "iso-8859-1") != 0); + if (rawmode || strchr(s, '\\') == NULL) { + if (need_encoding) { #ifndef Py_USING_UNICODE - /* This should not happen - we never see any other - encoding. */ - Py_FatalError( - "cannot deal with encodings in this build."); + /* This should not happen - we never see any other + encoding. */ + Py_FatalError( + "cannot deal with encodings in this build."); #else - PyObject *v, *u = PyUnicode_DecodeUTF8(s, len, NULL); - if (u == NULL) - return NULL; - v = PyUnicode_AsEncodedString(u, encoding, NULL); - Py_DECREF(u); - return v; + PyObject *v, *u = PyUnicode_DecodeUTF8(s, len, NULL); + if (u == NULL) + return NULL; + v = PyUnicode_AsEncodedString(u, encoding, NULL); + Py_DECREF(u); + return v; #endif - } else { - return PyString_FromStringAndSize(s, len); - } - } + } else { + return PyString_FromStringAndSize(s, len); + } + } - return PyString_DecodeEscape(s, len, NULL, unicode, - need_encoding ? encoding : NULL); + return PyString_DecodeEscape(s, len, NULL, unicode, + need_encoding ? encoding : NULL); } /* Build a Python string object out of a STRING atom. This takes care of @@ -3244,36 +3263,36 @@ static PyObject * parsestrplus(struct compiling *c, const node *n) { - PyObject *v; - int i; - REQ(CHILD(n, 0), STRING); - if ((v = parsestr(STR(CHILD(n, 0)), c->c_encoding)) != NULL) { - /* String literal concatenation */ - for (i = 1; i < NCH(n); i++) { - PyObject *s; - s = parsestr(STR(CHILD(n, i)), c->c_encoding); - if (s == NULL) - goto onError; - if (PyString_Check(v) && PyString_Check(s)) { - PyString_ConcatAndDel(&v, s); - if (v == NULL) - goto onError; - } + PyObject *v; + int i; + REQ(CHILD(n, 0), STRING); + if ((v = parsestr(STR(CHILD(n, 0)), c->c_encoding)) != NULL) { + /* String literal concatenation */ + for (i = 1; i < NCH(n); i++) { + PyObject *s; + s = parsestr(STR(CHILD(n, i)), c->c_encoding); + if (s == NULL) + goto onError; + if (PyString_Check(v) && PyString_Check(s)) { + PyString_ConcatAndDel(&v, s); + if (v == NULL) + goto onError; + } #ifdef Py_USING_UNICODE - else { - PyObject *temp = PyUnicode_Concat(v, s); - Py_DECREF(s); - Py_DECREF(v); - v = temp; - if (v == NULL) - goto onError; - } + else { + PyObject *temp = PyUnicode_Concat(v, s); + Py_DECREF(s); + Py_DECREF(v); + v = temp; + if (v == NULL) + goto onError; + } #endif - } - } - return v; + } + } + return v; onError: - Py_XDECREF(v); - return NULL; + Py_XDECREF(v); + return NULL; } From buildbot at python.org Fri Mar 16 17:54:28 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 16 Mar 2007 16:54:28 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070316165428.71D511E400D@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/143 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: jeremy.hylton Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From buildbot at python.org Fri Mar 16 18:04:00 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 16 Mar 2007 17:04:00 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070316170400.E5A721E400D@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/322 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: jeremy.hylton,ziga.seilnacht Build had warnings: warnings test Excerpt from the test logfile: 6 tests failed: test_class test_mailbox test_os test_pkg test_pyexpat test_thread ====================================================================== ERROR: test_makedir (test.test_os.MakedirTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 376, in setUp os.mkdir(test_support.TESTFN) WindowsError: [Error 183] Cannot create a file when that file already exists: '@test' ====================================================================== ERROR: test_access (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 443, in test_access self.assertRaises(WindowsError, os.utime, test_support.TESTFN, 0) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\unittest.py", line 329, in failUnlessRaises callableObj(*args, **kwargs) TypeError: utime() arg 2 must be a tuple (atime, mtime) ====================================================================== FAIL: test_traversal (test.test_os.WalkTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 311, in test_traversal self.assertEqual(len(all), 4) AssertionError: 5 != 4 ====================================================================== FAIL: test_chdir (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 434, in test_chdir self.assertRaises(WindowsError, os.chdir, test_support.TESTFN) AssertionError: WindowsError not raised sincerely, -The Buildbot From python-checkins at python.org Fri Mar 16 21:01:58 2007 From: python-checkins at python.org (david.goodger) Date: Fri, 16 Mar 2007 21:01:58 +0100 (CET) Subject: [Python-checkins] r54416 - peps/trunk/pep-3112.txt Message-ID: <20070316200158.34CFC1E400D@bag.python.org> Author: david.goodger Date: Fri Mar 16 21:01:57 2007 New Revision: 54416 Modified: peps/trunk/pep-3112.txt Log: markup & punctuation fixes Modified: peps/trunk/pep-3112.txt ============================================================================== --- peps/trunk/pep-3112.txt (original) +++ peps/trunk/pep-3112.txt Fri Mar 16 21:01:57 2007 @@ -62,7 +62,7 @@ =============== The proposed syntax is an extension of the existing string -syntax. [#stringliterals]_ +syntax [#stringliterals]_. The new syntax for strings, including the new bytes literal, is:: @@ -89,12 +89,12 @@ between 1 and 127 inclusive, regardless of any encoding declaration [#encodings]_ in the source file. -- The Unicode-specific escape sequences ``\u``*xxxx*, - ``\U``*xxxxxxxx*, and ``\N{``*name*``}`` are unrecognized in +- The Unicode-specific escape sequences ``\u``\ *xxxx*, + ``\U``\ *xxxxxxxx*, and ``\N{``\ *name*\ ``}`` are unrecognized in Python 2.x and forbidden in Python 3000. Adjacent bytes literals are subject to the same concatenation rules as -adjacent string literals. [#concat]_ A bytes literal adjacent to a +adjacent string literals [#concat]_. A bytes literal adjacent to a string literal is an error. @@ -127,7 +127,7 @@ A bytes literal produces a new object each time it is evaluated, like list displays and unlike string literals. This is necessary because bytes literals, like lists and unlike strings, are -mutable. [#eachnew]_ +mutable [#eachnew]_. Reference Implementation From python-checkins at python.org Fri Mar 16 22:13:40 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 16 Mar 2007 22:13:40 +0100 (CET) Subject: [Python-checkins] r54417 - in python/trunk/Lib: popen2.py test/test_popen2.py Message-ID: <20070316211340.1B7241E400D@bag.python.org> Author: collin.winter Date: Fri Mar 16 22:13:35 2007 New Revision: 54417 Modified: python/trunk/Lib/popen2.py python/trunk/Lib/test/test_popen2.py Log: Patch #1676994: Refactor test_popen2 to use unittest. Modified: python/trunk/Lib/popen2.py ============================================================================== --- python/trunk/Lib/popen2.py (original) +++ python/trunk/Lib/popen2.py Fri Mar 16 22:13:35 2007 @@ -200,45 +200,3 @@ return inst.fromchild, inst.tochild __all__.extend(["Popen3", "Popen4"]) - -def _test(): - # When the test runs, there shouldn't be any open pipes - _cleanup() - assert not _active, "Active pipes when test starts " + repr([c.cmd for c in _active]) - cmd = "cat" - teststr = "ab cd\n" - if os.name == "nt": - cmd = "more" - # "more" doesn't act the same way across Windows flavors, - # sometimes adding an extra newline at the start or the - # end. So we strip whitespace off both ends for comparison. - expected = teststr.strip() - print "testing popen2..." - r, w = popen2(cmd) - w.write(teststr) - w.close() - got = r.read() - if got.strip() != expected: - raise ValueError("wrote %r read %r" % (teststr, got)) - print "testing popen3..." - try: - r, w, e = popen3([cmd]) - except: - r, w, e = popen3(cmd) - w.write(teststr) - w.close() - got = r.read() - if got.strip() != expected: - raise ValueError("wrote %r read %r" % (teststr, got)) - got = e.read() - if got: - raise ValueError("unexpected %r on stderr" % (got,)) - for inst in _active[:]: - inst.wait() - _cleanup() - if _active: - raise ValueError("_active not empty") - print "All OK" - -if __name__ == '__main__': - _test() Modified: python/trunk/Lib/test/test_popen2.py ============================================================================== --- python/trunk/Lib/test/test_popen2.py (original) +++ python/trunk/Lib/test/test_popen2.py Fri Mar 16 22:13:35 2007 @@ -1,78 +1,92 @@ #! /usr/bin/env python -"""Test script for popen2.py - Christian Tismer -""" +"""Test script for popen2.py""" import os import sys -from test.test_support import TestSkipped, reap_children +import unittest +import popen2 -# popen2 contains its own testing routine -# which is especially useful to see if open files -# like stdin can be read successfully by a forked -# subprocess. - -def main(): - print "Test popen2 module:" - if (sys.platform[:4] == 'beos' or sys.platform[:6] == 'atheos') \ - and __name__ != '__main__': - # Locks get messed up or something. Generally we're supposed - # to avoid mixing "posix" fork & exec with native threads, and - # they may be right about that after all. - raise TestSkipped, "popen2() doesn't work during import on " + sys.platform - try: - from os import popen - except ImportError: - # if we don't have os.popen, check that - # we have os.fork. if not, skip the test - # (by raising an ImportError) - from os import fork - import popen2 - popen2._test() - - -def _test(): - # same test as popen2._test(), but using the os.popen*() API - print "Testing os module:" - import popen2 - # When the test runs, there shouldn't be any open pipes - popen2._cleanup() - assert not popen2._active, "Active pipes when test starts " + repr([c.cmd for c in popen2._active]) - cmd = "cat" - teststr = "ab cd\n" +from test.test_support import TestSkipped, run_unittest, reap_children + +if sys.platform[:4] == 'beos' or sys.platform[:6] == 'atheos': + # Locks get messed up or something. Generally we're supposed + # to avoid mixing "posix" fork & exec with native threads, and + # they may be right about that after all. + raise TestSkipped("popen2() doesn't work on " + sys.platform) + +# if we don't have os.popen, check that +# we have os.fork. if not, skip the test +# (by raising an ImportError) +try: + from os import popen + del popen +except ImportError: + from os import fork + del fork + +class Popen2Test(unittest.TestCase): + cmd = "cat" if os.name == "nt": cmd = "more" + teststr = "ab cd\n" # "more" doesn't act the same way across Windows flavors, # sometimes adding an extra newline at the start or the # end. So we strip whitespace off both ends for comparison. expected = teststr.strip() - print "testing popen2..." - w, r = os.popen2(cmd) - w.write(teststr) - w.close() - got = r.read() - if got.strip() != expected: - raise ValueError("wrote %r read %r" % (teststr, got)) - print "testing popen3..." - try: - w, r, e = os.popen3([cmd]) - except: - w, r, e = os.popen3(cmd) - w.write(teststr) - w.close() - got = r.read() - if got.strip() != expected: - raise ValueError("wrote %r read %r" % (teststr, got)) - got = e.read() - if got: - raise ValueError("unexpected %r on stderr" % (got,)) - for inst in popen2._active[:]: - inst.wait() - popen2._cleanup() - if popen2._active: - raise ValueError("_active not empty") - print "All OK" - -main() -_test() -reap_children() + + def setUp(self): + popen2._cleanup() + # When the test runs, there shouldn't be any open pipes + self.assertFalse(popen2._active, "Active pipes when test starts" + + repr([c.cmd for c in popen2._active])) + + def tearDown(self): + for inst in popen2._active: + inst.wait() + popen2._cleanup() + self.assertFalse(popen2._active, "_active not empty") + reap_children() + + def validate_output(self, teststr, expected_out, r, w, e=None): + w.write(teststr) + w.close() + got = r.read() + self.assertEquals(expected_out, got.strip(), "wrote %r read %r" % + (teststr, got)) + + if e is not None: + got = e.read() + self.assertFalse(got, "unexpected %r on stderr" % got) + + def test_popen2(self): + r, w = popen2.popen2(self.cmd) + self.validate_output(self.teststr, self.expected, r, w) + + def test_popen3(self): + if os.name == 'posix': + r, w, e = popen2.popen3([self.cmd]) + self.validate_output(self.teststr, self.expected, r, w, e) + + r, w, e = popen2.popen3(self.cmd) + self.validate_output(self.teststr, self.expected, r, w, e) + + def test_os_popen2(self): + # same test as test_popen2(), but using the os.popen*() API + w, r = os.popen2(self.cmd) + self.validate_output(self.teststr, self.expected, r, w) + + def test_os_popen3(self): + # same test as test_popen3(), but using the os.popen*() API + if os.name == 'posix': + w, r, e = os.popen3([self.cmd]) + self.validate_output(self.teststr, self.expected, r, w, e) + + w, r, e = os.popen3(self.cmd) + self.validate_output(self.teststr, self.expected, r, w, e) + + +def test_main(): + run_unittest(Popen2Test) + +if __name__ == "__main__": + test_main() From python-checkins at python.org Fri Mar 16 22:15:36 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 16 Mar 2007 22:15:36 +0100 (CET) Subject: [Python-checkins] r54418 - python/trunk/Lib/test/output/test_popen2 Message-ID: <20070316211536.4F2991E4014@bag.python.org> Author: collin.winter Date: Fri Mar 16 22:15:35 2007 New Revision: 54418 Removed: python/trunk/Lib/test/output/test_popen2 Log: Remove test/output/test_popen2 (missed in r54417). Deleted: /python/trunk/Lib/test/output/test_popen2 ============================================================================== --- /python/trunk/Lib/test/output/test_popen2 Fri Mar 16 22:15:35 2007 +++ (empty file) @@ -1,9 +0,0 @@ -test_popen2 -Test popen2 module: -testing popen2... -testing popen3... -All OK -Testing os module: -testing popen2... -testing popen3... -All OK From python-checkins at python.org Fri Mar 16 23:16:09 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 16 Mar 2007 23:16:09 +0100 (CET) Subject: [Python-checkins] r54419 - in python/trunk: Doc/lib/libposixpath.tex Lib/ntpath.py Lib/posixpath.py Lib/test/test_ntpath.py Lib/test/test_posixpath.py Misc/ACKS Misc/NEWS Message-ID: <20070316221609.B59681E4015@bag.python.org> Author: collin.winter Date: Fri Mar 16 23:16:08 2007 New Revision: 54419 Modified: python/trunk/Doc/lib/libposixpath.tex python/trunk/Lib/ntpath.py python/trunk/Lib/posixpath.py python/trunk/Lib/test/test_ntpath.py python/trunk/Lib/test/test_posixpath.py python/trunk/Misc/ACKS python/trunk/Misc/NEWS Log: Patch 1339796: add a relpath() function to os.path. Modified: python/trunk/Doc/lib/libposixpath.tex ============================================================================== --- python/trunk/Doc/lib/libposixpath.tex (original) +++ python/trunk/Doc/lib/libposixpath.tex Fri Mar 16 23:16:08 2007 @@ -189,6 +189,15 @@ \versionadded{2.2} \end{funcdesc} +\begin{funcdesc}{relpath}{path\optional{, start}} +Return a relative filepath to \var{path} either from the current +directory or from an optional \var{start} point. + +\var{start} defaults to \member{os.curdir}. +Availability: Windows, \UNIX. +\versionadded{2.6} +\end{funcdesc} + \begin{funcdesc}{samefile}{path1, path2} Return \code{True} if both pathname arguments refer to the same file or directory (as indicated by device number and i-node number). Modified: python/trunk/Lib/ntpath.py ============================================================================== --- python/trunk/Lib/ntpath.py (original) +++ python/trunk/Lib/ntpath.py Fri Mar 16 23:16:08 2007 @@ -16,7 +16,7 @@ "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"] + "extsep","devnull","realpath","supports_unicode_filenames","relpath"] # strings representing various path-related bits and pieces curdir = '.' @@ -465,3 +465,29 @@ # Win9x family and earlier have no Unicode filename support. supports_unicode_filenames = (hasattr(sys, "getwindowsversion") and sys.getwindowsversion()[3] >= 2) + +def relpath(path, start=curdir): + """Return a relative version of a path""" + + if not path: + raise ValueError("no path specified") + start_list = abspath(start).split(sep) + path_list = abspath(path).split(sep) + if start_list[0].lower() != path_list[0].lower(): + unc_path, rest = splitunc(path) + unc_start, rest = splitunc(start) + if bool(unc_path) ^ bool(unc_start): + raise ValueError("Cannot mix UNC and non-UNC paths (%s and %s)" + % (path, start)) + else: + raise ValueError("path is on drive %s, start on drive %s" + % (path_list[0], start_list[0])) + # Work out how much of the filepath is shared by start and path. + for i in range(min(len(start_list), len(path_list))): + if start_list[i].lower() != path_list[i].lower(): + break + else: + i += 1 + + rel_list = [pardir] * (len(start_list)-i) + path_list[i:] + return join(*rel_list) Modified: python/trunk/Lib/posixpath.py ============================================================================== --- python/trunk/Lib/posixpath.py (original) +++ python/trunk/Lib/posixpath.py Fri Mar 16 23:16:08 2007 @@ -21,7 +21,7 @@ "ismount","walk","expanduser","expandvars","normpath","abspath", "samefile","sameopenfile","samestat", "curdir","pardir","sep","pathsep","defpath","altsep","extsep", - "devnull","realpath","supports_unicode_filenames"] + "devnull","realpath","supports_unicode_filenames","relpath"] # strings representing various path-related bits and pieces curdir = '.' @@ -382,3 +382,18 @@ return path supports_unicode_filenames = False + +def relpath(path, start=curdir): + """Return a relative version of a path""" + + if not path: + raise ValueError("no path specified") + + start_list = abspath(start).split(sep) + path_list = abspath(path).split(sep) + + # Work out how much of the filepath is shared by start and path. + i = len(commonprefix([start_list, path_list])) + + rel_list = [pardir] * (len(start_list)-i) + path_list[i:] + return join(*rel_list) Modified: python/trunk/Lib/test/test_ntpath.py ============================================================================== --- python/trunk/Lib/test/test_ntpath.py (original) +++ python/trunk/Lib/test/test_ntpath.py Fri Mar 16 23:16:08 2007 @@ -157,6 +157,16 @@ else: tester('ntpath.abspath("C:\\")', "C:\\") +currentdir = os.path.split(os.getcwd())[-1] +tester('ntpath.relpath("a")', 'a') +tester('ntpath.relpath(os.path.abspath("a"))', 'a') +tester('ntpath.relpath("a/b")', 'a\\b') +tester('ntpath.relpath("../a/b")', '..\\a\\b') +tester('ntpath.relpath("a", "../b")', '..\\'+currentdir+'\\a') +tester('ntpath.relpath("a/b", "../c")', '..\\'+currentdir+'\\a\\b') +tester('ntpath.relpath("a", "b/c")', '..\\..\\a') +tester('ntpath.relpath("//conky/mountpoint/a", "//conky/mountpoint/b/c")', '..\\..\\a') + if errors: raise TestFailed(str(errors) + " errors.") elif verbose: Modified: python/trunk/Lib/test/test_posixpath.py ============================================================================== --- python/trunk/Lib/test/test_posixpath.py (original) +++ python/trunk/Lib/test/test_posixpath.py Fri Mar 16 23:16:08 2007 @@ -2,7 +2,7 @@ from test import test_support import posixpath, os -from posixpath import realpath, abspath, join, dirname, basename +from posixpath import realpath, abspath, join, dirname, basename, relpath # An absolute path to a temporary filename for testing. We can't rely on TESTFN # being an absolute path, so we need this. @@ -479,6 +479,17 @@ safe_rmdir(ABSTFN + "/k") safe_rmdir(ABSTFN) + def test_relpath(self): + currentdir = os.path.split(os.getcwd())[-1] + self.assertRaises(ValueError, posixpath.relpath, "") + self.assertEqual(posixpath.relpath("a"), "a") + self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a") + self.assertEqual(posixpath.relpath("a/b"), "a/b") + self.assertEqual(posixpath.relpath("../a/b"), "../a/b") + self.assertEqual(posixpath.relpath("a", "../b"), "../"+currentdir+"/a") + self.assertEqual(posixpath.relpath("a/b", "../c"), "../"+currentdir+"/a/b") + self.assertEqual(posixpath.relpath("a", "b/c"), "../../a") + def test_main(): test_support.run_unittest(PosixPathTest) Modified: python/trunk/Misc/ACKS ============================================================================== --- python/trunk/Misc/ACKS (original) +++ python/trunk/Misc/ACKS Fri Mar 16 23:16:08 2007 @@ -36,6 +36,7 @@ Michael J. Barber Chris Barker Quentin Barnes +Richard Barran Cesar Eduardo Barros Des Barry Ulf Bartelt Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 16 23:16:08 2007 @@ -191,6 +191,8 @@ of those present. Also, it tries the Windows default browser before trying Mozilla variants. +- Patch #1339796: add a relpath() function to os.path. + - Patch #1681153: the wave module now closes a file object it opened if initialization failed. From nnorwitz at gmail.com Fri Mar 16 23:48:52 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Fri, 16 Mar 2007 17:48:52 -0500 Subject: [Python-checkins] Python Regression Test Failures all (1) Message-ID: <20070316224852.GA5490@python.psfb.org> test_grammar test_opcodes test_dict test_builtin test_exceptions test_types test_unittest test_doctest test_doctest2 test_MimeWriter test_StringIO test___all__ test___future__ test__locale test_aepack test_aepack skipped -- No module named aepack test_al test_al skipped -- No module named al test_anydbm test_applesingle test_applesingle skipped -- No module named macostools test_array test_ast test_asynchat WARNING: failed to listen on port 54322, trying another WARNING: failed to listen on port 9907, trying another test_atexit test_audioop test_augassign test_base64 test_bastion test_bigaddrspace test_bigmem test_binascii test_binhex test_binop test_bisect test_bool test_bsddb test_bsddb185 test_bsddb185 skipped -- No module named bsddb185 test_bsddb3 test test_bsddb3 failed -- errors occurred; run in verbose mode for details test_bufio test_bz2 test_cProfile test_calendar test_call test_capi test_cd test_cd skipped -- No module named cd test_cfgparser test_cgi test_charmapcodec test_cl test_cl skipped -- No module named cl test_class test_cmath test_cmd_line test_code test_codeccallbacks test_codecencodings_cn test_codecencodings_hk test_codecencodings_jp test_codecencodings_kr test_codecencodings_tw test_codecmaps_cn test_codecmaps_hk test_codecmaps_jp test_codecmaps_kr test_codecmaps_tw test_codecs test_codeop test_coding test_coercion test_collections test_colorsys test_commands /tmp/python-test/local/lib/python2.6/commands.py:36: DeprecationWarning: commands.getstatus() is deprecated warnings.warn("commands.getstatus() is deprecated", DeprecationWarning) test_compare test_compile test_compiler testCompileLibrary still working, be patient... test_complex test_complex_args test_contains test_contextlib test_cookie test_cookielib test_copy test_copy_reg test_cpickle test_crypt test_csv test_ctypes test_datetime test_dbm test_decimal test_decorators test_defaultdict test_deque test_descr test_descrtut test_difflib test_dircache test_dis test_distutils test_dl test_dumbdbm test_dummy_thread test_dummy_threading test_email test_email_codecs test_email_renamed test_enumerate test_eof test_errno test_exception_variations test_extcall test_fcntl test_file test_filecmp test_fileinput test_float test_fnmatch test_fork1 test_format test_fpformat test_frozen test_funcattrs test_functools test_future test_gc test_gdbm test_generators test_genericpath test_genexps test_getargs test_getargs2 test_getopt test_gettext test_gl test_gl skipped -- No module named gl test_glob test_global test_grp test_gzip test_hash test_hashlib test_heapq test_hexoct test_hmac test_hotshot test_htmllib test_htmlparser test_httplib test_imageop test_imaplib test_imgfile test_imgfile skipped -- No module named imgfile test_imp test_import test_importhooks test_index test_inspect test_ioctl test_ioctl skipped -- Unable to open /dev/tty test_isinstance test_iter test_iterlen test_itertools test_largefile test_list test_locale test_logging test_long test_long_future test_longexp test_macfs test_macfs skipped -- No module named macfs test_macostools test_macostools skipped -- No module named macostools test_macpath test_mailbox test_marshal test_math test_md5 test_mhlib test_mimetools test_mimetypes test_minidom test_mmap test_module test_modulefinder test_multibytecodec test_multibytecodec_support test_multifile test_mutants test_netrc test_new test_nis test_normalization test_ntpath test_old_mailbox test_openpty test_operator test_optparse test_os test_parser test_peepholer test_pep247 test_pep263 test_pep277 test_pep277 skipped -- test works only on NT+ test_pep292 test_pep352 test_pickle test_pickletools test_pkg test_pkgimport test_platform test_plistlib test_plistlib skipped -- No module named plistlib test_poll test_popen [7321 refs] [7321 refs] [7321 refs] test_popen2 test_posix test_posixpath test_pow test_pprint test_profile test_profilehooks test_pty test_pwd test_pyclbr test_pyexpat test_queue test_quopri [7696 refs] [7696 refs] test_random test_re test_repr test_resource test_rfc822 test_rgbimg test_richcmp test_robotparser test_runpy test_sax test_scope test_scriptpackages test_scriptpackages skipped -- No module named aetools test_select test_set test_sets test_sgmllib test_sha test_shelve test_shlex test_shutil test_signal test_site test_slice test_socket test_socket_ssl test_socketserver test test_socketserver crashed -- : (2, 'No such file or directory') test_softspace test_sort test_sqlite test_startfile test_startfile skipped -- cannot import name startfile test_str test_strftime test_string test_stringprep test_strop test_strptime test_struct test_structmembers test_structseq test_subprocess [7316 refs] [7317 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7317 refs] [8865 refs] [7532 refs] [7317 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] [7316 refs] . [7316 refs] [7316 refs] this bit of output is from a test of stdout in a different process ... [7316 refs] [7316 refs] [7532 refs] test_sunaudiodev test_sunaudiodev skipped -- No module named sunaudiodev test_sundry test_symtable test_syntax test_sys [7316 refs] [7316 refs] test_tarfile test_tcl test_tcl skipped -- No module named _tkinter test_tempfile [7320 refs] test_textwrap test_thread test_threaded_import test_threadedtempfile test_threading test_threading_local test_threadsignals test_time test_timeout test_tokenize test_trace test_traceback test_transformer test_tuple test_ucn test_unary test_unicode test_unicode_file test_unicode_file skipped -- No Unicode filesystem semantics on this platform. test_unicodedata test_univnewlines test_unpack test_urllib test_urllib2 test_urllib2net test_urllibnet test_urlparse test_userdict test_userlist test_userstring test_uu test_uuid WARNING: uuid.getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. WARNING: uuid._ifconfig_getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. WARNING: uuid._unixdll_getnode is unreliable on many platforms. It is disabled until the code and/or test can be fixed properly. test_wait3 test_wait4 test_warnings test_wave test_weakref test_whichdb test_winreg test_winreg skipped -- No module named _winreg test_winsound test_winsound skipped -- No module named winsound test_with test_wsgiref test_xdrlib test_xml_etree test_xml_etree_c test_xmllib test_xmlrpc test_xpickle test_xrange test_zipfile test_zipfile64 test_zipfile64 skipped -- test requires loads of disk-space bytes and a long time to run test_zipimport test_zlib 297 tests OK. 2 tests failed: test_bsddb3 test_socketserver 21 tests skipped: test_aepack test_al test_applesingle test_bsddb185 test_cd test_cl test_gl test_imgfile test_ioctl test_macfs test_macostools test_pep277 test_plistlib test_scriptpackages test_startfile test_sunaudiodev test_tcl test_unicode_file test_winreg test_winsound test_zipfile64 1 skip unexpected on linux2: test_ioctl [477216 refs] From buildbot at python.org Sat Mar 17 03:58:08 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 17 Mar 2007 02:58:08 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070317025808.3A22A1E400A@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/325 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings failed slave lost sincerely, -The Buildbot From python-checkins at python.org Sat Mar 17 08:02:51 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 17 Mar 2007 08:02:51 +0100 (CET) Subject: [Python-checkins] r54420 - in sandbox/trunk/2to3: HACKING fixes/fix_tuple_params.py pytree.py refactor.py tests/test_pytree.py Message-ID: <20070317070251.3D0A61E4005@bag.python.org> Author: collin.winter Date: Sat Mar 17 08:02:46 2007 New Revision: 54420 Added: sandbox/trunk/2to3/HACKING (contents, props changed) Modified: sandbox/trunk/2to3/fixes/fix_tuple_params.py sandbox/trunk/2to3/pytree.py sandbox/trunk/2to3/refactor.py sandbox/trunk/2to3/tests/test_pytree.py Log: Add a mechanism to explicitly flag a tree as changed. This comes in handy when a fixer works by modifying a node's children or a leaf's value. Added: sandbox/trunk/2to3/HACKING ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/HACKING Sat Mar 17 08:02:46 2007 @@ -0,0 +1,8 @@ +Tips/tricks/hints for writing new fixers: + + * Don't write your own PATTERN from scratch; that's what find_pattern.py + is for. + + * If your fixer works by changing a node's children list or a leaf's + value, be sure to call the node/leaf's changed() method. This to + be sure refactor.py will recognize that the tree has changed. Modified: sandbox/trunk/2to3/fixes/fix_tuple_params.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_tuple_params.py (original) +++ sandbox/trunk/2to3/fixes/fix_tuple_params.py Sat Mar 17 08:02:46 2007 @@ -84,3 +84,4 @@ for i in range(after+1, after+len(new_lines)+1): children[i].set_prefix(indent) suite[0].children = tuple(children) + suite[0].changed() Modified: sandbox/trunk/2to3/pytree.py ============================================================================== --- sandbox/trunk/2to3/pytree.py (original) +++ sandbox/trunk/2to3/pytree.py Sat Mar 17 08:02:46 2007 @@ -29,6 +29,7 @@ type = None # int: token number (< 256) or symbol number (>= 256) parent = None # Parent node pointer, or None children = () # Tuple of subnodes + was_changed = False def __new__(cls, *args, **kwds): """Constructor that prevents Base from being instantiated.""" @@ -111,6 +112,7 @@ else: l_children.append(ch) assert found, (self.children, self, new) + self.changed() self.parent.children = tuple(l_children) if new is not None: new.parent = self.parent @@ -124,6 +126,11 @@ return node = node.children[0] return node.lineno + + def changed(self): + if self.parent: + self.parent.changed() + self.was_changed = True class Node(Base): Modified: sandbox/trunk/2to3/refactor.py ============================================================================== --- sandbox/trunk/2to3/refactor.py (original) +++ sandbox/trunk/2to3/refactor.py Sat Mar 17 08:02:46 2007 @@ -231,6 +231,8 @@ if new is not None and new != node: node.replace(new) changes += 1 + elif tree.was_changed: + changes += 1 for fixer in self.fixers: fixer.finish_tree(tree, filename) return changes Modified: sandbox/trunk/2to3/tests/test_pytree.py ============================================================================== --- sandbox/trunk/2to3/tests/test_pytree.py (original) +++ sandbox/trunk/2to3/tests/test_pytree.py Sat Mar 17 08:02:46 2007 @@ -117,13 +117,45 @@ l3 = pytree.Leaf(100, "bar") n1 = pytree.Node(1000, [l1, l2, l3]) self.assertEqual(n1.children, (l1, l2, l3)) + self.failIf(n1.was_changed) l2new = pytree.Leaf(100, "-") l2.replace(l2new) self.assertEqual(n1.children, (l1, l2new, l3)) + self.failUnless(n1.was_changed) def testConvert(self): # XXX pass + + def testChangedLeaf(self): + l1 = pytree.Leaf(100, "f") + self.failIf(l1.was_changed) + + l1.changed() + self.failUnless(l1.was_changed) + + def testChangedNode(self): + l1 = pytree.Leaf(100, "f") + n1 = pytree.Node(1000, [l1]) + self.failIf(n1.was_changed) + + n1.changed() + self.failUnless(n1.was_changed) + + def testChangedRecursive(self): + l1 = pytree.Leaf(100, "foo") + l2 = pytree.Leaf(100, "+") + l3 = pytree.Leaf(100, "bar") + n1 = pytree.Node(1000, [l1, l2, l3]) + n2 = pytree.Node(1000, [n1]) + self.failIf(l1.was_changed) + self.failIf(n1.was_changed) + self.failIf(n2.was_changed) + + n1.changed() + self.failUnless(n1.was_changed) + self.failUnless(n2.was_changed) + self.failIf(l1.was_changed) class TestPatterns(support.TestCase): From g.brandl at gmx.net Sat Mar 17 12:05:13 2007 From: g.brandl at gmx.net (Georg Brandl) Date: Sat, 17 Mar 2007 12:05:13 +0100 Subject: [Python-checkins] r54415 - python/trunk/Python/ast.c In-Reply-To: <20070316155950.8AE821E400D@bag.python.org> References: <20070316155950.8AE821E400D@bag.python.org> Message-ID: jeremy.hylton schrieb: > Author: jeremy.hylton > Date: Fri Mar 16 16:59:47 2007 > New Revision: 54415 > > Modified: > python/trunk/Python/ast.c > Log: > Clean up formatting of this file. > > The file should now follow PEP 7, except that it uses 4 space indents > (in the style of Py3k). This particular code would be really hard to > read with the regular tab idents. > > Other changes: > - reflow long lines > - change multi-line conditionals to have test at end of line This should be done in the p3yk branch too (perhaps after a merge until before the reformatting), or else merging changes will be a PITA. Georg From thomas at python.org Sat Mar 17 13:45:34 2007 From: thomas at python.org (Thomas Wouters) Date: Sat, 17 Mar 2007 13:45:34 +0100 Subject: [Python-checkins] r54415 - python/trunk/Python/ast.c In-Reply-To: References: <20070316155950.8AE821E400D@bag.python.org> Message-ID: <9e804ac0703170545o6c7cb829l523754a8d1c45bf9@mail.gmail.com> On 3/17/07, Georg Brandl wrote: > > jeremy.hylton schrieb: > > Author: jeremy.hylton > > Date: Fri Mar 16 16:59:47 2007 > > New Revision: 54415 > > > > Modified: > > python/trunk/Python/ast.c > > Log: > > Clean up formatting of this file. > > > > The file should now follow PEP 7, except that it uses 4 space indents > > (in the style of Py3k). This particular code would be really hard to > > read with the regular tab idents. > > > > Other changes: > > - reflow long lines > > - change multi-line conditionals to have test at end of line > > This should be done in the p3yk branch too (perhaps after a merge until > before > the reformatting), or else merging changes will be a PITA. Eh, no, it's much better to do it in the trunk only (and let me merge it.). Merging from py3k to trunk isn't normally done, so doing it in one case would be painful. Any change that applies to both the trunk and py3k should be done in the trunk. (I'm working on setting up a sane way to do backports of py3k features to 2.6, using bazaar or mercurial, but that's a few weeks away still. In the mean time, if you want to do backports of py3k features, please do them in a branch and don't actually commit them to the trunk, thanks :-) -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20070317/93dc05cc/attachment.html From g.brandl at gmx.net Sat Mar 17 16:50:09 2007 From: g.brandl at gmx.net (Georg Brandl) Date: Sat, 17 Mar 2007 16:50:09 +0100 Subject: [Python-checkins] r54415 - python/trunk/Python/ast.c In-Reply-To: <9e804ac0703170545o6c7cb829l523754a8d1c45bf9@mail.gmail.com> References: <20070316155950.8AE821E400D@bag.python.org> <9e804ac0703170545o6c7cb829l523754a8d1c45bf9@mail.gmail.com> Message-ID: Thomas Wouters schrieb: > > > On 3/17/07, *Georg Brandl* > > wrote: > > jeremy.hylton schrieb: > > Author: jeremy.hylton > > Date: Fri Mar 16 16:59:47 2007 > > New Revision: 54415 > > > > Modified: > > python/trunk/Python/ast.c > > Log: > > Clean up formatting of this file. > > > > The file should now follow PEP 7, except that it uses 4 space indents > > (in the style of Py3k). This particular code would be really hard to > > read with the regular tab idents. > > > > Other changes: > > - reflow long lines > > - change multi-line conditionals to have test at end of line > > This should be done in the p3yk branch too (perhaps after a merge > until before > the reformatting), or else merging changes will be a PITA. > > > Eh, no, it's much better to do it in the trunk only (and let me merge > it.). Merging from py3k to trunk isn't normally done, so doing it in one > case would be painful. Any change that applies to both the trunk and > py3k should be done in the trunk. Okay, thanks for clarifying. I thought that since the files are already different in the two branches merging these changes would be more work than selecting the needed revisions to merge. > (I'm working on setting up a sane way to do backports of py3k features to 2.6, > using bazaar or mercurial, but that's a few weeks away still. In the mean time, > if you want to do backports of py3k features, please do them in a branch and > don't actually commit them to the trunk, thanks :-) Ok. Last time I asked, I was told to commit them to the trunk ;) Georg From python-checkins at python.org Sat Mar 17 17:09:00 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 17 Mar 2007 17:09:00 +0100 (CET) Subject: [Python-checkins] r54421 - in python/trunk: Doc/api/concrete.tex Doc/lib/libcmath.tex Lib/test/test_cmath.py Misc/NEWS Objects/complexobject.c Message-ID: <20070317160900.C1A0A1E4005@bag.python.org> Author: georg.brandl Date: Sat Mar 17 17:08:45 2007 New Revision: 54421 Modified: python/trunk/Doc/api/concrete.tex python/trunk/Doc/lib/libcmath.tex python/trunk/Lib/test/test_cmath.py python/trunk/Misc/NEWS python/trunk/Objects/complexobject.c Log: Patch #1675423: PyComplex_AsCComplex() now tries to convert an object to complex using its __complex__() method before falling back to the __float__() method. Therefore, the functions in the cmath module now can operate on objects that define a __complex__() method. (backport) Modified: python/trunk/Doc/api/concrete.tex ============================================================================== --- python/trunk/Doc/api/concrete.tex (original) +++ python/trunk/Doc/api/concrete.tex Sat Mar 17 17:08:45 2007 @@ -443,7 +443,9 @@ \begin{cfuncdesc}{double}{PyFloat_AsDouble}{PyObject *pyfloat} Return a C \ctype{double} representation of the contents of - \var{pyfloat}. + \var{pyfloat}. If \var{pyfloat} is not a Python floating point + object but has a \method{__float__} method, this method will first + be called to convert \var{pyfloat} into a float. \end{cfuncdesc} \begin{cfuncdesc}{double}{PyFloat_AS_DOUBLE}{PyObject *pyfloat} @@ -558,8 +560,11 @@ \end{cfuncdesc} \begin{cfuncdesc}{Py_complex}{PyComplex_AsCComplex}{PyObject *op} - Return the \ctype{Py_complex} value of the complex number - \var{op}. + Return the \ctype{Py_complex} value of the complex number \var{op}. + \versionchanged[If \var{op} is not a Python complex number object + but has a \method{__complex__} method, this method + will first be called to convert \var{op} to a Python + complex number object]{2.6} \end{cfuncdesc} Modified: python/trunk/Doc/lib/libcmath.tex ============================================================================== --- python/trunk/Doc/lib/libcmath.tex (original) +++ python/trunk/Doc/lib/libcmath.tex Sat Mar 17 17:08:45 2007 @@ -5,7 +5,14 @@ \modulesynopsis{Mathematical functions for complex numbers.} This module is always available. It provides access to mathematical -functions for complex numbers. The functions are: +functions for complex numbers. The functions in this module accept +integers, floating-point numbers or complex numbers as arguments. +They will also accept any Python object that has either a +\method{__complex__} or a \method{__float__} method: these methods are +used to convert the object to a complex or floating-point number, respectively, and +the function is then applied to the result of the conversion. + +The functions are: \begin{funcdesc}{acos}{x} Return the arc cosine of \var{x}. Modified: python/trunk/Lib/test/test_cmath.py ============================================================================== --- python/trunk/Lib/test/test_cmath.py (original) +++ python/trunk/Lib/test/test_cmath.py Sat Mar 17 17:08:45 2007 @@ -1,52 +1,196 @@ -#! /usr/bin/env python -""" Simple test script for cmathmodule.c - Roger E. Masse -""" +from test.test_support import run_unittest +import unittest import cmath, math -from test.test_support import verbose, verify, TestFailed -verify(abs(cmath.log(10) - math.log(10)) < 1e-9) -verify(abs(cmath.log(10,2) - math.log(10,2)) < 1e-9) -try: - cmath.log('a') -except TypeError: - pass -else: - raise TestFailed - -try: - cmath.log(10, 'a') -except TypeError: - pass -else: - raise TestFailed - - -testdict = {'acos' : 1.0, - 'acosh' : 1.0, - 'asin' : 1.0, - 'asinh' : 1.0, - 'atan' : 0.2, - 'atanh' : 0.2, - 'cos' : 1.0, - 'cosh' : 1.0, - 'exp' : 1.0, - 'log' : 1.0, - 'log10' : 1.0, - 'sin' : 1.0, - 'sinh' : 1.0, - 'sqrt' : 1.0, - 'tan' : 1.0, - 'tanh' : 1.0} - -for func in testdict.keys(): - f = getattr(cmath, func) - r = f(testdict[func]) - if verbose: - print 'Calling %s(%f) = %f' % (func, testdict[func], abs(r)) - -p = cmath.pi -e = cmath.e -if verbose: - print 'PI = ', abs(p) - print 'E = ', abs(e) +class CMathTests(unittest.TestCase): + # list of all functions in cmath + test_functions = [getattr(cmath, fname) for fname in [ + 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh', + 'cos', 'cosh', 'exp', 'log', 'log10', 'sin', 'sinh', + 'sqrt', 'tan', 'tanh']] + # test first and second arguments independently for 2-argument log + test_functions.append(lambda x : cmath.log(x, 1729. + 0j)) + test_functions.append(lambda x : cmath.log(14.-27j, x)) + + def cAssertAlmostEqual(self, a, b, rel_eps = 1e-10, abs_eps = 1e-100): + """Check that two complex numbers are almost equal.""" + # the two complex numbers are considered almost equal if + # either the relative error is <= rel_eps or the absolute error + # is tiny, <= abs_eps. + if a == b == 0: + return + absolute_error = abs(a-b) + relative_error = absolute_error/max(abs(a), abs(b)) + if relative_error > rel_eps and absolute_error > abs_eps: + self.fail("%s and %s are not almost equal" % (a, b)) + + def test_constants(self): + e_expected = 2.71828182845904523536 + pi_expected = 3.14159265358979323846 + self.assertAlmostEqual(cmath.pi, pi_expected, 9, + "cmath.pi is %s; should be %s" % (cmath.pi, pi_expected)) + self.assertAlmostEqual(cmath.e, e_expected, 9, + "cmath.e is %s; should be %s" % (cmath.e, e_expected)) + + def test_user_object(self): + # Test automatic calling of __complex__ and __float__ by cmath + # functions + + # some random values to use as test values; we avoid values + # for which any of the functions in cmath is undefined + # (i.e. 0., 1., -1., 1j, -1j) or would cause overflow + cx_arg = 4.419414439 + 1.497100113j + flt_arg = -6.131677725 + + # a variety of non-complex numbers, used to check that + # non-complex return values from __complex__ give an error + non_complexes = ["not complex", 1, 5L, 2., None, + object(), NotImplemented] + + # Now we introduce a variety of classes whose instances might + # end up being passed to the cmath functions + + # usual case: new-style class implementing __complex__ + class MyComplex(object): + def __init__(self, value): + self.value = value + def __complex__(self): + return self.value + + # old-style class implementing __complex__ + class MyComplexOS: + def __init__(self, value): + self.value = value + def __complex__(self): + return self.value + + # classes for which __complex__ raises an exception + class SomeException(Exception): + pass + class MyComplexException(object): + def __complex__(self): + raise SomeException + class MyComplexExceptionOS: + def __complex__(self): + raise SomeException + + # some classes not providing __float__ or __complex__ + class NeitherComplexNorFloat(object): + pass + class NeitherComplexNorFloatOS: + pass + class MyInt(object): + def __int__(self): return 2 + def __long__(self): return 2L + def __index__(self): return 2 + class MyIntOS: + def __int__(self): return 2 + def __long__(self): return 2L + def __index__(self): return 2 + + # other possible combinations of __float__ and __complex__ + # that should work + class FloatAndComplex(object): + def __float__(self): + return flt_arg + def __complex__(self): + return cx_arg + class FloatAndComplexOS: + def __float__(self): + return flt_arg + def __complex__(self): + return cx_arg + class JustFloat(object): + def __float__(self): + return flt_arg + class JustFloatOS: + def __float__(self): + return flt_arg + + for f in self.test_functions: + # usual usage + self.cAssertAlmostEqual(f(MyComplex(cx_arg)), f(cx_arg)) + self.cAssertAlmostEqual(f(MyComplexOS(cx_arg)), f(cx_arg)) + # other combinations of __float__ and __complex__ + self.cAssertAlmostEqual(f(FloatAndComplex()), f(cx_arg)) + self.cAssertAlmostEqual(f(FloatAndComplexOS()), f(cx_arg)) + self.cAssertAlmostEqual(f(JustFloat()), f(flt_arg)) + self.cAssertAlmostEqual(f(JustFloatOS()), f(flt_arg)) + # TypeError should be raised for classes not providing + # either __complex__ or __float__, even if they provide + # __int__, __long__ or __index__. An old-style class + # currently raises AttributeError instead of a TypeError; + # this could be considered a bug. + self.assertRaises(TypeError, f, NeitherComplexNorFloat()) + self.assertRaises(TypeError, f, MyInt()) + self.assertRaises(Exception, f, NeitherComplexNorFloatOS()) + self.assertRaises(Exception, f, MyIntOS()) + # non-complex return value from __complex__ -> TypeError + for bad_complex in non_complexes: + self.assertRaises(TypeError, f, MyComplex(bad_complex)) + self.assertRaises(TypeError, f, MyComplexOS(bad_complex)) + # exceptions in __complex__ should be propagated correctly + self.assertRaises(SomeException, f, MyComplexException()) + self.assertRaises(SomeException, f, MyComplexExceptionOS()) + + def test_input_type(self): + # ints and longs should be acceptable inputs to all cmath + # functions, by virtue of providing a __float__ method + for f in self.test_functions: + for arg in [2, 2L, 2.]: + self.cAssertAlmostEqual(f(arg), f(arg.__float__())) + + # but strings should give a TypeError + for f in self.test_functions: + for arg in ["a", "long_string", "0", "1j", ""]: + self.assertRaises(TypeError, f, arg) + + def test_cmath_matches_math(self): + # check that corresponding cmath and math functions are equal + # for floats in the appropriate range + + # test_values in (0, 1) + test_values = [0.01, 0.1, 0.2, 0.5, 0.9, 0.99] + + # test_values for functions defined on [-1., 1.] + unit_interval = test_values + [-x for x in test_values] + \ + [0., 1., -1.] + + # test_values for log, log10, sqrt + positive = test_values + [1.] + [1./x for x in test_values] + nonnegative = [0.] + positive + + # test_values for functions defined on the whole real line + real_line = [0.] + positive + [-x for x in positive] + + test_functions = { + 'acos' : unit_interval, + 'asin' : unit_interval, + 'atan' : real_line, + 'cos' : real_line, + 'cosh' : real_line, + 'exp' : real_line, + 'log' : positive, + 'log10' : positive, + 'sin' : real_line, + 'sinh' : real_line, + 'sqrt' : nonnegative, + 'tan' : real_line, + 'tanh' : real_line} + + for fn, values in test_functions.items(): + float_fn = getattr(math, fn) + complex_fn = getattr(cmath, fn) + for v in values: + self.cAssertAlmostEqual(float_fn(v), complex_fn(v)) + + # test two-argument version of log with various bases + for base in [0.5, 2., 10.]: + for v in positive: + self.cAssertAlmostEqual(cmath.log(v, base), math.log(v, base)) + +def test_main(): + run_unittest(CMathTests) + +if __name__ == "__main__": + test_main() Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sat Mar 17 17:08:45 2007 @@ -12,6 +12,11 @@ Core and builtins ----------------- +- Patch #1675423: PyComplex_AsCComplex() now tries to convert an object + to complex using its __complex__() method before falling back to the + __float__() method. Therefore, the functions in the cmath module now + can operate on objects that define a __complex__() method. + - Patch #1623563: allow __class__ assignment for classes with __slots__. The old and the new class are still required to have the same slot names. Modified: python/trunk/Objects/complexobject.c ============================================================================== --- python/trunk/Objects/complexobject.c (original) +++ python/trunk/Objects/complexobject.c Sat Mar 17 17:08:45 2007 @@ -252,12 +252,59 @@ PyComplex_AsCComplex(PyObject *op) { Py_complex cv; + PyObject *newop = NULL; + static PyObject *complex_str = NULL; + + assert(op); + /* If op is already of type PyComplex_Type, return its value */ if (PyComplex_Check(op)) { return ((PyComplexObject *)op)->cval; } + /* If not, use op's __complex__ method, if it exists */ + + /* return -1 on failure */ + cv.real = -1.; + cv.imag = 0.; + + if (PyInstance_Check(op)) { + /* this can go away in python 3000 */ + if (PyObject_HasAttrString(op, "__complex__")) { + newop = PyObject_CallMethod(op, "__complex__", NULL); + if (!newop) + return cv; + } + /* else try __float__ */ + } else { + PyObject *complexfunc; + if (!complex_str) { + if (!(complex_str = PyString_FromString("__complex__"))) + return cv; + } + complexfunc = _PyType_Lookup(op->ob_type, complex_str); + /* complexfunc is a borrowed reference */ + if (complexfunc) { + newop = PyObject_CallFunctionObjArgs(complexfunc, op, NULL); + if (!newop) + return cv; + } + } + + if (newop) { + if (!PyComplex_Check(newop)) { + PyErr_SetString(PyExc_TypeError, + "__complex__ should return a complex object"); + Py_DECREF(newop); + return cv; + } + cv = ((PyComplexObject *)newop)->cval; + Py_DECREF(newop); + return cv; + } + /* If neither of the above works, interpret op as a float giving the + real part of the result, and fill in the imaginary part as 0. */ else { + /* PyFloat_AsDouble will return -1 on failure */ cv.real = PyFloat_AsDouble(op); - cv.imag = 0.; return cv; } } From python-checkins at python.org Sat Mar 17 23:32:55 2007 From: python-checkins at python.org (gregory.p.smith) Date: Sat, 17 Mar 2007 23:32:55 +0100 (CET) Subject: [Python-checkins] r54422 - python/branches/release25-maint/Misc/NEWS Message-ID: <20070317223255.1FD6D1E4005@bag.python.org> Author: gregory.p.smith Date: Sat Mar 17 23:32:49 2007 New Revision: 54422 Modified: python/branches/release25-maint/Misc/NEWS Log: move note to the correct section Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sat Mar 17 23:32:49 2007 @@ -127,9 +127,6 @@ - Allow exception instances to be directly sliced again. -- fixed a bug with bsddb.DB.stat: the flags and txn keyword arguments - were transposed. - Extension Modules ----------------- @@ -200,6 +197,9 @@ - Make regex engine raise MemoryError if allocating memory fails. +- fixed a bug with bsddb.DB.stat: the flags and txn keyword arguments + were transposed. + - Added support for linking the bsddb module against BerkeleyDB 4.5.x. - Modifying an empty deque during iteration now raises RuntimeError From python-checkins at python.org Sat Mar 17 23:33:38 2007 From: python-checkins at python.org (gregory.p.smith) Date: Sat, 17 Mar 2007 23:33:38 +0100 (CET) Subject: [Python-checkins] r54423 - python/trunk/Misc/NEWS Message-ID: <20070317223338.035391E4005@bag.python.org> Author: gregory.p.smith Date: Sat Mar 17 23:33:35 2007 New Revision: 54423 Modified: python/trunk/Misc/NEWS Log: move note to the correct section Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sat Mar 17 23:33:35 2007 @@ -551,9 +551,6 @@ - Bug #1531862: Do not close standard file descriptors in subprocess. -- fixed a bug with bsddb.DB.stat: the flags and txn keyword arguments - were transposed. - - idle: Honor the "Cancel" action in the save dialog (Debian bug #299092). @@ -644,6 +641,9 @@ been defined. This prevents an interactive Python from waking up 10 times per second. Patch by Richard Boulton. +- fixed a bug with bsddb.DB.stat: the flags and txn keyword arguments + were transposed. + - Added support for linking the bsddb module against BerkeleyDB 4.5.x. - Bug #1633621: if curses.resizeterm() or curses.resize_term() is called, From python-checkins at python.org Sun Mar 18 16:42:35 2007 From: python-checkins at python.org (guido.van.rossum) Date: Sun, 18 Mar 2007 16:42:35 +0100 (CET) Subject: [Python-checkins] r54429 - peps/trunk/pep-0000.txt peps/trunk/pep-3115.txt Message-ID: <20070318154235.7F14F1E400A@bag.python.org> Author: guido.van.rossum Date: Sun Mar 18 16:42:32 2007 New Revision: 54429 Modified: peps/trunk/pep-0000.txt peps/trunk/pep-3115.txt Log: Accept PEP 3115. Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Sun Mar 18 16:42:32 2007 @@ -83,6 +83,7 @@ SA 3111 Simple input built-in in Python 3000 Roberge SA 3112 Bytes literals in Python 3000 Orendorff SA 3113 Removal of Tuple Parameter Unpacking Cannon + SA 3115 Metaclasses in Python 3000 Talin Open PEPs (under consideration) @@ -113,7 +114,6 @@ S 3101 Advanced String Formatting Talin S 3108 Standard Library Reorganization Cannon S 3114 Renaming iterator.next() to iterator.__next__() Yee - S 3115 Metaclasses in Python 3000 Talin S 3116 New I/O Stutzbach, Verdone, GvR @@ -466,7 +466,7 @@ SA 3112 Bytes literals in Python 3000 Orendorff SA 3113 Removal of Tuple Parameter Unpacking Cannon S 3114 Renaming iterator.next() to iterator.__next__() Yee - S 3115 Metaclasses in Python 3000 Talin + SA 3115 Metaclasses in Python 3000 Talin S 3116 New I/O Stutzbach, Verdone, GvR Modified: peps/trunk/pep-3115.txt ============================================================================== --- peps/trunk/pep-3115.txt (original) +++ peps/trunk/pep-3115.txt Sun Mar 18 16:42:32 2007 @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Talin -Status: Draft +Status: Accepted Type: Standards Content-Type: text/plain Created: 07-Mar-2007 From python-checkins at python.org Sun Mar 18 19:20:24 2007 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2007 19:20:24 +0100 (CET) Subject: [Python-checkins] r54431 - sandbox/trunk/2to3/refactor.py Message-ID: <20070318182024.60C201E401B@bag.python.org> Author: georg.brandl Date: Sun Mar 18 19:20:20 2007 New Revision: 54431 Modified: sandbox/trunk/2to3/refactor.py Log: Make refactoring from stdin easier. Modified: sandbox/trunk/2to3/refactor.py ============================================================================== --- sandbox/trunk/2to3/refactor.py (original) +++ sandbox/trunk/2to3/refactor.py Sun Mar 18 19:20:20 2007 @@ -160,7 +160,9 @@ def refactor_args(self, args): """Refactors files and directories from an argument list.""" for arg in args: - if os.path.isdir(arg): + if arg == "-": + self.refactor_stdin() + elif os.path.isdir(arg): self.refactor_dir(arg) else: self.refactor_file(arg) @@ -219,6 +221,33 @@ elif self.options.verbose: self.log_message("No changes in %s", filename) + def refactor_stdin(self): + if self.options.write: + self.log_error("Can't write changes back to stdin") + return + input = sys.stdin.read() + if self.options.doctests_only: + if self.options.verbose: + self.log_message("Refactoring doctests in stdin") + output = self.refactor_docstring(input, "") + if output != input: + self.write_file(output, "", input) + elif self.options.verbose: + self.log_message("No doctest changes in stdin") + else: + if self.options.verbose: + self.log_message("Refactoring stdin") + try: + tree = self.driver.parse_string(input) + except Exception, err: + self.log_error("Can't parse stdin: %s: %s", + err.__class__.__name__, err) + return + if self.refactor_tree(tree, ""): + self.write_file(str(tree), "", input) + elif self.options.verbose: + self.log_message("No changes in stdin") + def refactor_tree(self, tree, filename): """Refactors a parse tree (modifying the tree in place).""" for fixer in self.fixers: From python-checkins at python.org Sun Mar 18 19:28:30 2007 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2007 19:28:30 +0100 (CET) Subject: [Python-checkins] r54432 - python/trunk/Lib/test/outstanding_bugs.py Message-ID: <20070318182830.B08691E400A@bag.python.org> Author: georg.brandl Date: Sun Mar 18 19:28:25 2007 New Revision: 54432 Modified: python/trunk/Lib/test/outstanding_bugs.py Log: Patch #1678339: test case for bug in difflib. Modified: python/trunk/Lib/test/outstanding_bugs.py ============================================================================== --- python/trunk/Lib/test/outstanding_bugs.py (original) +++ python/trunk/Lib/test/outstanding_bugs.py Sun Mar 18 19:28:25 2007 @@ -10,13 +10,44 @@ from test import test_support # -# No test cases for outstanding bugs at the moment. +# One test case for outstanding bugs at the moment: # +class TestDifflibLongestMatch(unittest.TestCase): + # From Patch #1678339: + # The find_longest_match method in the difflib's SequenceMatcher has a bug. + + # The bug is in turn caused by a problem with creating a b2j mapping which + # should contain a list of indices for each of the list elements in b. + # However, when the b2j mapping is being created (this is being done in + # __chain_b method in the SequenceMatcher) the mapping becomes broken. The + # cause of this is that for the frequently used elements the list of indices + # is removed and the element is being enlisted in the populardict mapping. + + # The test case tries to match two strings like: + # abbbbbb.... and ...bbbbbbc + + # The number of b is equal and the find_longest_match should have returned + # the proper amount. However, in case the number of "b"s is large enough, the + # method reports that the length of the longest common substring is 0. It + # simply can't find it. + + # A bug was raised some time ago on this matter. It's ID is 1528074. + + def test_find_longest_match(self): + import difflib + for i in (190, 200, 210): + text1 = "a" + "b"*i + text2 = "b"*i + "c" + m = difflib.SequenceMatcher(None, text1, text2) + (aptr, bptr, l) = m.find_longest_match(0, len(text1), 0, len(text2)) + self.assertEquals(i, l) + self.assertEquals(aptr, 1) + self.assertEquals(bptr, 0) + def test_main(): - #test_support.run_unittest() - pass + test_support.run_unittest(TestDifflibLongestMatch) if __name__ == "__main__": test_main() From python-checkins at python.org Sun Mar 18 21:04:06 2007 From: python-checkins at python.org (georg.brandl) Date: Sun, 18 Mar 2007 21:04:06 +0100 (CET) Subject: [Python-checkins] r54436 - peps/trunk/pep-0000.txt peps/trunk/pep-0358.txt Message-ID: <20070318200406.AF1361E4011@bag.python.org> Author: georg.brandl Date: Sun Mar 18 21:04:00 2007 New Revision: 54436 Modified: peps/trunk/pep-0000.txt peps/trunk/pep-0358.txt Log: PEP 358 is accepted. Modified: peps/trunk/pep-0000.txt ============================================================================== --- peps/trunk/pep-0000.txt (original) +++ peps/trunk/pep-0000.txt Sun Mar 18 21:04:00 2007 @@ -77,6 +77,7 @@ Accepted PEPs (accepted; may not be implemented yet) + SA 358 The "bytes" Object Schemenauer, GvR SA 3106 Revamping dict.keys(), .values() and .items() GvR SA 3109 Raising Exceptions in Python 3000 Winter SA 3110 Catching Exceptions in Python 3000 Winter @@ -107,7 +108,6 @@ I 350 Codetags Elliott S 354 Enumerations in Python Finney S 355 Path - Object oriented filesystem paths Lindqvist - S 358 The "bytes" Object Schemenauer, GvR S 362 Function Signature Object Cannon, Seo S 364 Transitioning to the Py3K Standard Library Warsaw S 754 IEEE 754 Floating Point Special Values Warnes @@ -438,7 +438,7 @@ S 355 Path - Object oriented filesystem paths Lindqvist IF 356 Python 2.5 Release Schedule Norwitz, et al SF 357 Allowing Any Object to be Used for Slicing Oliphant - S 358 The "bytes" Object Schemenauer, GvR + SA 358 The "bytes" Object Schemenauer, GvR SW 359 The "make" Statement Bethard I 360 Externally Maintained Packages Cannon I 361 Python 2.6 Release Schedule Norwitz, et al Modified: peps/trunk/pep-0358.txt ============================================================================== --- peps/trunk/pep-0358.txt (original) +++ peps/trunk/pep-0358.txt Sun Mar 18 21:04:00 2007 @@ -3,7 +3,7 @@ Version: $Revision$ Last-Modified: $Date$ Author: Neil Schemenauer , Guido van Rossum -Status: Draft +Status: Accepted Type: Standards Track Content-Type: text/plain Created: 15-Feb-2006 From python-checkins at python.org Mon Mar 19 19:52:14 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 19:52:14 +0100 (CET) Subject: [Python-checkins] r54439 - in python/trunk: Doc/lib/libtempfile.tex Lib/tempfile.py Lib/test/test_tempfile.py Misc/ACKS Misc/NEWS Message-ID: <20070319185214.D7DB91E4003@bag.python.org> Author: collin.winter Date: Mon Mar 19 19:52:08 2007 New Revision: 54439 Modified: python/trunk/Doc/lib/libtempfile.tex python/trunk/Lib/tempfile.py python/trunk/Lib/test/test_tempfile.py python/trunk/Misc/ACKS python/trunk/Misc/NEWS Log: Patch #1630118: add a SpooledTemporaryFile class to tempfile. Modified: python/trunk/Doc/lib/libtempfile.tex ============================================================================== --- python/trunk/Doc/lib/libtempfile.tex (original) +++ python/trunk/Doc/lib/libtempfile.tex Mon Mar 19 19:52:08 2007 @@ -67,6 +67,23 @@ \versionadded[The \var{delete} parameter]{2.6} \end{funcdesc} +\begin{funcdesc}{SpooledTemporaryFile}{\optional{max\_size=\code{0}, + \optional{mode=\code{'w+b'}\optional{, + bufsize=\code{-1}\optional{, + suffix\optional{, prefix\optional{, + dir}}}}}}} +This function operates exactly as \function{TemporaryFile()} does, +except that data is spooled in memory until the file size exceeds +\var{max_size}, or until the file's \function{fileno()} method is +called, at which point the contents are written to disk and operation +proceeds as with \function{TemporaryFile()}. + +The resulting file has one additional method, \function{rollover()}, +which causes the file to roll over to an on-disk file regardless of +its size. +\versionadded{2.6} +\end{funcdesc} + \begin{funcdesc}{mkstemp}{\optional{suffix\optional{, prefix\optional{, dir\optional{, text}}}}} Creates a temporary file in the most secure manner possible. There Modified: python/trunk/Lib/tempfile.py ============================================================================== --- python/trunk/Lib/tempfile.py (original) +++ python/trunk/Lib/tempfile.py Mon Mar 19 19:52:08 2007 @@ -19,6 +19,7 @@ __all__ = [ "NamedTemporaryFile", "TemporaryFile", # high level safe interfaces + "SpooledTemporaryFile", "mkstemp", "mkdtemp", # low level safe interfaces "mktemp", # deprecated unsafe interface "TMP_MAX", "gettempprefix", # constants @@ -37,6 +38,11 @@ import Carbon.Folders as _Folders try: + from cStringIO import StringIO as _StringIO +except: + from StringIO import StringIO as _StringIO + +try: import fcntl as _fcntl except ImportError: def _set_cloexec(fd): @@ -473,3 +479,111 @@ except: _os.close(fd) raise + +class SpooledTemporaryFile: + """Temporary file wrapper, specialized to switch from + StringIO to a real file when it exceeds a certain size or + when a fileno is needed. + """ + _rolled = False + + def __init__(self, max_size=0, mode='w+b', bufsize=-1, + suffix="", prefix=template, dir=None): + self._file = _StringIO() + self._max_size = max_size + self._rolled = False + self._TemporaryFileArgs = (mode, bufsize, suffix, prefix, dir) + + def _check(self, file): + if self._rolled: return + max_size = self._max_size + if max_size and file.tell() > max_size: + self.rollover() + + def rollover(self): + if self._rolled: return + file = self._file + newfile = self._file = TemporaryFile(*self._TemporaryFileArgs) + del self._TemporaryFileArgs + + newfile.write(file.getvalue()) + newfile.seek(file.tell(), 0) + + self._rolled = True + + # file protocol + def __iter__(self): + return self._file.__iter__() + + def close(self): + self._file.close() + + @property + def closed(self): + return self._file.closed + + @property + def encoding(self): + return self._file.encoding + + def fileno(self): + self.rollover() + return self._file.fileno() + + def flush(self): + self._file.flush() + + def isatty(self): + return self._file.isatty() + + @property + def mode(self): + return self._file.mode + + @property + def name(self): + return self._file.name + + @property + def newlines(self): + return self._file.newlines + + def next(self): + return self._file.next + + def read(self, *args): + return self._file.read(*args) + + def readline(self, *args): + return self._file.readline(*args) + + def readlines(self, *args): + return self._file.readlines(*args) + + def seek(self, *args): + self._file.seek(*args) + + @property + def softspace(self): + return self._file.softspace + + def tell(self): + return self._file.tell() + + def truncate(self): + self._file.truncate() + + def write(self, s): + file = self._file + rv = file.write(s) + self._check(file) + return rv + + def writelines(self, iterable): + file = self._file + rv = file.writelines(iterable) + self._check(file) + return rv + + def xreadlines(self, *args): + return self._file.xreadlines(*args) Modified: python/trunk/Lib/test/test_tempfile.py ============================================================================== --- python/trunk/Lib/test/test_tempfile.py (original) +++ python/trunk/Lib/test/test_tempfile.py Mon Mar 19 19:52:08 2007 @@ -81,7 +81,8 @@ "gettempprefix" : 1, "gettempdir" : 1, "tempdir" : 1, - "template" : 1 + "template" : 1, + "SpooledTemporaryFile" : 1 } unexp = [] @@ -632,6 +633,107 @@ test_classes.append(test_NamedTemporaryFile) +class test_SpooledTemporaryFile(TC): + """Test SpooledTemporaryFile().""" + + def do_create(self, max_size=0, dir=None, pre="", suf=""): + if dir is None: + dir = tempfile.gettempdir() + try: + file = tempfile.SpooledTemporaryFile(max_size=max_size, dir=dir, prefix=pre, suffix=suf) + except: + self.failOnException("SpooledTemporaryFile") + + return file + + + def test_basic(self): + # SpooledTemporaryFile can create files + f = self.do_create() + self.failIf(f._rolled) + f = self.do_create(max_size=100, pre="a", suf=".txt") + self.failIf(f._rolled) + + def test_del_on_close(self): + # A SpooledTemporaryFile is deleted when closed + dir = tempfile.mkdtemp() + try: + f = tempfile.SpooledTemporaryFile(max_size=10, dir=dir) + self.failIf(f._rolled) + f.write('blat ' * 5) + self.failUnless(f._rolled) + filename = f.name + f.close() + self.failIf(os.path.exists(filename), + "SpooledTemporaryFile %s exists after close" % filename) + finally: + os.rmdir(dir) + + def test_rewrite_small(self): + # A SpooledTemporaryFile can be written to multiple within the max_size + f = self.do_create(max_size=30) + self.failIf(f._rolled) + for i in range(5): + f.seek(0, 0) + f.write('x' * 20) + self.failIf(f._rolled) + + def test_write_sequential(self): + # A SpooledTemporaryFile should hold exactly max_size bytes, and roll + # over afterward + f = self.do_create(max_size=30) + self.failIf(f._rolled) + f.write('x' * 20) + self.failIf(f._rolled) + f.write('x' * 10) + self.failIf(f._rolled) + f.write('x') + self.failUnless(f._rolled) + + def test_sparse(self): + # A SpooledTemporaryFile that is written late in the file will extend + # when that occurs + f = self.do_create(max_size=30) + self.failIf(f._rolled) + f.seek(100, 0) + self.failIf(f._rolled) + f.write('x') + self.failUnless(f._rolled) + + def test_fileno(self): + # A SpooledTemporaryFile should roll over to a real file on fileno() + f = self.do_create(max_size=30) + self.failIf(f._rolled) + self.failUnless(f.fileno() > 0) + self.failUnless(f._rolled) + + def test_multiple_close(self): + # A SpooledTemporaryFile can be closed many times without error + f = tempfile.SpooledTemporaryFile() + f.write('abc\n') + f.close() + try: + f.close() + f.close() + except: + self.failOnException("close") + + def test_bound_methods(self): + # It should be OK to steal a bound method from a SpooledTemporaryFile + # and use it independently; when the file rolls over, those bound + # methods should continue to function + f = self.do_create(max_size=30) + read = f.read + write = f.write + seek = f.seek + + write("a" * 35) + write("b" * 35) + seek(0, 0) + self.failUnless(read(70) == 'a'*35 + 'b'*35) + +test_classes.append(test_SpooledTemporaryFile) + class test_TemporaryFile(TC): """Test TemporaryFile().""" Modified: python/trunk/Misc/ACKS ============================================================================== --- python/trunk/Misc/ACKS (original) +++ python/trunk/Misc/ACKS Mon Mar 19 19:52:08 2007 @@ -442,6 +442,7 @@ Damien Miller Roman Milner Dom Mitchell +Dustin J. Mitchell Doug Moen Paul Moore The Dragon De Monsyne Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Mon Mar 19 19:52:08 2007 @@ -187,6 +187,8 @@ Library ------- +- Patch #1630118: add a SpooledTemporaryFile class to tempfile.py. + - Patch #1273829: os.walk() now has a "followlinks" parameter. If set to True (which is not the default), it visits symlinks pointing to directories. From python-checkins at python.org Mon Mar 19 20:02:52 2007 From: python-checkins at python.org (georg.brandl) Date: Mon, 19 Mar 2007 20:02:52 +0100 (CET) Subject: [Python-checkins] r54441 - python/trunk/Demo/parser/unparse.py Message-ID: <20070319190252.149E31E4003@bag.python.org> Author: georg.brandl Date: Mon Mar 19 20:02:48 2007 New Revision: 54441 Modified: python/trunk/Demo/parser/unparse.py Log: Patch #1683328: fixes and enhancements for "unparse" demo. Modified: python/trunk/Demo/parser/unparse.py ============================================================================== --- python/trunk/Demo/parser/unparse.py (original) +++ python/trunk/Demo/parser/unparse.py Mon Mar 19 20:02:48 2007 @@ -4,6 +4,19 @@ import cStringIO import os +def interleave(inter, f, seq): + """Call f on each item in seq, calling inter() in between. + """ + seq = iter(seq) + try: + f(seq.next()) + except StopIteration: + pass + else: + for x in seq: + inter() + f(x) + class Unparser: """Methods in this class recursively traverse an AST and output source code for the abstract syntax; original formatting @@ -63,26 +76,13 @@ def _Import(self, t): self.fill("import ") - first = True - for a in t.names: - if first: - first = False - else: - self.write(", ") - self.write(a.name) - if a.asname: - self.write(" as "+a.asname) + interleave(lambda: self.write(", "), self.dispatch, t.names) def _ImportFrom(self, t): self.fill("from ") self.write(t.module) self.write(" import ") - for i, a in enumerate(t.names): - if i == 0: - self.write(", ") - self.write(a.name) - if a.asname: - self.write(" as "+a.asname) + interleave(lambda: self.write(", "), self.dispatch, t.names) # XXX(jpe) what is level for? def _Assign(self, t): @@ -99,8 +99,9 @@ self.dispatch(t.value) def _Return(self, t): - self.fill("return ") + self.fill("return") if t.value: + self.write(" ") self.dispatch(t.value) def _Pass(self, t): @@ -148,18 +149,16 @@ self.write(",") def _Global(self, t): - self.fill("global") - for i, n in enumerate(t.names): - if i != 0: - self.write(",") - self.write(" " + n) + self.fill("global ") + interleave(lambda: self.write(", "), self.write, t.names) def _Yield(self, t): - self.fill("yield") + self.write("(") + self.write("yield") if t.value: - self.write(" (") + self.write(" ") self.dispatch(t.value) - self.write(")") + self.write(")") def _Raise(self, t): self.fill('raise ') @@ -198,8 +197,9 @@ self.leave() def _excepthandler(self, t): - self.fill("except ") + self.fill("except") if t.type: + self.write(" ") self.dispatch(t.type) if t.name: self.write(", ") @@ -299,9 +299,7 @@ def _List(self, t): self.write("[") - for e in t.elts: - self.dispatch(e) - self.write(", ") + interleave(lambda: self.write(", "), self.dispatch, t.elts) self.write("]") def _ListComp(self, t): @@ -328,30 +326,31 @@ self.dispatch(if_clause) def _IfExp(self, t): + self.write("(") self.dispatch(t.body) self.write(" if ") self.dispatch(t.test) - if t.orelse: - self.write(" else ") - self.dispatch(t.orelse) + self.write(" else ") + self.dispatch(t.orelse) + self.write(")") def _Dict(self, t): self.write("{") - for k,v in zip(t.keys, t.values): + def writem((k, v)): self.dispatch(k) - self.write(" : ") + self.write(": ") self.dispatch(v) - self.write(", ") + interleave(lambda: self.write(", "), writem, zip(t.keys, t.values)) self.write("}") def _Tuple(self, t): - if not t.elts: - self.write("()") - return self.write("(") - for e in t.elts: - self.dispatch(e) - self.write(", ") + if len(t.elts) == 1: + (elt,) = t.elts + self.dispatch(elt) + self.write(",") + else: + interleave(lambda: self.write(", "), self.dispatch, t.elts) self.write(")") unop = {"Invert":"~", "Not": "not", "UAdd":"+", "USub":"-"} @@ -367,7 +366,7 @@ def _BinOp(self, t): self.write("(") self.dispatch(t.left) - self.write(")" + self.binop[t.op.__class__.__name__] + "(") + self.write(" " + self.binop[t.op.__class__.__name__] + " ") self.dispatch(t.right) self.write(")") @@ -377,17 +376,15 @@ self.write("(") self.dispatch(t.left) for o, e in zip(t.ops, t.comparators): - self.write(") " +self.cmpops[o.__class__.__name__] + " (") + self.write(" " + self.cmpops[o.__class__.__name__] + " ") self.dispatch(e) self.write(")") boolops = {_ast.And: 'and', _ast.Or: 'or'} def _BoolOp(self, t): self.write("(") - self.dispatch(t.values[0]) - for v in t.values[1:]: - self.write(" %s " % self.boolops[t.op.__class__]) - self.dispatch(v) + s = " %s " % self.boolops[t.op.__class__] + interleave(lambda: self.write(s), self.dispatch, t.values) self.write(")") def _Attribute(self,t): @@ -443,10 +440,7 @@ self.dispatch(t.step) def _ExtSlice(self, t): - for i, d in enumerate(t.dims): - if i != 0: - self.write(': ') - self.dispatch(d) + interleave(lambda: self.write(', '), self.dispatch, t.dims) # others def _arguments(self, t): @@ -482,9 +476,14 @@ self.write(": ") self.dispatch(t.body) + def _alias(self, t): + self.write(t.name) + if t.asname: + self.write(" as "+t.asname) + def roundtrip(filename, output=sys.stdout): source = open(filename).read() - tree = compile(source, filename, "exec", 0x400) + tree = compile(source, filename, "exec", _ast.PyCF_ONLY_AST) Unparser(tree, output) From python-checkins at python.org Mon Mar 19 21:24:37 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 21:24:37 +0100 (CET) Subject: [Python-checkins] r54442 - in sandbox/trunk/2to3: README fixes/fix_next.py tests/test_fixers.py Message-ID: <20070319202437.B171E1E4006@bag.python.org> Author: collin.winter Date: Mon Mar 19 21:24:35 2007 New Revision: 54442 Added: sandbox/trunk/2to3/fixes/fix_next.py (contents, props changed) Modified: sandbox/trunk/2to3/README sandbox/trunk/2to3/tests/test_fixers.py Log: Add a beta version of the next() fixer for PEP 3114. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Mon Mar 19 21:24:35 2007 @@ -50,6 +50,8 @@ * **fix_ne** - convert the "<>" operator to "!=". +* **fix_next** - fixer for it.next() -> next(it), per PEP 3114. + * **fix_print** - convert "print" statements to print() function calls. * **fix_raise** - convert "raise" statements to Python 3 syntax. Added: sandbox/trunk/2to3/fixes/fix_next.py ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/fixes/fix_next.py Mon Mar 19 21:24:35 2007 @@ -0,0 +1,183 @@ +"""Fixer for it.next() -> next(it), per PEP 3114.""" +# Author: Collin Winter + +# Things that currently aren't covered: +# - listcomp "next" names aren't warned +# - "with" statement targets aren't checked + +# Local imports +import pytree +from pgen2 import token +from fixes import basefix +from fixes.macros import Name, Call + +bind_warning = "Calls to builtin next() possibly shadowed by global binding" + +class DelayedStrNode(object): + def __init__(self, type, base): + self.parent = None + self.shadowed_next = False + self.base = base + self.type = type + self.value = "" + + def __str__(self): + b = "".join([str(n) for n in self.base]) + if self.shadowed_next: + return "%s.__next__()" % b + else: + return "next(%s)" % b + +class FixNext(basefix.BaseFix): + PATTERN = """ + power< base=any+ trailer< '.' 'next' > trailer< '(' ')' > > + | + power< head=any+ trailer< '.' attr='next' > not trailer< '(' ')' > > + | + classdef< 'class' any+ ':' + suite< any* + funcdef< 'def' + name='next' + parameters< '(' NAME ')' > any+ > + any* > > + | + global=global_stmt< 'global' any* 'next' any* > + | + mod=file_input< any+ > + """ + + def start_tree(self, tree, filename): + super(FixNext, self).start_tree(tree, filename) + self.shadowed_next = False + self.delayed = [] + + def transform(self, node): + syms = self.syms + results = self.match(node) + assert results + + base = results.get("base") + attr = results.get("attr") + name = results.get("name") + mod = results.get("mod") + + if base: + n = DelayedStrNode(syms.power, base) + node.replace(n) + self.delayed.append(n) + elif name: + n = Name("__next__") + n.set_prefix(name.get_prefix()) + name.replace(n) + elif attr: + # We don't do this transformation if we're assignment to "x.next". + # Unfortunately, it doesn't seem possible to do this in PATTERN, + # so it's being done here. + if is_assign_target(syms, node): + head = results["head"] + if "".join([str(n) for n in head]).strip() == '__builtin__': + self.warning(node, bind_warning) + return + attr.replace(Name("__next__")) + elif "global" in results: + self.warning(node, bind_warning) + self.shadowed_next = True + elif mod: + n = find_binding(syms, 'next', mod) + if n: + self.warning(n, bind_warning) + self.shadowed_next = True + + def finish_tree(self, tree, filename): + super(FixNext, self).finish_tree(tree, filename) + if self.shadowed_next: + for node in self.delayed: + node.shadowed_next = True + + +### The following functions are to find module-level bindings + +def find_binding(syms, name, file_input): + for child in file_input.children: + if child.type == syms.for_stmt: + if find(name, child.children[1]): + return child + elif child.type == syms.funcdef and child.children[1].value == name: + return child + elif is_import_binding(syms, child, name): + return child + elif child.type == syms.simple_stmt: + if child.children[0].type == syms.expr_stmt: + n = find(name, child.children[0].children[0]) + if n: + return n + +def find(name, node): + nodes = [node] + while nodes: + node = nodes.pop() + if isinstance(node, pytree.Node): + nodes.extend(node.children) + elif node.type == token.NAME and node.value == name: + return node + return None + +def is_import_binding(syms, node, name): + if node.type == syms.simple_stmt: + i = node.children[0] + if i.type == syms.import_name: + imp = i.children[1] + if imp.type == syms.dotted_as_names: + for child in imp.children: + if child.type == syms.dotted_as_name: + if child.children[2].value == name: + return i + elif imp.type == syms.dotted_as_name: + last = imp.children[-1] + if last.type == token.NAME and last.value == name: + return i + elif i.type == syms.import_from: + n = i.children[3] + if n.type == syms.import_as_names: + if find(name, n): + return i + elif n.type == token.NAME and n.value == name: + return i + return None + + +### The following functions help test if node is part of an assignment +### target. + +try: + any +except NameError: + def any(l): + for o in l: + if o: + return True + return False + +def is_assign_target(syms, node): + assign = find_assign(syms, node) + if assign is None: + return False + + for child in assign.children: + if child.type == token.EQUAL: + return False + elif is_subtree(child, node): + return True + return False + +def find_assign(syms, node): + if node.type == syms.expr_stmt: + return node + if node.type == syms.simple_stmt or node.parent is None: + return None + return find_assign(syms, node.parent) + +def is_subtree(root, node): + if root == node: + return True + return any([is_subtree(c, node) for c in root.children]) Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Mon Mar 19 21:24:35 2007 @@ -1228,6 +1228,365 @@ (d, e, f) = xxx_todo_changeme1 x = 5""" self.check(b, a) + +class Test_next(FixerTestCase): + fixer = "next" + + def test_1(self): + b = """it.next()""" + a = """next(it)""" + self.check(b, a) + + def test_2(self): + b = """a.b.c.d.next()""" + a = """next(a.b.c.d)""" + self.check(b, a) + + def test_3(self): + b = """(a + b).next()""" + a = """next((a + b))""" + self.check(b, a) + + def test_4(self): + b = """a().next()""" + a = """next(a())""" + self.check(b, a) + + def test_5(self): + b = """a().next() + b""" + a = """next(a()) + b""" + self.check(b, a) + + def test_method_1(self): + b = """ + class A: + def next(self): + pass + """ + a = """ + class A: + def __next__(self): + pass + """ + self.check(b, a) + + def test_method_2(self): + b = """ + class A(object): + def next(self): + pass + """ + a = """ + class A(object): + def __next__(self): + pass + """ + self.check(b, a) + + def test_method_3(self): + b = """ + class A: + def next(x): + pass + """ + a = """ + class A: + def __next__(x): + pass + """ + self.check(b, a) + + def test_method_4(self): + b = """ + class A: + def __init__(self, foo): + self.foo = foo + + def next(self): + pass + + def __iter__(self): + return self + """ + a = """ + class A: + def __init__(self, foo): + self.foo = foo + + def __next__(self): + pass + + def __iter__(self): + return self + """ + self.check(b, a) + + def test_method_unchanged(self): + s = """ + class A: + def next(self, a, b): + pass + """ + self.check(s, s) + + def test_shadowing_assign_simple(self): + s = """ + next = foo + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_assign_tuple_1(self): + s = """ + (next, a) = foo + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_assign_tuple_2(self): + s = """ + (a, (b, (next, c)), a) = foo + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_assign_list_1(self): + s = """ + [next, a] = foo + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_assign_list_2(self): + s = """ + [a, [b, [next, c]], a] = foo + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_builtin_assign(self): + s = """ + def foo(): + __builtin__.next = foo + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_builtin_assign_in_tuple(self): + s = """ + def foo(): + (a, __builtin__.next) = foo + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_assign_to_next(self): + s = """ + def foo(): + A.next = foo + + class A: + def next(self, a, b): + pass + """ + self.check(s, s) + + def test_assign_to_next_in_tuple(self): + s = """ + def foo(): + (a, A.next) = foo + + class A: + def next(self, a, b): + pass + """ + self.check(s, s) + + def test_shadowing_import_1(self): + s = """ + import foo.bar as next + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_import_2(self): + s = """ + import bar, bar.foo as next + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_import_3(self): + s = """ + import bar, bar.foo as next, baz + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_import_from_1(self): + s = """ + from x import next + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_import_from_2(self): + s = """ + from x.a import next + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_import_from_3(self): + s = """ + from x import a, next, b + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_import_from_4(self): + s = """ + from x.a import a, next, b + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_funcdef_1(self): + s = """ + def next(a): + pass + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_funcdef_2(self): + b = """ + def next(a): + pass + + class A: + def next(self): + pass + + it.next() + """ + a = """ + def next(a): + pass + + class A: + def __next__(self): + pass + + it.__next__() + """ + self.warns(b, a, "Calls to builtin next() possibly shadowed") + + def test_shadowing_global_1(self): + s = """ + def f(): + global next + next = 5 + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_global_2(self): + s = """ + def f(): + global a, next, b + next = 5 + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_for_simple(self): + s = """ + for next in it(): + pass + + b = 5 + c = 6 + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_for_tuple_1(self): + s = """ + for next, b in it(): + pass + + b = 5 + c = 6 + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_shadowing_for_tuple_2(self): + s = """ + for a, (next, c), b in it(): + pass + + b = 5 + c = 6 + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + + def test_noncall_access_1(self): + b = """gnext = g.next""" + a = """gnext = g.__next__""" + self.check(b, a) + + def test_noncall_access_2(self): + b = """f(g.next + 5)""" + a = """f(g.__next__ + 5)""" + self.check(b, a) + + def test_noncall_access_3(self): + b = """f(g().next + 5)""" + a = """f(g().__next__ + 5)""" + self.check(b, a) if __name__ == "__main__": From python-checkins at python.org Mon Mar 19 21:30:10 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 21:30:10 +0100 (CET) Subject: [Python-checkins] r54443 - sandbox/trunk/2to3/README Message-ID: <20070319203010.D24371E4003@bag.python.org> Author: collin.winter Date: Mon Mar 19 21:30:07 2007 New Revision: 54443 Modified: sandbox/trunk/2to3/README Log: Add PEP citations for certain fixers. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Mon Mar 19 21:30:07 2007 @@ -36,13 +36,13 @@ * **fix_dict** - fix up dict.keys(), .values(), .items() and their iterator versions. -* **fix_except** - adjust "except" statements to Python 3 syntax. +* **fix_except** - adjust "except" statements to Python 3 syntax (PEP 3110). * **fix_exec** - convert "exec" statements to exec() function calls. * **fix_has_key** - "d.has_key(x)" -> "x in d". -* **fix_input** - "input()" -> "eval(input())". +* **fix_input** - "input()" -> "eval(input())" (PEP 3111). * **fix_intern** - "intern(x)" -> "sys.intern(x)". @@ -50,23 +50,23 @@ * **fix_ne** - convert the "<>" operator to "!=". -* **fix_next** - fixer for it.next() -> next(it), per PEP 3114. +* **fix_next** - fixer for it.next() -> next(it) (PEP 3114). * **fix_print** - convert "print" statements to print() function calls. -* **fix_raise** - convert "raise" statements to Python 3 syntax. +* **fix_raise** - convert "raise" statements to Python 3 syntax (PEP 3109). -* **fix_raw_input** - "raw_input()" -> "input()". +* **fix_raw_input** - "raw_input()" -> "input()" (PEP 3111). * **fix_repr** - swap backticks for repr() calls. * **fix_sysexcinfo** - warn on usage of sys.value, sys.type and sys.traceback. -* **fix_throw** - fix generator.throw() calls to be 3.0-compliant. +* **fix_throw** - fix generator.throw() calls to be 3.0-compliant (PEP 3109). * **fix_tuple_params** - remove tuple parameters from function and method - declarations. + declarations (PEP 3113). * **fix_xrange** - "xrange()" -> "range()". From python-checkins at python.org Mon Mar 19 22:25:31 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 22:25:31 +0100 (CET) Subject: [Python-checkins] r54444 - sandbox/trunk/2to3/pytree.py Message-ID: <20070319212531.505861E4006@bag.python.org> Author: collin.winter Date: Mon Mar 19 22:25:27 2007 New Revision: 54444 Modified: sandbox/trunk/2to3/pytree.py Log: Explicitly stringify a Leaf's value. Modified: sandbox/trunk/2to3/pytree.py ============================================================================== --- sandbox/trunk/2to3/pytree.py (original) +++ sandbox/trunk/2to3/pytree.py Mon Mar 19 22:25:27 2007 @@ -230,7 +230,7 @@ This reproduces the input source exactly. """ - return self.prefix + self.value + return self.prefix + str(self.value) def _eq(self, other): """Compares two nodes for equality.""" From python-checkins at python.org Mon Mar 19 22:33:01 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 22:33:01 +0100 (CET) Subject: [Python-checkins] r54445 - sandbox/trunk/2to3/tests/test_pytree.py Message-ID: <20070319213301.C21381E4003@bag.python.org> Author: collin.winter Date: Mon Mar 19 22:33:00 2007 New Revision: 54445 Modified: sandbox/trunk/2to3/tests/test_pytree.py Log: Add a test for Leaf.value stringification. Modified: sandbox/trunk/2to3/tests/test_pytree.py ============================================================================== --- sandbox/trunk/2to3/tests/test_pytree.py (original) +++ sandbox/trunk/2to3/tests/test_pytree.py Mon Mar 19 22:33:00 2007 @@ -49,6 +49,13 @@ self.assertEqual(str(l1), "foo") l2 = pytree.Leaf(100, "foo", context=(" ", (10, 1))) self.assertEqual(str(l2), " foo") + + def testLeafStrNumericValue(self): + # Make sure that the Leaf's value is stringified. Failing to + # do this can cause a TypeError in certain situations. + l1 = pytree.Leaf(2, 5) + l1.set_prefix("foo_") + self.assertEqual(str(l1), "foo_5") def testLeafEq(self): l1 = pytree.Leaf(100, "foo") From python-checkins at python.org Mon Mar 19 22:43:55 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 22:43:55 +0100 (CET) Subject: [Python-checkins] r54446 - sandbox/trunk/2to3/fixes/macros.py Message-ID: <20070319214355.554F11E4003@bag.python.org> Author: collin.winter Date: Mon Mar 19 22:43:48 2007 New Revision: 54446 Modified: sandbox/trunk/2to3/fixes/macros.py Log: Add Number and Subscript macros. Modified: sandbox/trunk/2to3/fixes/macros.py ============================================================================== --- sandbox/trunk/2to3/fixes/macros.py (original) +++ sandbox/trunk/2to3/fixes/macros.py Mon Mar 19 22:43:48 2007 @@ -54,6 +54,15 @@ """A newline literal""" return Leaf(token.NEWLINE, "\n") +def Number(n): + return Leaf(token.NUMBER, n) + +def Subscript(index_node): + """A numeric or string subscript""" + return Node(syms.trailer, [Leaf(token.LBRACE, '['), + index_node, + Leaf(token.RBRACE, ']')]) + def is_tuple(node): """Does the node represent a tuple literal?""" From python-checkins at python.org Mon Mar 19 22:46:06 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 22:46:06 +0100 (CET) Subject: [Python-checkins] r54447 - in sandbox/trunk/2to3: README fixes/fix_tuple_params.py tests/test_fixers.py Message-ID: <20070319214606.45D161E4003@bag.python.org> Author: collin.winter Date: Mon Mar 19 22:46:01 2007 New Revision: 54447 Modified: sandbox/trunk/2to3/README sandbox/trunk/2to3/fixes/fix_tuple_params.py sandbox/trunk/2to3/tests/test_fixers.py Log: Add lambda support to fix_tuple_params. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Mon Mar 19 22:46:01 2007 @@ -65,8 +65,8 @@ * **fix_throw** - fix generator.throw() calls to be 3.0-compliant (PEP 3109). -* **fix_tuple_params** - remove tuple parameters from function and method - declarations (PEP 3113). +* **fix_tuple_params** - remove tuple parameters from function, method and + lambda declarations (PEP 3113). * **fix_xrange** - "xrange()" -> "range()". Modified: sandbox/trunk/2to3/fixes/fix_tuple_params.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_tuple_params.py (original) +++ sandbox/trunk/2to3/fixes/fix_tuple_params.py Mon Mar 19 22:46:01 2007 @@ -8,28 +8,38 @@ def func(x, d): ((a, b), c) = x ... + +It will also support lambdas: + + lambda (x, y): x + y -> lambda: t: t[0] + t[1] """ # Author: Collin Winter # Local imports import pytree from pgen2 import token +from pygram import python_symbols as syms from fixes import basefix -from fixes.macros import Assign, Name, Newline +from fixes.macros import Assign, Name, Newline, Number, Subscript def is_docstring(stmt): return isinstance(stmt, pytree.Node) and \ stmt.children[0].type == token.STRING class FixTupleParams(basefix.BaseFix): - PATTERN = """funcdef< 'def' any parameters< '(' args=any ')' > - ['->' any] ':' suite=any+ >""" + PATTERN = """ + funcdef< 'def' any parameters< '(' args=any ')' > + ['->' any] ':' suite=any+ > + | + lambda=lambdef< 'lambda' args=vfpdef< any+ > ':' body=any >""" def transform(self, node): - syms = self.syms results = self.match(node) assert results + if "lambda" in results: + return self.transform_lambda(node) + new_lines = [] suite = results["suite"] args = results["args"] @@ -85,3 +95,54 @@ children[i].set_prefix(indent) suite[0].children = tuple(children) suite[0].changed() + + def transform_lambda(self, node): + results = self.match(node) + assert results + args = results["args"] + body = results["body"] + + params = find_params(args) + to_index = map_to_index(params) + tup_name = self.new_name(tuple_name(params)) + + new_param = Name(tup_name) + new_param.set_prefix(args.get_prefix()) + args.replace(new_param.clone()) + for n in body.post_order(): + if n.type == token.NAME and n.value in to_index: + subscripts = [c.clone() for c in to_index[n.value]] + new = pytree.Node(syms.power, + [new_param.clone()] + subscripts) + new.set_prefix(n.get_prefix()) + n.replace(new) + + +### Helper functions for transform_lambda() + +def find_params(node): + if node.type == syms.vfpdef: + return find_params(node.children[1]) + elif node.type == token.NAME: + return node.value + return [find_params(c) for c in node.children if c.type != token.COMMA] + +def map_to_index(param_list, prefix=[], d=None): + if d is None: + d = {} + for i, obj in enumerate(param_list): + trailer = [Subscript(Number(i))] + if isinstance(obj, list): + map_to_index(obj, trailer, d=d) + else: + d[obj] = prefix + trailer + return d + +def tuple_name(param_list): + l = [] + for obj in param_list: + if isinstance(obj, list): + l.append(tuple_name(obj)) + else: + l.append(obj) + return "_".join(l) Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Mon Mar 19 22:46:01 2007 @@ -1229,6 +1229,35 @@ x = 5""" self.check(b, a) + def test_lambda_no_change(self): + s = """lambda x: x + 5""" + self.check(s, s) + + def test_lambda_simple(self): + b = """lambda (x, y): x + f(y)""" + a = """lambda x_y: x_y[0] + f(x_y[1])""" + self.check(b, a) + + def test_lambda_simple_multi_use(self): + b = """lambda (x, y): x + x + f(x) + x""" + a = """lambda x_y: x_y[0] + x_y[0] + f(x_y[0]) + x_y[0]""" + self.check(b, a) + + def test_lambda_simple_reverse(self): + b = """lambda (x, y): y + x""" + a = """lambda x_y: x_y[1] + x_y[0]""" + self.check(b, a) + + def test_lambda_nested(self): + b = """lambda (x, (y, z)): x + y + z""" + a = """lambda x_y_z: x_y_z[0] + x_y_z[1][0] + x_y_z[1][1]""" + self.check(b, a) + + def test_lambda_nested_multi_use(self): + b = """lambda (x, (y, z)): x + y + f(y)""" + a = """lambda x_y_z: x_y_z[0] + x_y_z[1][0] + f(x_y_z[1][0])""" + self.check(b, a) + class Test_next(FixerTestCase): fixer = "next" From python-checkins at python.org Mon Mar 19 22:48:21 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 22:48:21 +0100 (CET) Subject: [Python-checkins] r54448 - sandbox/trunk/2to3/fixes/fix_next.py Message-ID: <20070319214821.50DAF1E4003@bag.python.org> Author: collin.winter Date: Mon Mar 19 22:48:17 2007 New Revision: 54448 Modified: sandbox/trunk/2to3/fixes/fix_next.py Log: Eliminate syms passing. Modified: sandbox/trunk/2to3/fixes/fix_next.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_next.py (original) +++ sandbox/trunk/2to3/fixes/fix_next.py Mon Mar 19 22:48:17 2007 @@ -8,6 +8,7 @@ # Local imports import pytree from pgen2 import token +from pygram import python_symbols as syms from fixes import basefix from fixes.macros import Name, Call @@ -52,7 +53,6 @@ self.delayed = [] def transform(self, node): - syms = self.syms results = self.match(node) assert results @@ -73,7 +73,7 @@ # We don't do this transformation if we're assignment to "x.next". # Unfortunately, it doesn't seem possible to do this in PATTERN, # so it's being done here. - if is_assign_target(syms, node): + if is_assign_target(node): head = results["head"] if "".join([str(n) for n in head]).strip() == '__builtin__': self.warning(node, bind_warning) @@ -83,7 +83,7 @@ self.warning(node, bind_warning) self.shadowed_next = True elif mod: - n = find_binding(syms, 'next', mod) + n = find_binding('next', mod) if n: self.warning(n, bind_warning) self.shadowed_next = True @@ -97,14 +97,14 @@ ### The following functions are to find module-level bindings -def find_binding(syms, name, file_input): +def find_binding(name, file_input): for child in file_input.children: if child.type == syms.for_stmt: if find(name, child.children[1]): return child elif child.type == syms.funcdef and child.children[1].value == name: return child - elif is_import_binding(syms, child, name): + elif is_import_binding(child, name): return child elif child.type == syms.simple_stmt: if child.children[0].type == syms.expr_stmt: @@ -122,7 +122,7 @@ return node return None -def is_import_binding(syms, node, name): +def is_import_binding(node, name): if node.type == syms.simple_stmt: i = node.children[0] if i.type == syms.import_name: @@ -158,8 +158,8 @@ return True return False -def is_assign_target(syms, node): - assign = find_assign(syms, node) +def is_assign_target(node): + assign = find_assign(node) if assign is None: return False @@ -170,12 +170,12 @@ return True return False -def find_assign(syms, node): +def find_assign(node): if node.type == syms.expr_stmt: return node if node.type == syms.simple_stmt or node.parent is None: return None - return find_assign(syms, node.parent) + return find_assign(node.parent) def is_subtree(root, node): if root == node: From python-checkins at python.org Mon Mar 19 23:04:26 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 23:04:26 +0100 (CET) Subject: [Python-checkins] r54449 - sandbox/trunk/2to3/tests/test_fixers.py Message-ID: <20070319220426.397051E4011@bag.python.org> Author: collin.winter Date: Mon Mar 19 23:04:24 2007 New Revision: 54449 Modified: sandbox/trunk/2to3/tests/test_fixers.py Log: Additional assignment tests for fix_next. Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Mon Mar 19 23:04:24 2007 @@ -1430,6 +1430,17 @@ """ self.warns(s, s, "Calls to builtin next() possibly shadowed") + def test_builtin_assign_in_list(self): + s = """ + def foo(): + [a, __builtin__.next] = foo + + class A: + def next(self, a, b): + pass + """ + self.warns(s, s, "Calls to builtin next() possibly shadowed") + def test_assign_to_next(self): s = """ def foo(): @@ -1451,6 +1462,17 @@ pass """ self.check(s, s) + + def test_assign_to_next_in_list(self): + s = """ + def foo(): + [a, A.next] = foo + + class A: + def next(self, a, b): + pass + """ + self.check(s, s) def test_shadowing_import_1(self): s = """ From python-checkins at python.org Mon Mar 19 23:13:09 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 19 Mar 2007 23:13:09 +0100 (CET) Subject: [Python-checkins] r54450 - sandbox/trunk/2to3/tests/test_fixers.py Message-ID: <20070319221309.220FB1E4003@bag.python.org> Author: collin.winter Date: Mon Mar 19 23:13:08 2007 New Revision: 54450 Modified: sandbox/trunk/2to3/tests/test_fixers.py Log: Replace the fixer's logging handlers, don't add to them. Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Mon Mar 19 23:13:08 2007 @@ -30,7 +30,7 @@ def start_tree(self, tree, filename): self.fixer.start_tree(tree, filename) - self.fixer.logger.addHandler(self.handler) + self.fixer.logger.handlers[:] = [self.handler] class Options: def __init__(self, **kwargs): From python-checkins at python.org Tue Mar 20 04:32:29 2007 From: python-checkins at python.org (collin.winter) Date: Tue, 20 Mar 2007 04:32:29 +0100 (CET) Subject: [Python-checkins] r54453 - sandbox/trunk/2to3/tests/support.py Message-ID: <20070320033229.196BE1E4003@bag.python.org> Author: collin.winter Date: Tue Mar 20 04:32:25 2007 New Revision: 54453 Modified: sandbox/trunk/2to3/tests/support.py Log: Reimplement tests.support.reformat(). Modified: sandbox/trunk/2to3/tests/support.py ============================================================================== --- sandbox/trunk/2to3/tests/support.py (original) +++ sandbox/trunk/2to3/tests/support.py Tue Mar 20 04:32:25 2007 @@ -5,6 +5,7 @@ import sys import os.path import re +from textwrap import dedent TestCase = unittest.TestCase @@ -24,12 +25,5 @@ parent_dir = os.path.split(sys.path[0])[0] sys.path = [parent_dir] + sys.path - -skip_whitespace = re.compile(r"""\S""") def reformat(string): - indent = re.search(skip_whitespace, string).start() - if indent == 0: - code = string - else: - code = "\n".join([line[indent-1:] for line in string.split("\n")[1:]]) - return code + "\n\n" + return dedent(string) + "\n\n" From python-checkins at python.org Tue Mar 20 04:59:47 2007 From: python-checkins at python.org (collin.winter) Date: Tue, 20 Mar 2007 04:59:47 +0100 (CET) Subject: [Python-checkins] r54454 - sandbox/trunk/2to3/tests/benchmark.py Message-ID: <20070320035947.992551E400B@bag.python.org> Author: collin.winter Date: Tue Mar 20 04:59:45 2007 New Revision: 54454 Added: sandbox/trunk/2to3/tests/benchmark.py (contents, props changed) Log: Add a benchmarking script for the pattern-matching system. Added: sandbox/trunk/2to3/tests/benchmark.py ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/tests/benchmark.py Tue Mar 20 04:59:45 2007 @@ -0,0 +1,58 @@ +#!/usr/bin/env python2.5 +""" +This is a benchmarking script to test the speed of 2to3's pattern matching +system. It's equivalent to "refactor.py -f all" for every Python module +in sys.modules, but without engaging the actual transformations. +""" + +__author__ = "Collin Winter " + +# Python imports +import os.path +import sys +from time import time + +# Test imports +from support import adjust_path +adjust_path() + +# Local imports +import refactor + +### Mock code for refactor.py and the fixers +############################################################################### +class Options: + def __init__(self, **kwargs): + for k, v in kwargs.items(): + setattr(self, k, v) + + self.verbose = False + +def dummy_transform(*args, **kwargs): + pass + +### Collect list of modules to match against +############################################################################### +files = [] +for mod in sys.modules.values(): + if mod is None or not hasattr(mod, '__file__'): + continue + f = mod.__file__ + if f.endswith('.pyc'): + f = f[:-1] + if f.endswith('.py'): + files.append(f) + +### Set up refactor and run the benchmark +############################################################################### +options = Options(fix=["all"], print_function=False, doctests_only=False) +refactor = refactor.RefactoringTool(options) +for fixer in refactor.fixers: + # We don't want them to actually fix the tree, just match against it. + fixer.transform = dummy_transform + +t = time() +for f in files: + print "Matching", f + refactor.refactor_file(f) +print "%d seconds to match %d files" % (time() - t, len(sys.modules)) From python-checkins at python.org Tue Mar 20 05:25:02 2007 From: python-checkins at python.org (collin.winter) Date: Tue, 20 Mar 2007 05:25:02 +0100 (CET) Subject: [Python-checkins] r54455 - in sandbox/trunk/2to3: README fixes/fix_nonzero.py tests/test_fixers.py Message-ID: <20070320042502.BD9DA1E4006@bag.python.org> Author: collin.winter Date: Tue Mar 20 05:24:56 2007 New Revision: 54455 Added: sandbox/trunk/2to3/fixes/fix_nonzero.py (contents, props changed) Modified: sandbox/trunk/2to3/README sandbox/trunk/2to3/tests/test_fixers.py Log: Add a fixer for __nonzero__ methods. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Tue Mar 20 05:24:56 2007 @@ -52,6 +52,8 @@ * **fix_next** - fixer for it.next() -> next(it) (PEP 3114). +* **fix_nonzero** - convert __nonzero__() methods to __bool__() methods. + * **fix_print** - convert "print" statements to print() function calls. * **fix_raise** - convert "raise" statements to Python 3 syntax (PEP 3109). Added: sandbox/trunk/2to3/fixes/fix_nonzero.py ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/fixes/fix_nonzero.py Tue Mar 20 05:24:56 2007 @@ -0,0 +1,27 @@ +"""Fixer for __nonzero__ -> __bool__ methods.""" +# Author: Collin Winter + +# Local imports +import pytree +from pgen2 import token +from pygram import python_symbols as syms +from fixes import basefix +from fixes.macros import Name + +class FixNonzero(basefix.BaseFix): + PATTERN = """ + classdef< 'class' any+ ':' + suite< any* + funcdef< 'def' name='__nonzero__' + parameters< '(' NAME ')' > any+ > + any* > > + """ + + def transform(self, node): + results = self.match(node) + assert results + + name = results["name"] + new = Name("__bool__") + new.set_prefix(name.get_prefix()) + name.replace(new) Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Tue Mar 20 05:24:56 2007 @@ -1638,6 +1638,58 @@ b = """f(g().next + 5)""" a = """f(g().__next__ + 5)""" self.check(b, a) + +class Test_nonzero(FixerTestCase): + fixer = "nonzero" + + def test_1(self): + b = """ + class A: + def __nonzero__(self): + pass + """ + a = """ + class A: + def __bool__(self): + pass + """ + self.check(b, a) + + def test_2(self): + b = """ + class A(object): + def __nonzero__(self): + pass + """ + a = """ + class A(object): + def __bool__(self): + pass + """ + self.check(b, a) + + def test_unchanged_1(self): + s = """ + class A(object): + def __bool__(self): + pass + """ + self.check(s, s) + + def test_unchanged_2(self): + s = """ + class A(object): + def __nonzero__(self, a): + pass + """ + self.check(s, s) + + def test_unchanged_func(self): + s = """ + def __nonzero__(self): + pass + """ + self.check(s, s) if __name__ == "__main__": From python-checkins at python.org Tue Mar 20 06:07:31 2007 From: python-checkins at python.org (neal.norwitz) Date: Tue, 20 Mar 2007 06:07:31 +0100 (CET) Subject: [Python-checkins] r54456 - python/trunk/Doc/lib/libplatform.tex Message-ID: <20070320050731.241721E4006@bag.python.org> Author: neal.norwitz Date: Tue Mar 20 06:07:28 2007 New Revision: 54456 Modified: python/trunk/Doc/lib/libplatform.tex Log: Add some doc that was left out from some change to platform.py Modified: python/trunk/Doc/lib/libplatform.tex ============================================================================== --- python/trunk/Doc/lib/libplatform.tex (original) +++ python/trunk/Doc/lib/libplatform.tex Tue Mar 20 06:07:28 2007 @@ -80,6 +80,22 @@ Returns a string identifying the compiler used for compiling Python. \end{funcdesc} +\begin{funcdesc}{python_branch}{} + Returns a string identifying the Python implementation SCM branch. + \versionadded{2.6} +\end{funcdesc} + +\begin{funcdesc}{python_implementation}{} + Returns a string identifying the Python implementation. + Possible return values are: 'CPython', 'IronPython', 'Jython' + \versionadded{2.6} +\end{funcdesc} + +\begin{funcdesc}{python_revision}{} + Returns a string identifying the Python implementation SCM revision. + \versionadded{2.6} +\end{funcdesc} + \begin{funcdesc}{python_version}{} Returns the Python version as string \code{'major.minor.patchlevel'} @@ -205,6 +221,7 @@ which defaults to the args given as parameters. \end{funcdesc} +% Document linux_distribution()? \begin{funcdesc}{libc_ver}{executable=sys.executable, lib='', version='', chunksize=2048} From python-checkins at python.org Tue Mar 20 06:08:24 2007 From: python-checkins at python.org (neal.norwitz) Date: Tue, 20 Mar 2007 06:08:24 +0100 (CET) Subject: [Python-checkins] r54457 - python/trunk/Doc/whatsnew/whatsnew26.tex Message-ID: <20070320050824.7EFC71E4006@bag.python.org> Author: neal.norwitz Date: Tue Mar 20 06:08:23 2007 New Revision: 54457 Modified: python/trunk/Doc/whatsnew/whatsnew26.tex Log: Add a comment about 3k migration Modified: python/trunk/Doc/whatsnew/whatsnew26.tex ============================================================================== --- python/trunk/Doc/whatsnew/whatsnew26.tex (original) +++ python/trunk/Doc/whatsnew/whatsnew26.tex Tue Mar 20 06:08:23 2007 @@ -29,6 +29,9 @@ % Large, PEP-level features and changes should be described here. +% Should there be a new section here for 3k migration? +% Or perhaps a more general section describing module changes/deprecation? +% sets module deprecated %====================================================================== \section{Other Language Changes} From python-checkins at python.org Tue Mar 20 06:21:24 2007 From: python-checkins at python.org (neal.norwitz) Date: Tue, 20 Mar 2007 06:21:24 +0100 (CET) Subject: [Python-checkins] r54458 - python/trunk/Lib/test/test_commands.py Message-ID: <20070320052124.10ED21E4006@bag.python.org> Author: neal.norwitz Date: Tue Mar 20 06:21:21 2007 New Revision: 54458 Modified: python/trunk/Lib/test/test_commands.py Log: Get rid of deprecation warning when testing commands.getstatus() Modified: python/trunk/Lib/test/test_commands.py ============================================================================== --- python/trunk/Lib/test/test_commands.py (original) +++ python/trunk/Lib/test/test_commands.py Tue Mar 20 06:21:21 2007 @@ -4,6 +4,10 @@ ''' import unittest import os, tempfile, re +import warnings + +warnings.filterwarnings('ignore', r".*commands.getstatus.. is deprecated", + DeprecationWarning) from test.test_support import TestSkipped, run_unittest, reap_children from commands import * From python-checkins at python.org Tue Mar 20 06:23:14 2007 From: python-checkins at python.org (neal.norwitz) Date: Tue, 20 Mar 2007 06:23:14 +0100 (CET) Subject: [Python-checkins] r54459 - in python/trunk: Doc/lib/libos.tex Lib/os.py Lib/test/test_os.py Misc/NEWS Message-ID: <20070320052314.53A811E4006@bag.python.org> Author: neal.norwitz Date: Tue Mar 20 06:23:09 2007 New Revision: 54459 Modified: python/trunk/Doc/lib/libos.tex python/trunk/Lib/os.py python/trunk/Lib/test/test_os.py python/trunk/Misc/NEWS Log: Try backing out 54407 to see if it corrects the problems on the Windows buildbots. This rev was backported, so we will need to keep both branches in sync, pending the outcome of the test after this checkin. Modified: python/trunk/Doc/lib/libos.tex ============================================================================== --- python/trunk/Doc/lib/libos.tex (original) +++ python/trunk/Doc/lib/libos.tex Tue Mar 20 06:23:09 2007 @@ -1233,8 +1233,7 @@ \end{funcdesc} \begin{funcdesc}{walk}{top\optional{, topdown\code{=True} - \optional{, onerror\code{=None}\optional{, - followlinks\code{=False}}}}} + \optional{, onerror\code{=None}}}} \index{directory!walking} \index{directory!traversal} \function{walk()} generates the file names in a directory tree, by @@ -1274,25 +1273,24 @@ to abort the walk. Note that the filename is available as the \code{filename} attribute of the exception object. -By default, \function{walk()} will not walk down into symbolic links that -resolve to directories. Set \var{followlinks} to True to visit directories -pointed to by symlinks, on systems that support them. - \versionadded[The \var{followlinks} parameter]{2.6} \begin{notice} -Be aware that setting \var{followlinks} to true can lead to infinite recursion -if a link points to a parent directory of itself. \function{walk()} does not -keep track of the directories it visited already. -\end{notice} - -\begin{notice} If you pass a relative pathname, don't change the current working directory between resumptions of \function{walk()}. \function{walk()} never changes the current directory, and assumes that its caller doesn't either. \end{notice} +\begin{notice} +On systems that support symbolic links, links to subdirectories appear +in \var{dirnames} lists, but \function{walk()} will not visit them +(infinite loops are hard to avoid when following symbolic links). +To visit linked directories, you can identify them with +\code{os.path.islink(\var{path})}, and invoke \code{walk(\var{path})} +on each directly. +\end{notice} + This example displays the number of bytes taken by non-directory files in each directory under the starting directory, except that it doesn't look under any CVS subdirectory: Modified: python/trunk/Lib/os.py ============================================================================== --- python/trunk/Lib/os.py (original) +++ python/trunk/Lib/os.py Tue Mar 20 06:23:09 2007 @@ -221,7 +221,7 @@ __all__.extend(["makedirs", "removedirs", "renames"]) -def walk(top, topdown=True, onerror=None, followlinks=False): +def walk(top, topdown=True, onerror=None): """Directory tree generator. For each directory in the directory tree rooted at top (including top @@ -257,10 +257,6 @@ to abort the walk. Note that the filename is available as the filename attribute of the exception object. - By default, os.walk does not follow symbolic links to subdirectories on - systems that support them. In order to get this functionality, set the - optional argument 'followlinks' to true. - Caution: if you pass a relative pathname for top, don't change the current working directory between resumptions of walk. walk never changes the current directory, and assumes that the client doesn't @@ -304,8 +300,8 @@ yield top, dirs, nondirs for name in dirs: path = join(top, name) - if followlinks or not islink(path): - for x in walk(path, topdown, onerror, followlinks): + if not islink(path): + for x in walk(path, topdown, onerror): yield x if not topdown: yield top, dirs, nondirs Modified: python/trunk/Lib/test/test_os.py ============================================================================== --- python/trunk/Lib/test/test_os.py (original) +++ python/trunk/Lib/test/test_os.py Tue Mar 20 06:23:09 2007 @@ -277,34 +277,22 @@ # SUB1/ a file kid and a directory kid # tmp2 # SUB11/ no kids - # SUB2/ a file kid and a dirsymlink kid + # SUB2/ just a file kid # tmp3 - # link/ a symlink to TESTFN.2 - # TESTFN.2/ - # tmp4 a lone file sub1_path = join(test_support.TESTFN, "SUB1") sub11_path = join(sub1_path, "SUB11") sub2_path = join(test_support.TESTFN, "SUB2") tmp1_path = join(test_support.TESTFN, "tmp1") tmp2_path = join(sub1_path, "tmp2") tmp3_path = join(sub2_path, "tmp3") - link_path = join(sub2_path, "link") - t2_path = join(test_support.TESTFN + ".2") - tmp4_path = join(test_support.TESTFN + ".2", "tmp4") # Create stuff. os.makedirs(sub11_path) os.makedirs(sub2_path) - os.makedirs(t2_path) - for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: + for path in tmp1_path, tmp2_path, tmp3_path: f = file(path, "w") f.write("I'm " + path + " and proud of it. Blame test_os.\n") f.close() - if hasattr(os, "symlink"): - os.symlink(os.path.join("..", "..", t2_path), link_path) - else: - # it must be a directory because the test expects that - os.mkdir(link_path) # Walk top-down. all = list(os.walk(test_support.TESTFN)) @@ -317,7 +305,7 @@ self.assertEqual(all[0], (test_support.TESTFN, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[1 + flipped], (sub1_path, ["SUB11"], ["tmp2"])) self.assertEqual(all[2 + flipped], (sub11_path, [], [])) - self.assertEqual(all[3 - 2 * flipped], (sub2_path, ["link"], ["tmp3"])) + self.assertEqual(all[3 - 2 * flipped], (sub2_path, [], ["tmp3"])) # Prune the search. all = [] @@ -329,7 +317,7 @@ dirs.remove('SUB1') self.assertEqual(len(all), 2) self.assertEqual(all[0], (test_support.TESTFN, ["SUB2"], ["tmp1"])) - self.assertEqual(all[1], (sub2_path, ["link"], ["tmp3"])) + self.assertEqual(all[1], (sub2_path, [], ["tmp3"])) # Walk bottom-up. all = list(os.walk(test_support.TESTFN, topdown=False)) @@ -342,17 +330,7 @@ self.assertEqual(all[3], (test_support.TESTFN, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[flipped], (sub11_path, [], [])) self.assertEqual(all[flipped + 1], (sub1_path, ["SUB11"], ["tmp2"])) - self.assertEqual(all[2 - 2 * flipped], (sub2_path, ["link"], ["tmp3"])) - - # Walk, following symlinks. - for root, dirs, files in os.walk(test_support.TESTFN, followlinks=True): - if root == link_path: - self.assertEqual(dirs, []) - self.assertEqual(files, ["tmp4"]) - break - else: - self.fail("Didn't follow symlink with followlinks=True") - + self.assertEqual(all[2 - 2 * flipped], (sub2_path, [], ["tmp3"])) # Tear everything down. This is a decent use for bottom-up on # Windows, which doesn't have a recursive delete command. The @@ -362,14 +340,8 @@ for name in files: os.remove(join(root, name)) for name in dirs: - dirname = join(root, name) - if not os.path.islink(dirname): - os.rmdir(dirname) - else: - os.remove(dirname) + os.rmdir(join(root, name)) os.rmdir(test_support.TESTFN) - os.unlink(tmp4_path) - os.rmdir(t2_path) class MakedirTests (unittest.TestCase): def setUp(self): Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Tue Mar 20 06:23:09 2007 @@ -189,10 +189,6 @@ - Patch #1630118: add a SpooledTemporaryFile class to tempfile.py. -- Patch #1273829: os.walk() now has a "followlinks" parameter. If set to - True (which is not the default), it visits symlinks pointing to - directories. - - Bug #1681228: the webbrowser module now correctly uses the default GNOME or KDE browser, depending on whether there is a session of one of those present. Also, it tries the Windows default browser before From buildbot at python.org Tue Mar 20 06:49:52 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 20 Mar 2007 05:49:52 +0000 Subject: [Python-checkins] buildbot warnings in x86 W2k trunk Message-ID: <20070320054952.B3EED1E4006@bag.python.org> The Buildbot has detected a new failure of x86 W2k trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520W2k%2520trunk/builds/136 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl,neal.norwitz Build had warnings: warnings test Excerpt from the test logfile: 3 tests failed: test_mailbox test_posixpath test_urllib ====================================================================== ERROR: test_add (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_and_close (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_from_string (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_mbox_or_mmdf_message (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_clear (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_close (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_contains (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_delitem (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_discard (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_dump_message (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_flush (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_file (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_message (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_string (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_getitem (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_has_key (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_items (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iter (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iteritems (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iterkeys (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_itervalues (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_keys (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_len (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_conflict (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_unlock (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_open_close_open (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_pop (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_popitem (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_relock (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_remove (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_set_item (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_update (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_values (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_and_close (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_from_string (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_mbox_or_mmdf_message (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_clear (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_close (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_contains (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_delitem (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_discard (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_dump_message (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_flush (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_file (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_message (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_string (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_getitem (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_has_key (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_items (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iter (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iteritems (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iterkeys (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_itervalues (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_keys (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_len (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_conflict (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_unlock (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_open_close_open (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_pop (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_popitem (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_relock (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_remove (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_set_item (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_update (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_values (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_clear (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_close (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_contains (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_delitem (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_discard (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_dump_message (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_flush (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_file (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_message (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_string (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_getitem (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_has_key (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_items (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iter (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iteritems (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iterkeys (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_itervalues (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_keys (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_labels (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_len (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_unlock (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_pop (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_popitem (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_remove (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_set_item (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_update (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_values (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== FAIL: test_relpath (test.test_posixpath.PosixPathTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_posixpath.py", line 486, in test_relpath self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a") AssertionError: 'C:\\trentm\\data\\buildbot\\python-slave\\trunk.mick-windows\\build\\PCbuild\\a' != 'a' ====================================================================== ERROR: test_copy (test.test_urllib.urlretrieve_FileTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_urllib.py", line 200, in test_copy test_support.TESTFN), second_temp) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\urllib.py", line 89, in urlretrieve return _urlopener.retrieve(url, filename, reporthook, data) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\urllib.py", line 225, in retrieve tfp = open(filename, 'wb') IOError: [Errno 13] Permission denied: '@test.2' ====================================================================== ERROR: test_reporthook (test.test_urllib.urlretrieve_FileTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_urllib.py", line 224, in test_reporthook second_temp, hooktester) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\urllib.py", line 89, in urlretrieve return _urlopener.retrieve(url, filename, reporthook, data) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\urllib.py", line 225, in retrieve tfp = open(filename, 'wb') IOError: [Errno 13] Permission denied: '@test.2' sincerely, -The Buildbot From buildbot at python.org Tue Mar 20 07:11:37 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 20 Mar 2007 06:11:37 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070320061137.D00121E4009@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/330 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl,neal.norwitz Build had warnings: warnings test Excerpt from the test logfile: 3 tests failed: test_mailbox test_posixpath test_urllib ====================================================================== ERROR: test_add (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_and_close (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_from_string (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_mbox_or_mmdf_message (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_clear (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_close (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_contains (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_delitem (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_discard (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_dump_message (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_flush (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_file (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_message (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_string (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_getitem (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_has_key (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_items (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iter (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iteritems (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iterkeys (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_itervalues (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_keys (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_len (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_conflict (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_unlock (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_open_close_open (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_pop (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_popitem (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_relock (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_remove (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_set_item (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_update (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_values (test.test_mailbox.TestMbox) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_and_close (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_from_string (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add_mbox_or_mmdf_message (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_clear (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_close (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_contains (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_delitem (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_discard (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_dump_message (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_flush (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_file (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_message (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_string (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_getitem (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_has_key (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_items (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iter (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iteritems (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iterkeys (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_itervalues (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_keys (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_len (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_conflict (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_unlock (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_open_close_open (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_pop (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_popitem (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_relock (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_remove (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_set_item (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_update (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_values (test.test_mailbox.TestMMDF) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 696, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_add (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_clear (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_close (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_contains (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_delitem (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_discard (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_dump_message (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_flush (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_file (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_message (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_get_string (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_getitem (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_has_key (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_items (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iter (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iteritems (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_iterkeys (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_itervalues (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_keys (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_labels (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_len (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_lock_unlock (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_pop (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_popitem (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_remove (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_set_item (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_update (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== ERROR: test_values (test.test_mailbox.TestBabyl) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_mailbox.py", line 917, in tearDown os.remove(lock_remnant) WindowsError: [Error 5] Access is denied: '@test.2' ====================================================================== FAIL: test_relpath (test.test_posixpath.PosixPathTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_posixpath.py", line 486, in test_relpath self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a") AssertionError: 'C:\\buildbot_py25\\trunk.mcintyre-windows\\build\\PCbuild\\a' != 'a' ====================================================================== ERROR: test_copy (test.test_urllib.urlretrieve_FileTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_urllib.py", line 200, in test_copy test_support.TESTFN), second_temp) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\urllib.py", line 89, in urlretrieve return _urlopener.retrieve(url, filename, reporthook, data) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\urllib.py", line 225, in retrieve tfp = open(filename, 'wb') IOError: [Errno 13] Permission denied: '@test.2' ====================================================================== ERROR: test_reporthook (test.test_urllib.urlretrieve_FileTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_urllib.py", line 224, in test_reporthook second_temp, hooktester) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\urllib.py", line 89, in urlretrieve return _urlopener.retrieve(url, filename, reporthook, data) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\urllib.py", line 225, in retrieve tfp = open(filename, 'wb') IOError: [Errno 13] Permission denied: '@test.2' sincerely, -The Buildbot From python-checkins at python.org Tue Mar 20 07:13:29 2007 From: python-checkins at python.org (neal.norwitz) Date: Tue, 20 Mar 2007 07:13:29 +0100 (CET) Subject: [Python-checkins] r54460 - python/trunk/Lib/test/test_urllib.py Message-ID: <20070320061329.E2E711E4006@bag.python.org> Author: neal.norwitz Date: Tue Mar 20 07:13:25 2007 New Revision: 54460 Modified: python/trunk/Lib/test/test_urllib.py Log: Try to make this test more resistant to dropping from previous runs (ie, files that may exist but cause the test to fail). Should be backported (assuming it works :-) Modified: python/trunk/Lib/test/test_urllib.py ============================================================================== --- python/trunk/Lib/test/test_urllib.py (original) +++ python/trunk/Lib/test/test_urllib.py Tue Mar 20 07:13:25 2007 @@ -27,6 +27,7 @@ def setUp(self): """Setup of a temp file to use for testing""" self.text = "test_urllib: %s\n" % self.__class__.__name__ + test_support.unlink(test_support.TESTFN) FILE = file(test_support.TESTFN, 'wb') try: FILE.write(self.text) @@ -195,6 +196,7 @@ def test_copy(self): # Test that setting the filename argument works. second_temp = "%s.2" % test_support.TESTFN + test_support.unlink(second_temp) self.registerFileForCleanUp(second_temp) result = urllib.urlretrieve(self.constructLocalFileUrl( test_support.TESTFN), second_temp) @@ -219,6 +221,7 @@ self.assertEqual(count, count_holder[0]) count_holder[0] = count_holder[0] + 1 second_temp = "%s.2" % test_support.TESTFN + test_support.unlink(second_temp) self.registerFileForCleanUp(second_temp) urllib.urlretrieve(self.constructLocalFileUrl(test_support.TESTFN), second_temp, hooktester) From python-checkins at python.org Tue Mar 20 07:16:27 2007 From: python-checkins at python.org (neal.norwitz) Date: Tue, 20 Mar 2007 07:16:27 +0100 (CET) Subject: [Python-checkins] r54461 - python/trunk/Lib/test/test_mailbox.py Message-ID: <20070320061627.CB4A11E4006@bag.python.org> Author: neal.norwitz Date: Tue Mar 20 07:16:26 2007 New Revision: 54461 Modified: python/trunk/Lib/test/test_mailbox.py Log: Try to make this test more resistant to dropping from previous runs (ie, files that may exist but cause the test to fail). Should be backported (assuming it works :-) Modified: python/trunk/Lib/test/test_mailbox.py ============================================================================== --- python/trunk/Lib/test/test_mailbox.py (original) +++ python/trunk/Lib/test/test_mailbox.py Tue Mar 20 07:16:26 2007 @@ -54,6 +54,7 @@ def setUp(self): self._path = test_support.TESTFN + self._delete_recursively(self._path) self._box = self._factory(self._path) def tearDown(self): From buildbot at python.org Tue Mar 20 07:38:51 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 20 Mar 2007 06:38:51 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070320063851.E1ACB1E4009@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/149 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl,neal.norwitz Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Tue Mar 20 07:53:24 2007 From: python-checkins at python.org (neal.norwitz) Date: Tue, 20 Mar 2007 07:53:24 +0100 (CET) Subject: [Python-checkins] r54462 - python/trunk/Lib/test/test_mailbox.py Message-ID: <20070320065324.8F1AA1E4008@bag.python.org> Author: neal.norwitz Date: Tue Mar 20 07:53:17 2007 New Revision: 54462 Modified: python/trunk/Lib/test/test_mailbox.py Log: Try to be a little more resilient to errors. This might help the test pass, but my guess is that it won't. I'm guessing that some other test is leaving this file open which means it can't be removed under Windows AFAIK. Modified: python/trunk/Lib/test/test_mailbox.py ============================================================================== --- python/trunk/Lib/test/test_mailbox.py (original) +++ python/trunk/Lib/test/test_mailbox.py Tue Mar 20 07:53:17 2007 @@ -694,7 +694,7 @@ self._box.close() self._delete_recursively(self._path) for lock_remnant in glob.glob(self._path + '.*'): - os.remove(lock_remnant) + test_support.unlink(lock_remnant) def test_add_from_string(self): # Add a string starting with 'From ' to the mailbox @@ -915,7 +915,7 @@ self._box.close() self._delete_recursively(self._path) for lock_remnant in glob.glob(self._path + '.*'): - os.remove(lock_remnant) + test_support.unlink(lock_remnant) def test_labels(self): # Get labels from the mailbox From python-checkins at python.org Tue Mar 20 09:14:59 2007 From: python-checkins at python.org (neal.norwitz) Date: Tue, 20 Mar 2007 09:14:59 +0100 (CET) Subject: [Python-checkins] r54463 - python/trunk/Lib/urllib.py Message-ID: <20070320081459.2EF441E4006@bag.python.org> Author: neal.norwitz Date: Tue Mar 20 09:14:57 2007 New Revision: 54463 Modified: python/trunk/Lib/urllib.py Log: Try to get test_urllib to pass on Windows by closing the file. I'm guessing that's the problem. h.getfile() must be called *after* h.getreply() and the fp can be None. I'm not entirely convinced this is the best fix (or even correct). The buildbots will tell us if things improve or not. I don't know if this needs to be backported (assuming it actually works). Modified: python/trunk/Lib/urllib.py ============================================================================== --- python/trunk/Lib/urllib.py (original) +++ python/trunk/Lib/urllib.py Tue Mar 20 09:14:57 2007 @@ -326,11 +326,12 @@ if data is not None: h.send(data) errcode, errmsg, headers = h.getreply() + fp = h.getfile() if errcode == -1: + if fp: fp.close() # something went wrong with the HTTP status line raise IOError, ('http protocol error', 0, 'got a bad status line', None) - fp = h.getfile() if errcode == 200: return addinfourl(fp, headers, "http:" + url) else: @@ -417,11 +418,12 @@ if data is not None: h.send(data) errcode, errmsg, headers = h.getreply() + fp = h.getfile() if errcode == -1: + if fp: fp.close() # something went wrong with the HTTP status line raise IOError, ('http protocol error', 0, 'got a bad status line', None) - fp = h.getfile() if errcode == 200: return addinfourl(fp, headers, "https:" + url) else: From python-checkins at python.org Tue Mar 20 22:12:24 2007 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 20 Mar 2007 22:12:24 +0100 (CET) Subject: [Python-checkins] r54464 - python/branches/release25-maint/Doc/lib/libitertools.tex Message-ID: <20070320211224.ED4471E4006@bag.python.org> Author: raymond.hettinger Date: Tue Mar 20 22:12:23 2007 New Revision: 54464 Modified: python/branches/release25-maint/Doc/lib/libitertools.tex Log: Add new example Modified: python/branches/release25-maint/Doc/lib/libitertools.tex ============================================================================== --- python/branches/release25-maint/Doc/lib/libitertools.tex (original) +++ python/branches/release25-maint/Doc/lib/libitertools.tex Tue Mar 20 22:12:23 2007 @@ -539,5 +539,8 @@ "grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')" return izip(*[chain(iterable, repeat(padvalue, n-1))]*n) +def reverse_map(d): + "Return a new dict with swapped keys and values" + return dict(izip(d.itervalues(), d)) \end{verbatim} From guido at python.org Tue Mar 20 22:19:06 2007 From: guido at python.org (Guido van Rossum) Date: Tue, 20 Mar 2007 14:19:06 -0700 Subject: [Python-checkins] r54197 - in python/trunk: Lib/glob.py Lib/test/test_glob.py Misc/NEWS In-Reply-To: <20070307083153.578C41E4003@bag.python.org> References: <20070307083153.578C41E4003@bag.python.org> Message-ID: This seems to have caused a new failure for me: ERROR: test_glob_literal (__main__.GlobTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "Lib/test/test_glob.py", line 60, in test_glob_literal u1 = glob.glob(u'*') File "/usr/local/google/home/guido/python/trunk/Lib/glob.py", line 16, in glob return list(iglob(pathname)) File "/usr/local/google/home/guido/python/trunk/Lib/glob.py", line 30, in iglob for name in glob1(os.curdir, basename): File "/usr/local/google/home/guido/python/trunk/Lib/glob.py", line 53, in glob1 dirname = unicode(dirname, sys.getfilesystemencoding()) TypeError: unicode() argument 2 must be string, not None On my system (derived from Ubuntu dapper), sys.getfilesystemencoding() returns None and the new code in glob.py doesn't seem to be prepared for that. --Guido On 3/7/07, georg.brandl wrote: > Author: georg.brandl > Date: Wed Mar 7 09:31:51 2007 > New Revision: 54197 > > Modified: > python/trunk/Lib/glob.py > python/trunk/Lib/test/test_glob.py > python/trunk/Misc/NEWS > Log: > Patch #1001604: glob.glob() now returns unicode filenames if it was > given a unicode argument and os.listdir() returns unicode filenames. > > > Modified: python/trunk/Lib/glob.py > ============================================================================== > --- python/trunk/Lib/glob.py (original) > +++ python/trunk/Lib/glob.py Wed Mar 7 09:31:51 2007 > @@ -1,8 +1,9 @@ > """Filename globbing utility.""" > > +import sys > import os > -import fnmatch > import re > +import fnmatch > > __all__ = ["glob", "iglob"] > > @@ -48,13 +49,15 @@ > def glob1(dirname, pattern): > if not dirname: > dirname = os.curdir > + if isinstance(pattern, unicode) and not isinstance(dirname, unicode): > + dirname = unicode(dirname, sys.getfilesystemencoding()) > try: > names = os.listdir(dirname) > except os.error: > return [] > - if pattern[0]!='.': > - names=filter(lambda x: x[0]!='.',names) > - return fnmatch.filter(names,pattern) > + if pattern[0] != '.': > + names = filter(lambda x: x[0] != '.', names) > + return fnmatch.filter(names, pattern) > > def glob0(dirname, basename): > if basename == '': > > Modified: python/trunk/Lib/test/test_glob.py > ============================================================================== > --- python/trunk/Lib/test/test_glob.py (original) > +++ python/trunk/Lib/test/test_glob.py Wed Mar 7 09:31:51 2007 > @@ -52,6 +52,16 @@ > eq(self.glob('aab'), [self.norm('aab')]) > eq(self.glob('zymurgy'), []) > > + # test return types are unicode, but only if os.listdir > + # returns unicode filenames > + uniset = set([unicode]) > + tmp = os.listdir(u'.') > + if set(type(x) for x in tmp) == uniset: > + u1 = glob.glob(u'*') > + u2 = glob.glob(u'./*') > + self.assertEquals(set(type(r) for r in u1), uniset) > + self.assertEquals(set(type(r) for r in u2), uniset) > + > def test_glob_one_directory(self): > eq = self.assertSequencesEqual_noorder > eq(self.glob('a*'), map(self.norm, ['a', 'aab', 'aaa'])) > > Modified: python/trunk/Misc/NEWS > ============================================================================== > --- python/trunk/Misc/NEWS (original) > +++ python/trunk/Misc/NEWS Wed Mar 7 09:31:51 2007 > @@ -152,6 +152,9 @@ > Library > ------- > > +- Patch #1001604: glob.glob() now returns unicode filenames if it was > + given a unicode argument and os.listdir() returns unicode filenames. > + > - Patch #1673619: setup.py identifies extension modules it doesn't know how > to build and those it knows how to build but that fail to build. > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > -- --Guido van Rossum (home page: http://www.python.org/~guido/) From python-checkins at python.org Tue Mar 20 22:27:30 2007 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 20 Mar 2007 22:27:30 +0100 (CET) Subject: [Python-checkins] r54465 - in python/trunk: Include/setobject.h Lib/test/test_set.py Objects/dictobject.c Objects/setobject.c Message-ID: <20070320212730.3AC2C1E4006@bag.python.org> Author: raymond.hettinger Date: Tue Mar 20 22:27:24 2007 New Revision: 54465 Modified: python/trunk/Include/setobject.h python/trunk/Lib/test/test_set.py python/trunk/Objects/dictobject.c python/trunk/Objects/setobject.c Log: Extend work on rev 52962 and 53829 eliminating redundant PyObject_Hash() calls and fixing set/dict interoperability. Modified: python/trunk/Include/setobject.h ============================================================================== --- python/trunk/Include/setobject.h (original) +++ python/trunk/Include/setobject.h Tue Mar 20 22:27:24 2007 @@ -82,7 +82,8 @@ PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key); PyAPI_FUNC(int) PySet_Discard(PyObject *set, PyObject *key); PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); -PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **entry); +PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key); +PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash); PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); Modified: python/trunk/Lib/test/test_set.py ============================================================================== --- python/trunk/Lib/test/test_set.py (original) +++ python/trunk/Lib/test/test_set.py Tue Mar 20 22:27:24 2007 @@ -288,6 +288,10 @@ self.assertEqual(sum(elem.hash_count for elem in d), n) if hasattr(s, 'symmetric_difference_update'): s.symmetric_difference_update(d) + self.assertEqual(sum(elem.hash_count for elem in d), n) + d2 = dict.fromkeys(set(d)) + self.assertEqual(sum(elem.hash_count for elem in d), n) + d3 = dict.fromkeys(frozenset(d)) self.assertEqual(sum(elem.hash_count for elem in d), n) class TestSet(TestJointOps): Modified: python/trunk/Objects/dictobject.c ============================================================================== --- python/trunk/Objects/dictobject.c (original) +++ python/trunk/Objects/dictobject.c Tue Mar 20 22:27:24 2007 @@ -1175,6 +1175,24 @@ if (d == NULL) return NULL; + if (PyDict_CheckExact(d) && PyAnySet_CheckExact(seq)) { + dictobject *mp = (dictobject *)d; + Py_ssize_t pos = 0; + PyObject *key; + long hash; + + if (dictresize(mp, PySet_GET_SIZE(seq))) + return NULL; + + while (_PySet_NextEntry(seq, &pos, &key, &hash)) { + Py_INCREF(key); + Py_INCREF(Py_None); + if (insertdict(mp, key, hash, Py_None)) + return NULL; + } + return d; + } + it = PyObject_GetIter(seq); if (it == NULL){ Py_DECREF(d); Modified: python/trunk/Objects/setobject.c ============================================================================== --- python/trunk/Objects/setobject.c (original) +++ python/trunk/Objects/setobject.c Tue Mar 20 22:27:24 2007 @@ -2137,7 +2137,7 @@ } int -_PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **entry) +_PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key) { setentry *entry_ptr; @@ -2147,7 +2147,23 @@ } if (set_next((PySetObject *)set, pos, &entry_ptr) == 0) return 0; - *entry = entry_ptr->key; + *key = entry_ptr->key; + return 1; +} + +int +_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash) +{ + setentry *entry; + + if (!PyAnySet_Check(set)) { + PyErr_BadInternalCall(); + return -1; + } + if (set_next((PySetObject *)set, pos, &entry) == 0) + return 0; + *key = entry->key; + *hash = entry->hash; return 1; } From brett at python.org Tue Mar 20 22:37:06 2007 From: brett at python.org (Brett Cannon) Date: Tue, 20 Mar 2007 14:37:06 -0700 Subject: [Python-checkins] r54463 - python/trunk/Lib/urllib.py In-Reply-To: <20070320081459.2EF441E4006@bag.python.org> References: <20070320081459.2EF441E4006@bag.python.org> Message-ID: Would using contextlib.closing() be a better solution? That way closure is guaranteed and it can handle both error and success cases? -Brett On 3/20/07, neal.norwitz wrote: > Author: neal.norwitz > Date: Tue Mar 20 09:14:57 2007 > New Revision: 54463 > > Modified: > python/trunk/Lib/urllib.py > Log: > Try to get test_urllib to pass on Windows by closing the file. > I'm guessing that's the problem. h.getfile() must be called *after* > h.getreply() and the fp can be None. > > I'm not entirely convinced this is the best fix (or even correct). > The buildbots will tell us if things improve or not. I don't > know if this needs to be backported (assuming it actually works). > > > Modified: python/trunk/Lib/urllib.py > ============================================================================== > --- python/trunk/Lib/urllib.py (original) > +++ python/trunk/Lib/urllib.py Tue Mar 20 09:14:57 2007 > @@ -326,11 +326,12 @@ > if data is not None: > h.send(data) > errcode, errmsg, headers = h.getreply() > + fp = h.getfile() > if errcode == -1: > + if fp: fp.close() > # something went wrong with the HTTP status line > raise IOError, ('http protocol error', 0, > 'got a bad status line', None) > - fp = h.getfile() > if errcode == 200: > return addinfourl(fp, headers, "http:" + url) > else: > @@ -417,11 +418,12 @@ > if data is not None: > h.send(data) > errcode, errmsg, headers = h.getreply() > + fp = h.getfile() > if errcode == -1: > + if fp: fp.close() > # something went wrong with the HTTP status line > raise IOError, ('http protocol error', 0, > 'got a bad status line', None) > - fp = h.getfile() > if errcode == 200: > return addinfourl(fp, headers, "https:" + url) > else: > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > From python-checkins at python.org Tue Mar 20 22:45:05 2007 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 20 Mar 2007 22:45:05 +0100 (CET) Subject: [Python-checkins] r54466 - in python/branches/release25-maint: Include/setobject.h Lib/test/test_set.py Objects/dictobject.c Objects/setobject.c Message-ID: <20070320214505.D8DDA1E400B@bag.python.org> Author: raymond.hettinger Date: Tue Mar 20 22:45:04 2007 New Revision: 54466 Modified: python/branches/release25-maint/Include/setobject.h python/branches/release25-maint/Lib/test/test_set.py python/branches/release25-maint/Objects/dictobject.c python/branches/release25-maint/Objects/setobject.c Log: Extend work on rev 52962 and 53830 eliminating redundant PyObject_Hash() calls and fixing set/dict interoperability. Modified: python/branches/release25-maint/Include/setobject.h ============================================================================== --- python/branches/release25-maint/Include/setobject.h (original) +++ python/branches/release25-maint/Include/setobject.h Tue Mar 20 22:45:04 2007 @@ -82,7 +82,8 @@ PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key); PyAPI_FUNC(int) PySet_Discard(PyObject *set, PyObject *key); PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key); -PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **entry); +PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key); +PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash); PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set); PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable); Modified: python/branches/release25-maint/Lib/test/test_set.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_set.py (original) +++ python/branches/release25-maint/Lib/test/test_set.py Tue Mar 20 22:45:04 2007 @@ -285,10 +285,14 @@ s = self.thetype(d) self.assertEqual(sum(elem.hash_count for elem in d), n) s.difference(d) - self.assertEqual(sum(elem.hash_count for elem in d), n) + self.assertEqual(sum(elem.hash_count for elem in d), n) if hasattr(s, 'symmetric_difference_update'): s.symmetric_difference_update(d) - self.assertEqual(sum(elem.hash_count for elem in d), n) + self.assertEqual(sum(elem.hash_count for elem in d), n) + d2 = dict.fromkeys(set(d)) + self.assertEqual(sum(elem.hash_count for elem in d), n) + d3 = dict.fromkeys(frozenset(d)) + self.assertEqual(sum(elem.hash_count for elem in d), n) class TestSet(TestJointOps): thetype = set Modified: python/branches/release25-maint/Objects/dictobject.c ============================================================================== --- python/branches/release25-maint/Objects/dictobject.c (original) +++ python/branches/release25-maint/Objects/dictobject.c Tue Mar 20 22:45:04 2007 @@ -1175,6 +1175,24 @@ if (d == NULL) return NULL; + if (PyDict_CheckExact(d) && PyAnySet_CheckExact(seq)) { + dictobject *mp = (dictobject *)d; + Py_ssize_t pos = 0; + PyObject *key; + long hash; + + if (dictresize(mp, PySet_GET_SIZE(seq))) + return NULL; + + while (_PySet_NextEntry(seq, &pos, &key, &hash)) { + Py_INCREF(key); + Py_INCREF(Py_None); + if (insertdict(mp, key, hash, Py_None)) + return NULL; + } + return d; + } + it = PyObject_GetIter(seq); if (it == NULL){ Py_DECREF(d); Modified: python/branches/release25-maint/Objects/setobject.c ============================================================================== --- python/branches/release25-maint/Objects/setobject.c (original) +++ python/branches/release25-maint/Objects/setobject.c Tue Mar 20 22:45:04 2007 @@ -2137,7 +2137,7 @@ } int -_PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **entry) +_PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key) { setentry *entry_ptr; @@ -2147,7 +2147,23 @@ } if (set_next((PySetObject *)set, pos, &entry_ptr) == 0) return 0; - *entry = entry_ptr->key; + *key = entry_ptr->key; + return 1; +} + +int +_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash) +{ + setentry *entry; + + if (!PyAnySet_Check(set)) { + PyErr_BadInternalCall(); + return -1; + } + if (set_next((PySetObject *)set, pos, &entry) == 0) + return 0; + *key = entry->key; + *hash = entry->hash; return 1; } From python-checkins at python.org Tue Mar 20 22:47:46 2007 From: python-checkins at python.org (brett.cannon) Date: Tue, 20 Mar 2007 22:47:46 +0100 (CET) Subject: [Python-checkins] r54467 - peps/trunk/pep-3113.txt Message-ID: <20070320214746.8D8471E4008@bag.python.org> Author: brett.cannon Date: Tue Mar 20 22:47:44 2007 New Revision: 54467 Modified: peps/trunk/pep-3113.txt Log: Clarify the transition plan for the 2to3 fixer. Also link directly to the fixer itself. Modified: peps/trunk/pep-3113.txt ============================================================================== --- peps/trunk/pep-3113.txt (original) +++ peps/trunk/pep-3113.txt Tue Mar 20 22:47:44 2007 @@ -216,13 +216,12 @@ Python 2.6. This will be treated like any other syntactic change that is to occur in Python 3.0 compared to Python 2.6. -Second, the 2to3 refactoring tool [#2to3]_ will gain a rule for -translating tuple parameters to being a single parameter that is -unpacked as the first statement in the function. The name of the new -parameter will be a mangling of tuple parameter's names by joining -them with underscores. The new parameter will then be unpacked into -the names originally used in the tuple parameter. This means that the -following function:: +Second, the 2to3 refactoring tool [#2to3]_ will gain a fixer +[#fixer]_ for translating tuple parameters to being a single parameter +that is unpacked as the first statement in the function. The name of +the new parameter will be changed. The new parameter will then be +unpacked into the names originally used in the tuple parameter. This +means that the following function:: def fxn((a, (b, c))): pass @@ -233,6 +232,17 @@ (a, (b, c)) = a_b_c pass +As tuple parameters are used by lambdas because of the single +expression limitation, they must also be supported. This is done by +having the expected sequence argument bound to a single parameter and +then indexing on that parameter:: + + lambda (x, y): x + y + +will be translated into:: + + lambda x_y: x_y[0] + x_y[1] + References ========== @@ -240,6 +250,9 @@ .. [#2to3] 2to3 refactoring tool (http://svn.python.org/view/sandbox/trunk/2to3/) +.. [#fixer] 2to3 fixer + (http://svn.python.org/view/sandbox/trunk/2to3/fixes/fix_tuple_params.py) + .. [#ironpython] IronPython (http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython) From buildbot at python.org Tue Mar 20 23:39:13 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 20 Mar 2007 22:39:13 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070320223913.BED661E4006@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/153 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: raymond.hettinger Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Wed Mar 21 00:05:21 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 00:05:21 +0100 (CET) Subject: [Python-checkins] r54468 - python/trunk/Lib/glob.py Message-ID: <20070320230521.44C4E1E4006@bag.python.org> Author: georg.brandl Date: Wed Mar 21 00:05:14 2007 New Revision: 54468 Modified: python/trunk/Lib/glob.py Log: Fix for glob.py if filesystem encoding is None. Modified: python/trunk/Lib/glob.py ============================================================================== --- python/trunk/Lib/glob.py (original) +++ python/trunk/Lib/glob.py Wed Mar 21 00:05:14 2007 @@ -50,7 +50,8 @@ if not dirname: dirname = os.curdir if isinstance(pattern, unicode) and not isinstance(dirname, unicode): - dirname = unicode(dirname, sys.getfilesystemencoding()) + dirname = unicode(dirname, sys.getfilesystemencoding() or + sys.getdefaultencoding()) try: names = os.listdir(dirname) except os.error: From g.brandl at gmx.net Wed Mar 21 00:05:41 2007 From: g.brandl at gmx.net (Georg Brandl) Date: Wed, 21 Mar 2007 00:05:41 +0100 Subject: [Python-checkins] r54197 - in python/trunk: Lib/glob.py Lib/test/test_glob.py Misc/NEWS In-Reply-To: References: <20070307083153.578C41E4003@bag.python.org> Message-ID: Guido van Rossum schrieb: > This seems to have caused a new failure for me: > > ERROR: test_glob_literal (__main__.GlobTests) > ---------------------------------------------------------------------- > Traceback (most recent call last): > File "Lib/test/test_glob.py", line 60, in test_glob_literal > u1 = glob.glob(u'*') > File "/usr/local/google/home/guido/python/trunk/Lib/glob.py", line 16, in glob > return list(iglob(pathname)) > File "/usr/local/google/home/guido/python/trunk/Lib/glob.py", line > 30, in iglob > for name in glob1(os.curdir, basename): > File "/usr/local/google/home/guido/python/trunk/Lib/glob.py", line > 53, in glob1 > dirname = unicode(dirname, sys.getfilesystemencoding()) > TypeError: unicode() argument 2 must be string, not None > > On my system (derived from Ubuntu dapper), sys.getfilesystemencoding() > returns None and the new code in glob.py doesn't seem to be prepared > for that. Thanks for noticing, I now select "sys.getfilesystemencoding() or sys.getdefaultencoding()". Georg From buildbot at python.org Wed Mar 21 00:32:41 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 20 Mar 2007 23:32:41 +0000 Subject: [Python-checkins] buildbot warnings in amd64 gentoo trunk Message-ID: <20070320233241.ED3681E4006@bag.python.org> The Buildbot has detected a new failure of amd64 gentoo trunk. Full details are available at: http://www.python.org/dev/buildbot/all/amd64%2520gentoo%2520trunk/builds/1887 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_timeout ====================================================================== ERROR: testRecvTimeout (test.test_timeout.TimeoutTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/buildbot/slave/py-build/trunk.norwitz-amd64/build/Lib/test/test_timeout.py", line 133, in testRecvTimeout self.sock.connect(self.addr_remote) File "", line 1, in connect gaierror: (-2, 'Name or service not known') ====================================================================== FAIL: testConnectTimeout (test.test_timeout.TimeoutTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/buildbot/slave/py-build/trunk.norwitz-amd64/build/Lib/test/test_timeout.py", line 128, in testConnectTimeout %(_delta, self.fuzz, _timeout)) AssertionError: timeout (10.0036) is more than 2 seconds more than expected (0.001) make: *** [buildbottest] Error 1 sincerely, -The Buildbot From buildbot at python.org Wed Mar 21 01:15:02 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 21 Mar 2007 00:15:02 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 Message-ID: <20070321001503.8E4791E4006@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/72 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl,gregory.p.smith,raymond.hettinger Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Wed Mar 21 03:21:46 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 03:21:46 +0100 (CET) Subject: [Python-checkins] r54471 - in sandbox/trunk/2to3: fixes/fix_apply.py fixes/fix_dict.py fixes/fix_except.py fixes/fix_exec.py fixes/fix_has_key.py fixes/fix_input.py fixes/fix_intern.py fixes/fix_long.py fixes/fix_next.py fixes/fix_nonzero.py fixes/fix_print.py fixes/fix_raise.py fixes/fix_raw_input.py fixes/fix_repr.py fixes/fix_throw.py fixes/fix_tuple_params.py fixes/fix_xrange.py fixes/macros.py fixes/util.py refactor.py Message-ID: <20070321022146.12C2B1E4006@bag.python.org> Author: collin.winter Date: Wed Mar 21 03:21:36 2007 New Revision: 54471 Added: sandbox/trunk/2to3/fixes/util.py - copied, changed from r54463, sandbox/trunk/2to3/fixes/macros.py Removed: sandbox/trunk/2to3/fixes/macros.py Modified: sandbox/trunk/2to3/fixes/fix_apply.py sandbox/trunk/2to3/fixes/fix_dict.py sandbox/trunk/2to3/fixes/fix_except.py sandbox/trunk/2to3/fixes/fix_exec.py sandbox/trunk/2to3/fixes/fix_has_key.py sandbox/trunk/2to3/fixes/fix_input.py sandbox/trunk/2to3/fixes/fix_intern.py sandbox/trunk/2to3/fixes/fix_long.py sandbox/trunk/2to3/fixes/fix_next.py sandbox/trunk/2to3/fixes/fix_nonzero.py sandbox/trunk/2to3/fixes/fix_print.py sandbox/trunk/2to3/fixes/fix_raise.py sandbox/trunk/2to3/fixes/fix_raw_input.py sandbox/trunk/2to3/fixes/fix_repr.py sandbox/trunk/2to3/fixes/fix_throw.py sandbox/trunk/2to3/fixes/fix_tuple_params.py sandbox/trunk/2to3/fixes/fix_xrange.py sandbox/trunk/2to3/refactor.py Log: Rename fixes.macros to fixes.util. I want it to be more general than just node construction macros. Modified: sandbox/trunk/2to3/fixes/fix_apply.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_apply.py (original) +++ sandbox/trunk/2to3/fixes/fix_apply.py Wed Mar 21 03:21:36 2007 @@ -9,7 +9,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Call, Comma +from fixes.util import Call, Comma class FixApply(basefix.BaseFix): Modified: sandbox/trunk/2to3/fixes/fix_dict.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_dict.py (original) +++ sandbox/trunk/2to3/fixes/fix_dict.py Wed Mar 21 03:21:36 2007 @@ -26,7 +26,7 @@ import patcomp from pgen2 import token from fixes import basefix -from fixes import macros +from fixes.util import Name, Call, lparen_leaf, rparen_leaf class FixDict(basefix.BaseFix): @@ -54,14 +54,14 @@ special = not tail and self.in_special_context(node, isiter) args = head + [pytree.Node(syms.trailer, [pytree.Leaf(token.DOT, '.'), - macros.Name(method)]), + Name(method)]), pytree.Node(syms.trailer, - [macros.lparen_leaf.clone(), - macros.rparen_leaf.clone()])] + [lparen_leaf.clone(), + rparen_leaf.clone()])] new = pytree.Node(syms.power, args) if not special: new.set_prefix("") - new = macros.Call(macros.Name(isiter and "iter" or "list"), [new]) + new = Call(Name(isiter and "iter" or "list"), [new]) if tail: new = pytree.Node(syms.power, [new] + tail) new.set_prefix(node.get_prefix()) Modified: sandbox/trunk/2to3/fixes/fix_except.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_except.py (original) +++ sandbox/trunk/2to3/fixes/fix_except.py Wed Mar 21 03:21:36 2007 @@ -27,7 +27,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Assign, Attr, Name +from fixes.util import Assign, Attr, Name def find_excepts(nodes): for i, n in enumerate(nodes): Modified: sandbox/trunk/2to3/fixes/fix_exec.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_exec.py (original) +++ sandbox/trunk/2to3/fixes/fix_exec.py Wed Mar 21 03:21:36 2007 @@ -13,7 +13,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Comma, Name, Call +from fixes.util import Comma, Name, Call class FixExec(basefix.BaseFix): Modified: sandbox/trunk/2to3/fixes/fix_has_key.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_has_key.py (original) +++ sandbox/trunk/2to3/fixes/fix_has_key.py Wed Mar 21 03:21:36 2007 @@ -33,7 +33,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Name +from fixes.util import Name class FixHasKey(basefix.BaseFix): Modified: sandbox/trunk/2to3/fixes/fix_input.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_input.py (original) +++ sandbox/trunk/2to3/fixes/fix_input.py Wed Mar 21 03:21:36 2007 @@ -6,7 +6,7 @@ import patcomp from pgen2 import token from fixes import basefix -from fixes import macros +from fixes.util import Call, Name class FixInput(basefix.BaseFix): @@ -20,6 +20,6 @@ def transform(self, node): new = node.clone() new.set_prefix("") - new = macros.Call(macros.Name("eval"), [new]) + new = Call(Name("eval"), [new]) new.set_prefix(node.get_prefix()) return new Modified: sandbox/trunk/2to3/fixes/fix_intern.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_intern.py (original) +++ sandbox/trunk/2to3/fixes/fix_intern.py Wed Mar 21 03:21:36 2007 @@ -9,7 +9,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Name, Attr +from fixes.util import Name, Attr class FixIntern(basefix.BaseFix): Modified: sandbox/trunk/2to3/fixes/fix_long.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_long.py (original) +++ sandbox/trunk/2to3/fixes/fix_long.py Wed Mar 21 03:21:36 2007 @@ -10,7 +10,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Name +from fixes.util import Name class FixLong(basefix.BaseFix): Modified: sandbox/trunk/2to3/fixes/fix_next.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_next.py (original) +++ sandbox/trunk/2to3/fixes/fix_next.py Wed Mar 21 03:21:36 2007 @@ -10,7 +10,7 @@ from pgen2 import token from pygram import python_symbols as syms from fixes import basefix -from fixes.macros import Name, Call +from fixes.util import Name, Call bind_warning = "Calls to builtin next() possibly shadowed by global binding" Modified: sandbox/trunk/2to3/fixes/fix_nonzero.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_nonzero.py (original) +++ sandbox/trunk/2to3/fixes/fix_nonzero.py Wed Mar 21 03:21:36 2007 @@ -6,7 +6,7 @@ from pgen2 import token from pygram import python_symbols as syms from fixes import basefix -from fixes.macros import Name +from fixes.util import Name class FixNonzero(basefix.BaseFix): PATTERN = """ Modified: sandbox/trunk/2to3/fixes/fix_print.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_print.py (original) +++ sandbox/trunk/2to3/fixes/fix_print.py Wed Mar 21 03:21:36 2007 @@ -14,7 +14,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Name, Call, Comma +from fixes.util import Name, Call, Comma class FixPrint(basefix.BaseFix): Modified: sandbox/trunk/2to3/fixes/fix_raise.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_raise.py (original) +++ sandbox/trunk/2to3/fixes/fix_raise.py Wed Mar 21 03:21:36 2007 @@ -25,7 +25,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Name, Call, Attr, ArgList, is_tuple +from fixes.util import Name, Call, Attr, ArgList, is_tuple class FixRaise(basefix.BaseFix): Modified: sandbox/trunk/2to3/fixes/fix_raw_input.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_raw_input.py (original) +++ sandbox/trunk/2to3/fixes/fix_raw_input.py Wed Mar 21 03:21:36 2007 @@ -5,7 +5,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes import macros +from fixes.util import Name class FixRawInput(basefix.BaseFix): @@ -20,6 +20,6 @@ results = self.match(node) args = results["args"] new = pytree.Node(self.syms.power, - [macros.Name("input"), args.clone()]) + [Name("input"), args.clone()]) new.set_prefix(node.get_prefix()) return new Modified: sandbox/trunk/2to3/fixes/fix_repr.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_repr.py (original) +++ sandbox/trunk/2to3/fixes/fix_repr.py Wed Mar 21 03:21:36 2007 @@ -7,7 +7,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Call, Name +from fixes.util import Call, Name class FixRepr(basefix.BaseFix): Modified: sandbox/trunk/2to3/fixes/fix_throw.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_throw.py (original) +++ sandbox/trunk/2to3/fixes/fix_throw.py Wed Mar 21 03:21:36 2007 @@ -11,7 +11,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.macros import Name, Call, ArgList, Attr, is_tuple +from fixes.util import Name, Call, ArgList, Attr, is_tuple class FixThrow(basefix.BaseFix): Modified: sandbox/trunk/2to3/fixes/fix_tuple_params.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_tuple_params.py (original) +++ sandbox/trunk/2to3/fixes/fix_tuple_params.py Wed Mar 21 03:21:36 2007 @@ -20,7 +20,7 @@ from pgen2 import token from pygram import python_symbols as syms from fixes import basefix -from fixes.macros import Assign, Name, Newline, Number, Subscript +from fixes.util import Assign, Name, Newline, Number, Subscript def is_docstring(stmt): return isinstance(stmt, pytree.Node) and \ Modified: sandbox/trunk/2to3/fixes/fix_xrange.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_xrange.py (original) +++ sandbox/trunk/2to3/fixes/fix_xrange.py Wed Mar 21 03:21:36 2007 @@ -6,7 +6,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes import macros +from fixes.util import Name class FixXrange(basefix.BaseFix): @@ -21,6 +21,6 @@ results = self.match(node) args = results["args"] new = pytree.Node(self.syms.power, - [macros.Name("range"), args.clone()]) + [Name("range"), args.clone()]) new.set_prefix(node.get_prefix()) return new Deleted: /sandbox/trunk/2to3/fixes/macros.py ============================================================================== --- /sandbox/trunk/2to3/fixes/macros.py Wed Mar 21 03:21:36 2007 +++ (empty file) @@ -1,74 +0,0 @@ -"""Abstract away often-used node construction routines.""" -# Author: Collin Winter - -# Local imports -from pgen2 import token -from pytree import Leaf, Node -from pygram import python_symbols as syms - - -### Constant nodes -ass_leaf = Leaf(token.EQUAL, "=") -ass_leaf.set_prefix(" ") - -comma_leaf = Leaf(token.COMMA, ",") -lparen_leaf = Leaf(token.LPAR, "(") -rparen_leaf = Leaf(token.RPAR, ")") - -def Assign(target, source): - """Build an assignment statement""" - if not isinstance(target, tuple): - target = (target,) - if not isinstance(source, tuple): - source.set_prefix(" ") - source = (source,) - - return Node(syms.atom, target + (ass_leaf.clone(),) + source) - -def Name(name): - """Return a NAME leaf""" - return Leaf(token.NAME, name) - -def Attr(obj, attr): - """A node tuple for obj.attr""" - return (obj, - Node(syms.trailer, [Leaf(token.DOT, '.'), - attr])) - -def Comma(): - """A comma leaf""" - return comma_leaf.clone() - -def ArgList(args, lparen=lparen_leaf, rparen=rparen_leaf): - """A parenthesised argument list, used by Call()""" - return Node(syms.trailer, - [lparen.clone(), - Node(syms.arglist, args), - rparen.clone()]) - -def Call(func_name, args): - """A function call""" - return Node(syms.power, [func_name, ArgList(args)]) - -def Newline(): - """A newline literal""" - return Leaf(token.NEWLINE, "\n") - -def Number(n): - return Leaf(token.NUMBER, n) - -def Subscript(index_node): - """A numeric or string subscript""" - return Node(syms.trailer, [Leaf(token.LBRACE, '['), - index_node, - Leaf(token.RBRACE, ']')]) - -def is_tuple(node): - """Does the node represent a tuple literal?""" - - return (isinstance(node, Node) - and len(node.children) > 1 - and isinstance(node.children[0], Leaf) - and isinstance(node.children[-1], Leaf) - and node.children[0].value == "(" - and node.children[-1].value == ")") Copied: sandbox/trunk/2to3/fixes/util.py (from r54463, sandbox/trunk/2to3/fixes/macros.py) ============================================================================== --- sandbox/trunk/2to3/fixes/macros.py (original) +++ sandbox/trunk/2to3/fixes/util.py Wed Mar 21 03:21:36 2007 @@ -1,4 +1,4 @@ -"""Abstract away often-used node construction routines.""" +"""Utility functions, node construction macros, etc.""" # Author: Collin Winter # Local imports Modified: sandbox/trunk/2to3/refactor.py ============================================================================== --- sandbox/trunk/2to3/refactor.py (original) +++ sandbox/trunk/2to3/refactor.py Wed Mar 21 03:21:36 2007 @@ -25,7 +25,6 @@ from pgen2 import driver from pgen2 import tokenize import fixes -import fixes.macros import pygram if sys.version_info < (2, 4): From python-checkins at python.org Wed Mar 21 04:01:52 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 04:01:52 +0100 (CET) Subject: [Python-checkins] r54473 - peps/trunk/pep-3100.txt Message-ID: <20070321030152.EA1C81E4006@bag.python.org> Author: collin.winter Date: Wed Mar 21 04:01:51 2007 New Revision: 54473 Modified: peps/trunk/pep-3100.txt Log: Mark the removal of sys.exitfunc as done. Modified: peps/trunk/pep-3100.txt ============================================================================== --- peps/trunk/pep-3100.txt (original) +++ peps/trunk/pep-3100.txt Wed Mar 21 04:01:51 2007 @@ -216,7 +216,8 @@ ``lockfile``, ``newdir``, ``ni``, ``packmail``, ``poly``, ``rand``, ``statcache``, ``tb``, ``tzparse``, ``util``, ``whatsound``, ``whrandom``, ``zmod`` -* ``sys.exitfunc``: use atexit module instead [#sys-module]_ +* ``sys.exitfunc``: use atexit module instead [#sys-module]_, + [#exitfunc-patch]_ [done] * ``sys.exc_type``, ``sys.exc_values``, ``sys.exc_traceback``: not thread-safe; use ``sys.exc_info()`` or an attribute of the exception [2]_ [11]_ [#sys-module]_ @@ -386,6 +387,9 @@ .. [#__builtin__] Approach to resolving __builtin__ vs __builtins__ http://mail.python.org/pipermail/python-3000/2007-March/006161.html + +.. [#exitfunc-patch] Patch to remove sys.exitfunc + http://www.python.org/sf/1680961 Copyright ========= From python-checkins at python.org Wed Mar 21 04:12:48 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 04:12:48 +0100 (CET) Subject: [Python-checkins] r54474 - sandbox/trunk/2to3/fixes/fix_throw.py Message-ID: <20070321031248.44F101E4006@bag.python.org> Author: collin.winter Date: Wed Mar 21 04:12:46 2007 New Revision: 54474 Modified: sandbox/trunk/2to3/fixes/fix_throw.py Log: Remove unnecessary comments. Modified: sandbox/trunk/2to3/fixes/fix_throw.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_throw.py (original) +++ sandbox/trunk/2to3/fixes/fix_throw.py Wed Mar 21 04:12:46 2007 @@ -56,7 +56,5 @@ call_wtb = list(with_tb + (ArgList([tb]),)) throw_args.replace(pytree.Node(syms.power, call_wtb)) - # No return else: throw_args.replace(Call(exc, args)) - # No return From python-checkins at python.org Wed Mar 21 04:14:04 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 04:14:04 +0100 (CET) Subject: [Python-checkins] r54475 - sandbox/trunk/2to3/fixes/fix_long.py Message-ID: <20070321031404.325871E4006@bag.python.org> Author: collin.winter Date: Wed Mar 21 04:14:02 2007 New Revision: 54475 Modified: sandbox/trunk/2to3/fixes/fix_long.py Log: Take advantage of the new Number macro. Modified: sandbox/trunk/2to3/fixes/fix_long.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_long.py (original) +++ sandbox/trunk/2to3/fixes/fix_long.py Wed Mar 21 04:14:02 2007 @@ -10,7 +10,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.util import Name +from fixes.util import Name, Number class FixLong(basefix.BaseFix): @@ -31,7 +31,7 @@ assert node == self.static_long, node new = self.static_int.clone() if number and node.value[-1] in ("l", "L"): - new = pytree.Leaf(token.NUMBER, node.value[:-1]) + new = Number(node.value[:-1]) if new is not None: new.set_prefix(node.get_prefix()) return new From python-checkins at python.org Wed Mar 21 04:14:51 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 04:14:51 +0100 (CET) Subject: [Python-checkins] r54476 - sandbox/trunk/2to3/fixes/fix_tuple_params.py Message-ID: <20070321031451.24A931E4006@bag.python.org> Author: collin.winter Date: Wed Mar 21 04:14:50 2007 New Revision: 54476 Modified: sandbox/trunk/2to3/fixes/fix_tuple_params.py Log: Consolidate imports. Modified: sandbox/trunk/2to3/fixes/fix_tuple_params.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_tuple_params.py (original) +++ sandbox/trunk/2to3/fixes/fix_tuple_params.py Wed Mar 21 04:14:50 2007 @@ -18,9 +18,8 @@ # Local imports import pytree from pgen2 import token -from pygram import python_symbols as syms from fixes import basefix -from fixes.util import Assign, Name, Newline, Number, Subscript +from fixes.util import Assign, Name, Newline, Number, Subscript, syms def is_docstring(stmt): return isinstance(stmt, pytree.Node) and \ From python-checkins at python.org Wed Mar 21 04:15:30 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 04:15:30 +0100 (CET) Subject: [Python-checkins] r54477 - sandbox/trunk/2to3/fixes/fix_except.py sandbox/trunk/2to3/fixes/fix_has_key.py sandbox/trunk/2to3/fixes/fix_next.py sandbox/trunk/2to3/fixes/fix_nonzero.py sandbox/trunk/2to3/fixes/util.py Message-ID: <20070321031530.D83DD1E400C@bag.python.org> Author: collin.winter Date: Wed Mar 21 04:15:30 2007 New Revision: 54477 Modified: sandbox/trunk/2to3/fixes/fix_except.py sandbox/trunk/2to3/fixes/fix_has_key.py sandbox/trunk/2to3/fixes/fix_next.py sandbox/trunk/2to3/fixes/fix_nonzero.py sandbox/trunk/2to3/fixes/util.py Log: Add a prefix keyword arg to Name(); have the fixers take advantage of it. Modified: sandbox/trunk/2to3/fixes/fix_except.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_except.py (original) +++ sandbox/trunk/2to3/fixes/fix_except.py Wed Mar 21 04:15:30 2007 @@ -60,8 +60,7 @@ comma.replace(as_leaf.clone()) if N.type != token.NAME: # Generate a new N for the except clause - new_N = Name(self.new_name()) - new_N.set_prefix(" ") + new_N = Name(self.new_name(), prefix=" ") target = N.clone() target.set_prefix("") N.replace(new_N) Modified: sandbox/trunk/2to3/fixes/fix_has_key.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_has_key.py (original) +++ sandbox/trunk/2to3/fixes/fix_has_key.py Wed Mar 21 04:15:30 2007 @@ -93,11 +93,9 @@ else: before = pytree.Node(syms.power, before) before.set_prefix(" ") - n_op = Name("in") - n_op.set_prefix(" ") + n_op = Name("in", prefix=" ") if negation: - n_not = Name("not") - n_not.set_prefix(" ") + n_not = Name("not", prefix=" ") n_op = pytree.Node(syms.comp_op, (n_not, n_op)) new = pytree.Node(syms.comparison, (arg, n_op, before)) if after: Modified: sandbox/trunk/2to3/fixes/fix_next.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_next.py (original) +++ sandbox/trunk/2to3/fixes/fix_next.py Wed Mar 21 04:15:30 2007 @@ -66,8 +66,7 @@ node.replace(n) self.delayed.append(n) elif name: - n = Name("__next__") - n.set_prefix(name.get_prefix()) + n = Name("__next__", prefix=name.get_prefix()) name.replace(n) elif attr: # We don't do this transformation if we're assignment to "x.next". Modified: sandbox/trunk/2to3/fixes/fix_nonzero.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_nonzero.py (original) +++ sandbox/trunk/2to3/fixes/fix_nonzero.py Wed Mar 21 04:15:30 2007 @@ -4,9 +4,8 @@ # Local imports import pytree from pgen2 import token -from pygram import python_symbols as syms from fixes import basefix -from fixes.util import Name +from fixes.util import Name, syms class FixNonzero(basefix.BaseFix): PATTERN = """ @@ -22,6 +21,5 @@ assert results name = results["name"] - new = Name("__bool__") - new.set_prefix(name.get_prefix()) + new = Name("__bool__", prefix=name.get_prefix()) name.replace(new) Modified: sandbox/trunk/2to3/fixes/util.py ============================================================================== --- sandbox/trunk/2to3/fixes/util.py (original) +++ sandbox/trunk/2to3/fixes/util.py Wed Mar 21 04:15:30 2007 @@ -25,9 +25,11 @@ return Node(syms.atom, target + (ass_leaf.clone(),) + source) -def Name(name): +def Name(name, prefix=""): """Return a NAME leaf""" - return Leaf(token.NAME, name) + l = Leaf(token.NAME, name) + l.set_prefix(prefix) + return l def Attr(obj, attr): """A node tuple for obj.attr""" From anthony at interlink.com.au Wed Mar 21 05:06:44 2007 From: anthony at interlink.com.au (Anthony Baxter) Date: Wed, 21 Mar 2007 15:06:44 +1100 Subject: [Python-checkins] r54466 - in python/branches/release25-maint: Include/setobject.h Lib/test/test_set.py Objects/dictobject.c Objects/setobject.c In-Reply-To: <20070320214505.D8DDA1E400B@bag.python.org> References: <20070320214505.D8DDA1E400B@bag.python.org> Message-ID: <200703211506.45707.anthony@interlink.com.au> On Wednesday 21 March 2007 08:45, raymond.hettinger wrote: > Author: raymond.hettinger > Date: Tue Mar 20 22:45:04 2007 > New Revision: 54466 > > Modified: > python/branches/release25-maint/Include/setobject.h > python/branches/release25-maint/Lib/test/test_set.py > python/branches/release25-maint/Objects/dictobject.c > python/branches/release25-maint/Objects/setobject.c > Log: > Extend work on rev 52962 and 53830 eliminating redundant > PyObject_Hash() calls and fixing set/dict interoperability. Why is new behaviour and a new C API being added to Python 2.5??? From guido at python.org Wed Mar 21 05:58:45 2007 From: guido at python.org (Guido van Rossum) Date: Tue, 20 Mar 2007 21:58:45 -0700 Subject: [Python-checkins] r54466 - in python/branches/release25-maint: Include/setobject.h Lib/test/test_set.py Objects/dictobject.c Objects/setobject.c In-Reply-To: <200703211506.45707.anthony@interlink.com.au> References: <20070320214505.D8DDA1E400B@bag.python.org> <200703211506.45707.anthony@interlink.com.au> Message-ID: Because EWT can't wait for 2.6 is released? :-) On 3/20/07, Anthony Baxter wrote: > On Wednesday 21 March 2007 08:45, raymond.hettinger wrote: > > Author: raymond.hettinger > > Date: Tue Mar 20 22:45:04 2007 > > New Revision: 54466 > > > > Modified: > > python/branches/release25-maint/Include/setobject.h > > python/branches/release25-maint/Lib/test/test_set.py > > python/branches/release25-maint/Objects/dictobject.c > > python/branches/release25-maint/Objects/setobject.c > > Log: > > Extend work on rev 52962 and 53830 eliminating redundant > > PyObject_Hash() calls and fixing set/dict interoperability. > > Why is new behaviour and a new C API being added to Python 2.5??? > > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > -- --Guido van Rossum (home page: http://www.python.org/~guido/) From python-checkins at python.org Wed Mar 21 07:39:54 2007 From: python-checkins at python.org (neal.norwitz) Date: Wed, 21 Mar 2007 07:39:54 +0100 (CET) Subject: [Python-checkins] r54479 - in python/trunk: Misc/NEWS Python/fmod.c Message-ID: <20070321063954.7CC851E4006@bag.python.org> Author: neal.norwitz Date: Wed Mar 21 07:39:48 2007 New Revision: 54479 Removed: python/trunk/Python/fmod.c Modified: python/trunk/Misc/NEWS Log: Remove unused file spotted by Paul Hankin Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 21 07:39:48 2007 @@ -12,6 +12,8 @@ Core and builtins ----------------- +- Remove unused file Python/fmod.c. + - Patch #1675423: PyComplex_AsCComplex() now tries to convert an object to complex using its __complex__() method before falling back to the __float__() method. Therefore, the functions in the cmath module now Deleted: /python/trunk/Python/fmod.c ============================================================================== --- /python/trunk/Python/fmod.c Wed Mar 21 07:39:48 2007 +++ (empty file) @@ -1,27 +0,0 @@ - -/* Portable fmod(x, y) implementation for systems that don't have it */ - -#include "pyconfig.h" - -#include "pyport.h" -#include - -double -fmod(double x, double y) -{ - double i, f; - - if (y == 0.0) { - errno = EDOM; - return 0.0; - } - - /* return f such that x = i*y + f for some integer i - such that |f| < |y| and f has the same sign as x */ - - i = floor(x/y); - f = x - i*y; - if ((x < 0.0) != (y < 0.0)) - f = f-y; - return f; -} From python-checkins at python.org Wed Mar 21 10:00:48 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 10:00:48 +0100 (CET) Subject: [Python-checkins] r54480 - in python/trunk: Lib/test/test_unpack.py Misc/NEWS Python/ceval.c Message-ID: <20070321090048.956A21E4006@bag.python.org> Author: georg.brandl Date: Wed Mar 21 10:00:39 2007 New Revision: 54480 Modified: python/trunk/Lib/test/test_unpack.py python/trunk/Misc/NEWS python/trunk/Python/ceval.c Log: Patch #1682205: a TypeError while unpacking an iterable is no longer masked by a generic one with the message "unpack non-sequence". Modified: python/trunk/Lib/test/test_unpack.py ============================================================================== --- python/trunk/Lib/test/test_unpack.py (original) +++ python/trunk/Lib/test/test_unpack.py Wed Mar 21 10:00:39 2007 @@ -55,7 +55,7 @@ >>> a, b, c = 7 Traceback (most recent call last): ... - TypeError: unpack non-sequence + TypeError: 'int' object is not iterable Unpacking tuple of wrong size Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 21 10:00:39 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #1682205: a TypeError while unpacking an iterable is no longer + masked by a generic one with the message "unpack non-sequence". + - Remove unused file Python/fmod.c. - Patch #1675423: PyComplex_AsCComplex() now tries to convert an object Modified: python/trunk/Python/ceval.c ============================================================================== --- python/trunk/Python/ceval.c (original) +++ python/trunk/Python/ceval.c Wed Mar 21 10:00:39 2007 @@ -1774,12 +1774,10 @@ PUSH(w); } } else if (unpack_iterable(v, oparg, - stack_pointer + oparg)) + stack_pointer + oparg)) { stack_pointer += oparg; - else { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_SetString(PyExc_TypeError, - "unpack non-sequence"); + } else { + /* unpack_iterable() raised an exception */ why = WHY_EXCEPTION; } Py_DECREF(v); From python-checkins at python.org Wed Mar 21 10:01:01 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 10:01:01 +0100 (CET) Subject: [Python-checkins] r54481 - in python/branches/release25-maint: Lib/test/test_unpack.py Misc/NEWS Python/ceval.c Message-ID: <20070321090101.3E3E61E4006@bag.python.org> Author: georg.brandl Date: Wed Mar 21 10:00:55 2007 New Revision: 54481 Modified: python/branches/release25-maint/Lib/test/test_unpack.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Python/ceval.c Log: Patch #1682205: a TypeError while unpacking an iterable is no longer masked by a generic one with the message "unpack non-sequence". (backport from rev. 54480) Modified: python/branches/release25-maint/Lib/test/test_unpack.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_unpack.py (original) +++ python/branches/release25-maint/Lib/test/test_unpack.py Wed Mar 21 10:00:55 2007 @@ -55,7 +55,7 @@ >>> a, b, c = 7 Traceback (most recent call last): ... - TypeError: unpack non-sequence + TypeError: 'int' object is not iterable Unpacking tuple of wrong size Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Wed Mar 21 10:00:55 2007 @@ -12,6 +12,9 @@ Core and builtins ----------------- +- Patch #1682205: a TypeError while unpacking an iterable is no longer + masked by a generic one with the message "unpack non-sequence". + - Patch #1642547: Fix an error/crash when encountering syntax errors in complex if statements. Modified: python/branches/release25-maint/Python/ceval.c ============================================================================== --- python/branches/release25-maint/Python/ceval.c (original) +++ python/branches/release25-maint/Python/ceval.c Wed Mar 21 10:00:55 2007 @@ -1765,12 +1765,10 @@ PUSH(w); } } else if (unpack_iterable(v, oparg, - stack_pointer + oparg)) + stack_pointer + oparg)) { stack_pointer += oparg; - else { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_SetString(PyExc_TypeError, - "unpack non-sequence"); + } else { + /* unpack_iterable() raised an exception */ why = WHY_EXCEPTION; } Py_DECREF(v); From python-checkins at python.org Wed Mar 21 10:10:30 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 10:10:30 +0100 (CET) Subject: [Python-checkins] r54482 - in python/trunk: Doc/lib/libos.tex Lib/os.py Lib/test/test_os.py Misc/NEWS Message-ID: <20070321091030.BD07B1E4006@bag.python.org> Author: georg.brandl Date: Wed Mar 21 10:10:29 2007 New Revision: 54482 Modified: python/trunk/Doc/lib/libos.tex python/trunk/Lib/os.py python/trunk/Lib/test/test_os.py python/trunk/Misc/NEWS Log: New test for rev. 54407 which only uses directories under TESTFN. Modified: python/trunk/Doc/lib/libos.tex ============================================================================== --- python/trunk/Doc/lib/libos.tex (original) +++ python/trunk/Doc/lib/libos.tex Wed Mar 21 10:10:29 2007 @@ -1233,7 +1233,8 @@ \end{funcdesc} \begin{funcdesc}{walk}{top\optional{, topdown\code{=True} - \optional{, onerror\code{=None}}}} + \optional{, onerror\code{=None}\optional{, + followlinks\code{=False}}}}} \index{directory!walking} \index{directory!traversal} \function{walk()} generates the file names in a directory tree, by @@ -1273,24 +1274,25 @@ to abort the walk. Note that the filename is available as the \code{filename} attribute of the exception object. +By default, \function{walk()} will not walk down into symbolic links that +resolve to directories. Set \var{followlinks} to True to visit directories +pointed to by symlinks, on systems that support them. + \versionadded[The \var{followlinks} parameter]{2.6} \begin{notice} +Be aware that setting \var{followlinks} to true can lead to infinite recursion +if a link points to a parent directory of itself. \function{walk()} does not +keep track of the directories it visited already. +\end{notice} + +\begin{notice} If you pass a relative pathname, don't change the current working directory between resumptions of \function{walk()}. \function{walk()} never changes the current directory, and assumes that its caller doesn't either. \end{notice} -\begin{notice} -On systems that support symbolic links, links to subdirectories appear -in \var{dirnames} lists, but \function{walk()} will not visit them -(infinite loops are hard to avoid when following symbolic links). -To visit linked directories, you can identify them with -\code{os.path.islink(\var{path})}, and invoke \code{walk(\var{path})} -on each directly. -\end{notice} - This example displays the number of bytes taken by non-directory files in each directory under the starting directory, except that it doesn't look under any CVS subdirectory: Modified: python/trunk/Lib/os.py ============================================================================== --- python/trunk/Lib/os.py (original) +++ python/trunk/Lib/os.py Wed Mar 21 10:10:29 2007 @@ -221,7 +221,7 @@ __all__.extend(["makedirs", "removedirs", "renames"]) -def walk(top, topdown=True, onerror=None): +def walk(top, topdown=True, onerror=None, followlinks=False): """Directory tree generator. For each directory in the directory tree rooted at top (including top @@ -257,6 +257,10 @@ to abort the walk. Note that the filename is available as the filename attribute of the exception object. + By default, os.walk does not follow symbolic links to subdirectories on + systems that support them. In order to get this functionality, set the + optional argument 'followlinks' to true. + Caution: if you pass a relative pathname for top, don't change the current working directory between resumptions of walk. walk never changes the current directory, and assumes that the client doesn't @@ -300,8 +304,8 @@ yield top, dirs, nondirs for name in dirs: path = join(top, name) - if not islink(path): - for x in walk(path, topdown, onerror): + if followlinks or not islink(path): + for x in walk(path, topdown, onerror, followlinks): yield x if not topdown: yield top, dirs, nondirs Modified: python/trunk/Lib/test/test_os.py ============================================================================== --- python/trunk/Lib/test/test_os.py (original) +++ python/trunk/Lib/test/test_os.py Wed Mar 21 10:10:29 2007 @@ -272,65 +272,89 @@ from os.path import join # Build: - # TESTFN/ a file kid and two directory kids + # TESTFN/ + # TEST1/ a file kid and two directory kids # tmp1 # SUB1/ a file kid and a directory kid - # tmp2 - # SUB11/ no kids - # SUB2/ just a file kid - # tmp3 - sub1_path = join(test_support.TESTFN, "SUB1") + # tmp2 + # SUB11/ no kids + # SUB2/ a file kid and a dirsymlink kid + # tmp3 + # link/ a symlink to TESTFN.2 + # TEST2/ + # tmp4 a lone file + walk_path = join(test_support.TESTFN, "TEST1") + sub1_path = join(walk_path, "SUB1") sub11_path = join(sub1_path, "SUB11") - sub2_path = join(test_support.TESTFN, "SUB2") - tmp1_path = join(test_support.TESTFN, "tmp1") + sub2_path = join(walk_path, "SUB2") + tmp1_path = join(walk_path, "tmp1") tmp2_path = join(sub1_path, "tmp2") tmp3_path = join(sub2_path, "tmp3") + link_path = join(sub2_path, "link") + t2_path = join(test_support.TESTFN, "TEST2") + tmp4_path = join(test_support.TESTFN, "TEST2", "tmp4") # Create stuff. os.makedirs(sub11_path) os.makedirs(sub2_path) - for path in tmp1_path, tmp2_path, tmp3_path: + os.makedirs(t2_path) + for path in tmp1_path, tmp2_path, tmp3_path, tmp4_path: f = file(path, "w") f.write("I'm " + path + " and proud of it. Blame test_os.\n") f.close() + if hasattr(os, "symlink"): + os.symlink(os.path.abspath(t2_path), link_path) + else: + # it must be a directory because the test expects that + os.mkdir(link_path) # Walk top-down. - all = list(os.walk(test_support.TESTFN)) + all = list(os.walk(walk_path)) self.assertEqual(len(all), 4) # We can't know which order SUB1 and SUB2 will appear in. # Not flipped: TESTFN, SUB1, SUB11, SUB2 # flipped: TESTFN, SUB2, SUB1, SUB11 flipped = all[0][1][0] != "SUB1" all[0][1].sort() - self.assertEqual(all[0], (test_support.TESTFN, ["SUB1", "SUB2"], ["tmp1"])) + self.assertEqual(all[0], (walk_path, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[1 + flipped], (sub1_path, ["SUB11"], ["tmp2"])) self.assertEqual(all[2 + flipped], (sub11_path, [], [])) - self.assertEqual(all[3 - 2 * flipped], (sub2_path, [], ["tmp3"])) + self.assertEqual(all[3 - 2 * flipped], (sub2_path, ["link"], ["tmp3"])) # Prune the search. all = [] - for root, dirs, files in os.walk(test_support.TESTFN): + for root, dirs, files in os.walk(walk_path): all.append((root, dirs, files)) # Don't descend into SUB1. if 'SUB1' in dirs: # Note that this also mutates the dirs we appended to all! dirs.remove('SUB1') self.assertEqual(len(all), 2) - self.assertEqual(all[0], (test_support.TESTFN, ["SUB2"], ["tmp1"])) - self.assertEqual(all[1], (sub2_path, [], ["tmp3"])) + self.assertEqual(all[0], (walk_path, ["SUB2"], ["tmp1"])) + self.assertEqual(all[1], (sub2_path, ["link"], ["tmp3"])) # Walk bottom-up. - all = list(os.walk(test_support.TESTFN, topdown=False)) + all = list(os.walk(walk_path, topdown=False)) self.assertEqual(len(all), 4) # We can't know which order SUB1 and SUB2 will appear in. # Not flipped: SUB11, SUB1, SUB2, TESTFN # flipped: SUB2, SUB11, SUB1, TESTFN flipped = all[3][1][0] != "SUB1" all[3][1].sort() - self.assertEqual(all[3], (test_support.TESTFN, ["SUB1", "SUB2"], ["tmp1"])) + self.assertEqual(all[3], (walk_path, ["SUB1", "SUB2"], ["tmp1"])) self.assertEqual(all[flipped], (sub11_path, [], [])) self.assertEqual(all[flipped + 1], (sub1_path, ["SUB11"], ["tmp2"])) - self.assertEqual(all[2 - 2 * flipped], (sub2_path, [], ["tmp3"])) + self.assertEqual(all[2 - 2 * flipped], (sub2_path, ["link"], ["tmp3"])) + + # Walk, following symlinks. + for root, dirs, files in os.walk(walk_path, followlinks=True): + if root == link_path: + self.assertEqual(dirs, []) + self.assertEqual(files, ["tmp4"]) + break + else: + self.fail("Didn't follow symlink with followlinks=True") + # Tear everything down. This is a decent use for bottom-up on # Windows, which doesn't have a recursive delete command. The @@ -340,7 +364,11 @@ for name in files: os.remove(join(root, name)) for name in dirs: - os.rmdir(join(root, name)) + dirname = join(root, name) + if not os.path.islink(dirname): + os.rmdir(dirname) + else: + os.remove(dirname) os.rmdir(test_support.TESTFN) class MakedirTests (unittest.TestCase): Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 21 10:10:29 2007 @@ -194,6 +194,10 @@ - Patch #1630118: add a SpooledTemporaryFile class to tempfile.py. +- Patch #1273829: os.walk() now has a "followlinks" parameter. If set to + True (which is not the default), it visits symlinks pointing to + directories. + - Bug #1681228: the webbrowser module now correctly uses the default GNOME or KDE browser, depending on whether there is a session of one of those present. Also, it tries the Windows default browser before From python-checkins at python.org Wed Mar 21 10:16:56 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 10:16:56 +0100 (CET) Subject: [Python-checkins] r54483 - python/trunk/Doc/api/utilities.tex Message-ID: <20070321091656.3B4F41E4006@bag.python.org> Author: georg.brandl Date: Wed Mar 21 10:16:53 2007 New Revision: 54483 Modified: python/trunk/Doc/api/utilities.tex Log: Patch #1684834: document some utility C API functions. Modified: python/trunk/Doc/api/utilities.tex ============================================================================== --- python/trunk/Doc/api/utilities.tex (original) +++ python/trunk/Doc/api/utilities.tex Wed Mar 21 10:16:53 2007 @@ -930,3 +930,94 @@ If there is an error in the format string, the \exception{SystemError} exception is set and \NULL{} returned. \end{cfuncdesc} + +\section{String conversion and formatting \label{string-formatting}} + +Functions for number conversion and formatted string output. + +\begin{cfuncdesc}{int}{PyOS_snprintf}{char *str, size_t size, + const char *format, \moreargs} +Output not more than \var{size} bytes to \var{str} according to the format +string \var{format} and the extra arguments. See the \UNIX{} man +page \manpage{snprintf}{2}. +\end{cfuncdesc} + +\begin{cfuncdesc}{int}{PyOS_vsnprintf}{char *str, size_t size, + const char *format, va_list va} +Output not more than \var{size} bytes to \var{str} according to the format +string \var{format} and the variable argument list \var{va}. \UNIX{} +man page \manpage{vsnprintf}{2}. +\end{cfuncdesc} + +\cfunction{PyOS_snprintf} and \cfunction{PyOS_vsnprintf} wrap the +Standard C library functions \cfunction{snprintf()} and +\cfunction{vsnprintf()}. Their purpose is to guarantee consistent +behavior in corner cases, which the Standard C functions do not. + +The wrappers ensure that \var{str}[\var{size}-1] is always +\character{\textbackslash0} upon return. They never write more than +\var{size} bytes (including the trailing \character{\textbackslash0} +into str. Both functions require that \code{\var{str} != NULL}, +\code{\var{size} > 0} and \code{\var{format} != NULL}. + +If the platform doesn't have \cfunction{vsnprintf()} and the buffer +size needed to avoid truncation exceeds \var{size} by more than 512 +bytes, Python aborts with a \var{Py_FatalError}. + +The return value (\var{rv}) for these functions should be interpreted +as follows: + +\begin{itemize} + +\item When \code{0 <= \var{rv} < \var{size}}, the output conversion + was successful and \var{rv} characters were written to \var{str} + (excluding the trailing \character{\textbackslash0} byte at + \var{str}[\var{rv}]). + +\item When \code{\var{rv} >= \var{size}}, the output conversion was + truncated and a buffer with \code{\var{rv} + 1} bytes would have + been needed to succeed. \var{str}[\var{size}-1] is + \character{\textbackslash0} in this case. + +\item When \code{\var{rv} < 0}, ``something bad happened.'' + \var{str}[\var{size}-1] is \character{\textbackslash0} in this case + too, but the rest of \var{str} is undefined. The exact cause of the + error depends on the underlying platform. + +\end{itemize} + +The following functions provide locale-independent string to number +conversions. + +\begin{cfuncdesc}{double}{PyOS_ascii_strtod}{const char *nptr, char **endptr} +Convert a string to a \ctype{double}. This function behaves like the +Standard C function \cfunction{strtod()} does in the C locale. It does +this without changing the current locale, since that would not be +thread-safe. + +\cfunction{PyOS_ascii_strtod} should typically be used for reading +configuration files or other non-user input that should be locale +independent. \versionadded{2.4} + +See the \UNIX{} man page \manpage{strtod}{2} for details. + +\end{cfuncdesc} + +\begin{cfuncdesc}{char *}{PyOS_ascii_formatd}{char *buffer, size_t buf_len, + const char *format, double d} +Convert a \ctype{double} to a string using the \character{.} as the +decimal separator. \var{format} is a \cfunction{printf()}-style format +string specifying the number format. Allowed conversion characters are +\character{e}, \character{E}, \character{f}, \character{F}, +\character{g} and \character{G}. + +The return value is a pointer to \var{buffer} with the converted +string or NULL if the conversion failed. \versionadded{2.4} +\end{cfuncdesc} + +\begin{cfuncdesc}{double}{PyOS_ascii_atof}{const char *nptr} +Convert a string to a \ctype{double} in a locale-independent +way. \versionadded{2.4} + +See the \UNIX{} man page \manpage{atof}{2} for details. +\end{cfuncdesc} From python-checkins at python.org Wed Mar 21 10:17:42 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 10:17:42 +0100 (CET) Subject: [Python-checkins] r54484 - python/branches/release25-maint/Doc/api/utilities.tex Message-ID: <20070321091742.4181C1E4006@bag.python.org> Author: georg.brandl Date: Wed Mar 21 10:17:36 2007 New Revision: 54484 Modified: python/branches/release25-maint/Doc/api/utilities.tex Log: Patch #1684834: document some utility C API functions. (backport from rev. 54483) Modified: python/branches/release25-maint/Doc/api/utilities.tex ============================================================================== --- python/branches/release25-maint/Doc/api/utilities.tex (original) +++ python/branches/release25-maint/Doc/api/utilities.tex Wed Mar 21 10:17:36 2007 @@ -930,3 +930,94 @@ If there is an error in the format string, the \exception{SystemError} exception is set and \NULL{} returned. \end{cfuncdesc} + +\section{String conversion and formatting \label{string-formatting}} + +Functions for number conversion and formatted string output. + +\begin{cfuncdesc}{int}{PyOS_snprintf}{char *str, size_t size, + const char *format, \moreargs} +Output not more than \var{size} bytes to \var{str} according to the format +string \var{format} and the extra arguments. See the \UNIX{} man +page \manpage{snprintf}{2}. +\end{cfuncdesc} + +\begin{cfuncdesc}{int}{PyOS_vsnprintf}{char *str, size_t size, + const char *format, va_list va} +Output not more than \var{size} bytes to \var{str} according to the format +string \var{format} and the variable argument list \var{va}. \UNIX{} +man page \manpage{vsnprintf}{2}. +\end{cfuncdesc} + +\cfunction{PyOS_snprintf} and \cfunction{PyOS_vsnprintf} wrap the +Standard C library functions \cfunction{snprintf()} and +\cfunction{vsnprintf()}. Their purpose is to guarantee consistent +behavior in corner cases, which the Standard C functions do not. + +The wrappers ensure that \var{str}[\var{size}-1] is always +\character{\textbackslash0} upon return. They never write more than +\var{size} bytes (including the trailing \character{\textbackslash0} +into str. Both functions require that \code{\var{str} != NULL}, +\code{\var{size} > 0} and \code{\var{format} != NULL}. + +If the platform doesn't have \cfunction{vsnprintf()} and the buffer +size needed to avoid truncation exceeds \var{size} by more than 512 +bytes, Python aborts with a \var{Py_FatalError}. + +The return value (\var{rv}) for these functions should be interpreted +as follows: + +\begin{itemize} + +\item When \code{0 <= \var{rv} < \var{size}}, the output conversion + was successful and \var{rv} characters were written to \var{str} + (excluding the trailing \character{\textbackslash0} byte at + \var{str}[\var{rv}]). + +\item When \code{\var{rv} >= \var{size}}, the output conversion was + truncated and a buffer with \code{\var{rv} + 1} bytes would have + been needed to succeed. \var{str}[\var{size}-1] is + \character{\textbackslash0} in this case. + +\item When \code{\var{rv} < 0}, ``something bad happened.'' + \var{str}[\var{size}-1] is \character{\textbackslash0} in this case + too, but the rest of \var{str} is undefined. The exact cause of the + error depends on the underlying platform. + +\end{itemize} + +The following functions provide locale-independent string to number +conversions. + +\begin{cfuncdesc}{double}{PyOS_ascii_strtod}{const char *nptr, char **endptr} +Convert a string to a \ctype{double}. This function behaves like the +Standard C function \cfunction{strtod()} does in the C locale. It does +this without changing the current locale, since that would not be +thread-safe. + +\cfunction{PyOS_ascii_strtod} should typically be used for reading +configuration files or other non-user input that should be locale +independent. \versionadded{2.4} + +See the \UNIX{} man page \manpage{strtod}{2} for details. + +\end{cfuncdesc} + +\begin{cfuncdesc}{char *}{PyOS_ascii_formatd}{char *buffer, size_t buf_len, + const char *format, double d} +Convert a \ctype{double} to a string using the \character{.} as the +decimal separator. \var{format} is a \cfunction{printf()}-style format +string specifying the number format. Allowed conversion characters are +\character{e}, \character{E}, \character{f}, \character{F}, +\character{g} and \character{G}. + +The return value is a pointer to \var{buffer} with the converted +string or NULL if the conversion failed. \versionadded{2.4} +\end{cfuncdesc} + +\begin{cfuncdesc}{double}{PyOS_ascii_atof}{const char *nptr} +Convert a string to a \ctype{double} in a locale-independent +way. \versionadded{2.4} + +See the \UNIX{} man page \manpage{atof}{2} for details. +\end{cfuncdesc} From buildbot at python.org Wed Mar 21 11:03:08 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 21 Mar 2007 10:03:08 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 2.5 Message-ID: <20070321100308.A5F681E4006@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%25202.5/builds/222 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket ====================================================================== FAIL: testInterruptedTimeout (test.test_socket.TCPTimeoutTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/net/ringneck/scratch1/nnorwitz/python/2.5.norwitz-tru64/build/Lib/test/test_socket.py", line 872, in testInterruptedTimeout self.fail("got Alarm in wrong place") AssertionError: got Alarm in wrong place sincerely, -The Buildbot From nnorwitz at gmail.com Wed Mar 21 11:38:43 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Wed, 21 Mar 2007 05:38:43 -0500 Subject: [Python-checkins] Python Regression Test Failures refleak (1) Message-ID: <20070321103843.GA25877@python.psfb.org> test_cmd_line leaked [-17, 0, 0] references test_sys leaked [0, 132, -132] references From amk at amk.ca Wed Mar 21 12:27:12 2007 From: amk at amk.ca (A.M. Kuchling) Date: Wed, 21 Mar 2007 07:27:12 -0400 Subject: [Python-checkins] r54466 - in python/branches/release25-maint: Include/setobject.h Lib/test/test_set.py Objects/dictobject.c Objects/setobject.c In-Reply-To: <200703211506.45707.anthony@interlink.com.au> References: <20070320214505.D8DDA1E400B@bag.python.org> <200703211506.45707.anthony@interlink.com.au> Message-ID: <20070321112712.GA5208@andrew-kuchlings-computer.local> On Wed, Mar 21, 2007 at 03:06:44PM +1100, Anthony Baxter wrote: > Why is new behaviour and a new C API being added to Python 2.5??? -PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **entry); +PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, PyObject **key); +PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, long *hash); Isn't the new function is Python-internal, not part of the official API, because of the leading underscore? --amk From python-checkins at python.org Wed Mar 21 12:51:29 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 12:51:29 +0100 (CET) Subject: [Python-checkins] r54485 - python/trunk/Lib/webbrowser.py Message-ID: <20070321115129.7BD2C1E4002@bag.python.org> Author: georg.brandl Date: Wed Mar 21 12:51:25 2007 New Revision: 54485 Modified: python/trunk/Lib/webbrowser.py Log: Fix #1684254: split BROWSER contents with shlex to avoid displaying 'URL'. Modified: python/trunk/Lib/webbrowser.py ============================================================================== --- python/trunk/Lib/webbrowser.py (original) +++ python/trunk/Lib/webbrowser.py Wed Mar 21 12:51:25 2007 @@ -2,6 +2,7 @@ """Interfaces for launching and remotely controlling Web browsers.""" import os +import shlex import sys import stat import subprocess @@ -32,7 +33,11 @@ for browser in alternatives: if '%s' in browser: # User gave us a command line, split it into name and args - return GenericBrowser(browser.split()) + browser = shlex.split(browser) + if browser[-1] == '&': + return BackgroundBrowser(browser[:-1]) + else: + return GenericBrowser(browser) else: # User gave us a browser name or path. try: From python-checkins at python.org Wed Mar 21 12:52:42 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 12:52:42 +0100 (CET) Subject: [Python-checkins] r54486 - in python/branches/release25-maint: Lib/webbrowser.py Misc/NEWS Message-ID: <20070321115242.2C2421E4006@bag.python.org> Author: georg.brandl Date: Wed Mar 21 12:52:38 2007 New Revision: 54486 Modified: python/branches/release25-maint/Lib/webbrowser.py python/branches/release25-maint/Misc/NEWS Log: Bug #1684254: webbrowser now uses shlex to split any command lines given to get(). It also detects when you use '&' as the last argument and creates a BackgroundBrowser then. (backport) Modified: python/branches/release25-maint/Lib/webbrowser.py ============================================================================== --- python/branches/release25-maint/Lib/webbrowser.py (original) +++ python/branches/release25-maint/Lib/webbrowser.py Wed Mar 21 12:52:38 2007 @@ -2,6 +2,7 @@ """Interfaces for launching and remotely controlling Web browsers.""" import os +import shlex import sys import stat import subprocess @@ -32,7 +33,11 @@ for browser in alternatives: if '%s' in browser: # User gave us a command line, split it into name and args - return GenericBrowser(browser.split()) + browser = shlex.split(browser) + if browser[-1] == '&': + return BackgroundBrowser(browser[:-1]) + else: + return GenericBrowser(browser) else: # User gave us a browser name or path. try: Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Wed Mar 21 12:52:38 2007 @@ -217,6 +217,10 @@ Library ------- +- Bug #1684254: webbrowser now uses shlex to split any command lines + given to get(). It also detects when you use '&' as the last argument + and creates a BackgroundBrowser then. + - Patch #1681153: the wave module now closes a file object it opened if initialization failed. From python-checkins at python.org Wed Mar 21 12:53:44 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 12:53:44 +0100 (CET) Subject: [Python-checkins] r54486 - svn:log Message-ID: <20070321115344.CB0211E4002@bag.python.org> Author: georg.brandl Revision: 54486 Property Name: svn:log New Property Value: Bug #1684254: webbrowser now uses shlex to split any command lines given to get(). It also detects when you use '&' as the last argument and creates a BackgroundBrowser then. (backport -- this is a regression from 2.4 and therefore backported) From buildbot at python.org Wed Mar 21 14:49:23 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 21 Mar 2007 13:49:23 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper 2.5 Message-ID: <20070321134923.8C9111E4002@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%25202.5/builds/74 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From buildbot at python.org Wed Mar 21 15:29:36 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 21 Mar 2007 14:29:36 +0000 Subject: [Python-checkins] buildbot warnings in hppa Ubuntu dapper trunk Message-ID: <20070321142936.6BC571E4006@bag.python.org> The Buildbot has detected a new failure of hppa Ubuntu dapper trunk. Full details are available at: http://www.python.org/dev/buildbot/all/hppa%2520Ubuntu%2520dapper%2520trunk/builds/158 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: georg.brandl Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Wed Mar 21 15:32:45 2007 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 21 Mar 2007 15:32:45 +0100 (CET) Subject: [Python-checkins] r54487 - python/trunk/Doc/whatsnew/whatsnew26.tex Message-ID: <20070321143245.13F081E4006@bag.python.org> Author: andrew.kuchling Date: Wed Mar 21 15:32:43 2007 New Revision: 54487 Modified: python/trunk/Doc/whatsnew/whatsnew26.tex Log: Add comments on maintenance of this file Modified: python/trunk/Doc/whatsnew/whatsnew26.tex ============================================================================== --- python/trunk/Doc/whatsnew/whatsnew26.tex (original) +++ python/trunk/Doc/whatsnew/whatsnew26.tex Wed Mar 21 15:32:43 2007 @@ -2,6 +2,46 @@ \usepackage{distutils} % $Id$ +% Rules for maintenance: +% +% * Anyone can add text to this document. Do not spend very much time +% on the wording of your changes, because your text will probably +% get rewritten to some degree. +% +% * The maintainer will go through Misc/NEWS periodically and add +% changes; it's therefore more important to add your changes to +% Misc/NEWS than to this file. +% +% * This is not a complete list of every single change; completeness +% is the purpose of Misc/NEWS. Some changes I consider too small +% or esoteric to include. If such a change is added to the text, +% I'll just remove it. (This is another reason you shouldn't spend +% too much time on writing your addition.) +% +% * If you want to draw your new text to the attention of the +% maintainer, add 'XXX' to the beginning of the paragraph or +% section. +% +% * It's OK to just add a fragmentary note about a change. For +% example: "XXX Describe the transmogrify() function added to the +% socket module." The maintainer will research the change and +% write the necessary text. +% +% * You can comment out your additions if you like, but it's not +% necessary (especially when a final release is some months away). +% +% * Credit the author of a patch or bugfix. Just the name is +% sufficient; the e-mail address isn't necessary. +% +% * It's helpful to add the bug/patch number as a comment: +% +% % Patch 12345 +% XXX Describe the transmogrify() function added to the socket +% module. +% (Contributed by P.Y. Developer.) +% +% This saves the maintainer the effort of going through the SVN log +% when researching a change. \title{What's New in Python 2.6} \release{0.0} From thomas at python.org Wed Mar 21 15:50:27 2007 From: thomas at python.org (Thomas Wouters) Date: Wed, 21 Mar 2007 15:50:27 +0100 Subject: [Python-checkins] r54464 - python/branches/release25-maint/Doc/lib/libitertools.tex In-Reply-To: <20070320211224.ED4471E4006@bag.python.org> References: <20070320211224.ED4471E4006@bag.python.org> Message-ID: <9e804ac0703210750l7d47d4b9u7e9fccd60665ca8f@mail.gmail.com> On 3/20/07, raymond.hettinger wrote: > > Author: raymond.hettinger > Date: Tue Mar 20 22:12:23 2007 > New Revision: 54464 > > Modified: > python/branches/release25-maint/Doc/lib/libitertools.tex > Log: > Add new example > > Modified: python/branches/release25-maint/Doc/lib/libitertools.tex > > ============================================================================== > --- python/branches/release25-maint/Doc/lib/libitertools.tex (original) > +++ python/branches/release25-maint/Doc/lib/libitertools.tex Tue Mar 20 > 22:12:23 2007 > @@ -539,5 +539,8 @@ > "grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), > ('g','x','x')" > return izip(*[chain(iterable, repeat(padvalue, n-1))]*n) > > +def reverse_map(d): > + "Return a new dict with swapped keys and values" > + return dict(izip(d.itervalues(), d)) Should we be advocating code that (rather implicitly) relies on a dict not changing ordering between calls (not to mention different calls)? (It strikes me as rather bad style, and fragile to boot, but the example isn't as readable without it :) -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20070321/b3c80862/attachment.htm From anthony at interlink.com.au Wed Mar 21 16:08:52 2007 From: anthony at interlink.com.au (Anthony Baxter) Date: Thu, 22 Mar 2007 02:08:52 +1100 Subject: [Python-checkins] r54466 - in python/branches/release25-maint: Include/setobject.h Lib/test/test_set.py Objects/dictobject.c Objects/setobject.c In-Reply-To: <20070321112712.GA5208@andrew-kuchlings-computer.local> References: <20070320214505.D8DDA1E400B@bag.python.org> <200703211506.45707.anthony@interlink.com.au> <20070321112712.GA5208@andrew-kuchlings-computer.local> Message-ID: <200703220208.56255.anthony@interlink.com.au> On Wednesday 21 March 2007 22:27, A.M. Kuchling wrote: > On Wed, Mar 21, 2007 at 03:06:44PM +1100, Anthony Baxter wrote: > > Why is new behaviour and a new C API being added to Python > > 2.5??? > > -PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, > PyObject **entry); +PyAPI_FUNC(int) _PySet_Next(PyObject *set, > Py_ssize_t *pos, PyObject **key); +PyAPI_FUNC(int) > _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, > long *hash); > > Isn't the new function is Python-internal, not part of the > official API, because of the leading underscore? Unless I'm mistaken, it's also adding the ability to pass a set to the dict constructor. -- Anthony Baxter It's never too late to have a happy childhood. From thomas at python.org Wed Mar 21 17:35:52 2007 From: thomas at python.org (Thomas Wouters) Date: Wed, 21 Mar 2007 17:35:52 +0100 Subject: [Python-checkins] r54466 - in python/branches/release25-maint: Include/setobject.h Lib/test/test_set.py Objects/dictobject.c Objects/setobject.c In-Reply-To: <200703220208.56255.anthony@interlink.com.au> References: <20070320214505.D8DDA1E400B@bag.python.org> <200703211506.45707.anthony@interlink.com.au> <20070321112712.GA5208@andrew-kuchlings-computer.local> <200703220208.56255.anthony@interlink.com.au> Message-ID: <9e804ac0703210935o647f77c0m4e074c4289175d8f@mail.gmail.com> On 3/21/07, Anthony Baxter wrote: > > On Wednesday 21 March 2007 22:27, A.M. Kuchling wrote: > > On Wed, Mar 21, 2007 at 03:06:44PM +1100, Anthony Baxter wrote: > > > Why is new behaviour and a new C API being added to Python > > > 2.5??? > > > > -PyAPI_FUNC(int) _PySet_Next(PyObject *set, Py_ssize_t *pos, > > PyObject **entry); +PyAPI_FUNC(int) _PySet_Next(PyObject *set, > > Py_ssize_t *pos, PyObject **key); +PyAPI_FUNC(int) > > _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, > > long *hash); > > > > Isn't the new function is Python-internal, not part of the > > official API, because of the leading underscore? > > Unless I'm mistaken, it's also adding the ability to pass a set to > the dict constructor. No, I don't believe it does; it just specialcases dict.fromkeys(some_set) for performance, not for added functionality. I still do not think this should be done in Python 2.5, though: it's not a bugfix, and adding such performance enhancements is prone to introducing bugs. -- Thomas Wouters Hi! I'm a .signature virus! copy me into your .signature file to help me spread! -------------- next part -------------- An HTML attachment was scrubbed... URL: http://mail.python.org/pipermail/python-checkins/attachments/20070321/c9d1ce08/attachment.htm From python-checkins at python.org Wed Mar 21 17:53:11 2007 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 21 Mar 2007 17:53:11 +0100 (CET) Subject: [Python-checkins] r54488 - python/branches/release25-maint/Misc/NEWS Message-ID: <20070321165311.D60DC1E4010@bag.python.org> Author: andrew.kuchling Date: Wed Mar 21 17:52:51 2007 New Revision: 54488 Modified: python/branches/release25-maint/Misc/NEWS Log: Add NEWS entry for old item Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Wed Mar 21 17:52:51 2007 @@ -380,7 +380,10 @@ - mailbox.py: Change MH.pack() to not lock individual message files; this wasn't consistent with existing implementations of message packing, and was buggy on some platforms. - + +- Bug #1633678: change old mailbox.UnixMailbox class to parse + 'From' lines less strictly. + - Bug #1576241: fix functools.wraps() to work on built-in functions. - Patch #1574068: fix urllib/urllib2 to not insert line breaks when From python at rcn.com Wed Mar 21 17:56:12 2007 From: python at rcn.com (Raymond Hettinger) Date: Wed, 21 Mar 2007 12:56:12 -0400 (EDT) Subject: [Python-checkins] r54466 - in python/branches/release25-maint: Include/setobject.h Lib/test/test_set.py Objects/dictobject.c Objects/setobject.c Message-ID: <20070321125612.BCF81449@ms09.lnh.mail.rcn.net> > No, I don't believe it does; it just specialcases > dict.fromkeys(some_set) for performance, not for added functionality. In Py2.5 sets are not supposed to call PyObject_Hash unnecessarily. This checkin fixes one that I had missed and completes that promise. Is is an important part of what Py2.5 sets were supposed to do (or not do). Raymond From python-checkins at python.org Wed Mar 21 17:57:36 2007 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 21 Mar 2007 17:57:36 +0100 (CET) Subject: [Python-checkins] r54489 - python/trunk/Doc/lib/libcollections.tex Message-ID: <20070321165736.1B6441E4007@bag.python.org> Author: andrew.kuchling Date: Wed Mar 21 17:57:32 2007 New Revision: 54489 Modified: python/trunk/Doc/lib/libcollections.tex Log: Fix sentence, and fix typo in example Modified: python/trunk/Doc/lib/libcollections.tex ============================================================================== --- python/trunk/Doc/lib/libcollections.tex (original) +++ python/trunk/Doc/lib/libcollections.tex Wed Mar 21 17:57:32 2007 @@ -377,12 +377,13 @@ The use cases are the same as those for tuples. The named factories assign meaning to each tuple position and allow for more readable, - self-documenting code. Can also be used to assign field names to tuples + self-documenting code. Named tuples can also be used to assign field names + to tuples returned by the \module{csv} or \module{sqlite3} modules. For example: \begin{verbatim} import csv - EmployeeRecord = NamedTuple('EmployeeRecord', 'name age title deparment paygrade') + EmployeeRecord = NamedTuple('EmployeeRecord', 'name age title department paygrade') for tup in csv.reader(open("employees.csv", "rb")): print EmployeeRecord(*tup) \end{verbatim} From python-checkins at python.org Wed Mar 21 17:59:24 2007 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 21 Mar 2007 17:59:24 +0100 (CET) Subject: [Python-checkins] r54490 - python/trunk/Doc/lib/libcollections.tex Message-ID: <20070321165924.801B41E4007@bag.python.org> Author: andrew.kuchling Date: Wed Mar 21 17:59:20 2007 New Revision: 54490 Modified: python/trunk/Doc/lib/libcollections.tex Log: Put code examples at left margin instead of indenting them Modified: python/trunk/Doc/lib/libcollections.tex ============================================================================== --- python/trunk/Doc/lib/libcollections.tex (original) +++ python/trunk/Doc/lib/libcollections.tex Wed Mar 21 17:59:20 2007 @@ -360,20 +360,20 @@ Example: \begin{verbatim} - >>> Point = NamedTuple('Point', 'x y') - >>> Point.__doc__ # docstring for the new datatype - 'Point(x, y)' - >>> p = Point(11, y=22) # instantiate with positional or keyword arguments - >>> p[0] + p[1] # works just like the tuple (11, 22) - 33 - >>> x, y = p # unpacks just like a tuple - >>> x, y - (11, 22) - >>> p.x + p.y # fields also accessable by name - 33 - >>> p # readable __repr__ with name=value style - Point(x=11, y=22) - \end{verbatim} +>>> Point = NamedTuple('Point', 'x y') +>>> Point.__doc__ # docstring for the new datatype +'Point(x, y)' +>>> p = Point(11, y=22) # instantiate with positional or keyword arguments +>>> p[0] + p[1] # works just like the tuple (11, 22) +33 +>>> x, y = p # unpacks just like a tuple +>>> x, y +(11, 22) +>>> p.x + p.y # fields also accessable by name +33 +>>> p # readable __repr__ with name=value style +Point(x=11, y=22) +\end{verbatim} The use cases are the same as those for tuples. The named factories assign meaning to each tuple position and allow for more readable, @@ -382,10 +382,10 @@ returned by the \module{csv} or \module{sqlite3} modules. For example: \begin{verbatim} - import csv - EmployeeRecord = NamedTuple('EmployeeRecord', 'name age title department paygrade') - for tup in csv.reader(open("employees.csv", "rb")): - print EmployeeRecord(*tup) - \end{verbatim} +import csv +EmployeeRecord = NamedTuple('EmployeeRecord', 'name age title department paygrade') +for tup in csv.reader(open("employees.csv", "rb")): + print EmployeeRecord(*tup) +\end{verbatim} \end{funcdesc} From python-checkins at python.org Wed Mar 21 20:41:28 2007 From: python-checkins at python.org (facundo.batista) Date: Wed, 21 Mar 2007 20:41:28 +0100 (CET) Subject: [Python-checkins] r54491 - python/trunk/Doc/lib/libsocket.tex Message-ID: <20070321194128.D75EF1E4007@bag.python.org> Author: facundo.batista Date: Wed Mar 21 20:41:24 2007 New Revision: 54491 Modified: python/trunk/Doc/lib/libsocket.tex Log: Minor clarification, saying that blocking means no timeout (from bug #882297) Modified: python/trunk/Doc/lib/libsocket.tex ============================================================================== --- python/trunk/Doc/lib/libsocket.tex (original) +++ python/trunk/Doc/lib/libsocket.tex Wed Mar 21 20:41:24 2007 @@ -548,7 +548,7 @@ The file object references a \cfunction{dup()}ped version of the socket file descriptor, so the file object and socket object may be closed or garbage-collected independently. -The socket must be in blocking mode. +The socket must be in blocking mode (it can not have a timeout). \index{I/O control!buffering}The optional \var{mode} and \var{bufsize} arguments are interpreted the same way as by the built-in \function{file()} function; see ``Built-in Functions'' From python-checkins at python.org Wed Mar 21 21:08:00 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Wed, 21 Mar 2007 21:08:00 +0100 (CET) Subject: [Python-checkins] r54492 - in python/trunk: Lib/sre.py Lib/test/test_re.py Misc/NEWS Message-ID: <20070321200800.2E36A1E4010@bag.python.org> Author: ziga.seilnacht Date: Wed Mar 21 21:07:56 2007 New Revision: 54492 Modified: python/trunk/Lib/sre.py python/trunk/Lib/test/test_re.py python/trunk/Misc/NEWS Log: Bug #1675967: re patterns pickled with older Python versions can now be unpickled. Will backport. Modified: python/trunk/Lib/sre.py ============================================================================== --- python/trunk/Lib/sre.py (original) +++ python/trunk/Lib/sre.py Wed Mar 21 21:07:56 2007 @@ -8,3 +8,6 @@ from re import * from re import __all__ + +# old pickles expect the _compile() reconstructor in this module +from re import _compile Modified: python/trunk/Lib/test/test_re.py ============================================================================== --- python/trunk/Lib/test/test_re.py (original) +++ python/trunk/Lib/test/test_re.py Wed Mar 21 21:07:56 2007 @@ -1,7 +1,7 @@ import sys sys.path = ['.'] + sys.path -from test.test_support import verbose, run_unittest +from test.test_support import verbose, run_unittest, guard_warnings_filter import re from re import Scanner import sys, os, traceback @@ -414,6 +414,12 @@ self.pickle_test(pickle) import cPickle self.pickle_test(cPickle) + # old pickles expect the _compile() reconstructor in sre module + import warnings + with guard_warnings_filter(): + warnings.filterwarnings("ignore", "The sre module is deprecated", + DeprecationWarning) + from sre import _compile def pickle_test(self, pickle): oldpat = re.compile('a(?:b|(c|e){1,2}?|d)+?(.)') Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Wed Mar 21 21:07:56 2007 @@ -192,6 +192,9 @@ Library ------- +- Bug #1675967: re patterns pickled with Python 2.4 and earlier can + now be unpickled with Python 2.5 and newer. + - Patch #1630118: add a SpooledTemporaryFile class to tempfile.py. - Patch #1273829: os.walk() now has a "followlinks" parameter. If set to From python-checkins at python.org Wed Mar 21 21:15:09 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 21:15:09 +0100 (CET) Subject: [Python-checkins] r54494 - peps/trunk/pep-3100.txt Message-ID: <20070321201509.31D761E400C@bag.python.org> Author: collin.winter Date: Wed Mar 21 21:15:07 2007 New Revision: 54494 Modified: peps/trunk/pep-3100.txt Log: Mark the removal of isCallable() and sequenceIncludes() from operator as 'done'. Modified: peps/trunk/pep-3100.txt ============================================================================== --- peps/trunk/pep-3100.txt (original) +++ peps/trunk/pep-3100.txt Wed Mar 21 21:15:07 2007 @@ -225,9 +225,9 @@ functionality [24]_ [#pep3110]_ [#sys-module]_ * ``array.read``, ``array.write`` [#array-module]_ * ``operator.isCallable`` : ``callable()`` built-in is being removed - [#operator-module]_ + [#operator-module]_ [#remove-operator-funcs]_ [done] * ``operator.sequenceIncludes`` : redundant thanks to - ``operator.contains`` [#operator-module]_ + ``operator.contains`` [#operator-module]_ [#remove-operator-funcs]_ [done] * In the thread module, the aquire_lock() and release_lock() aliases for the acquire() and release() methods on lock objects. (Probably also just remove the thread module as a public API, @@ -390,6 +390,9 @@ .. [#exitfunc-patch] Patch to remove sys.exitfunc http://www.python.org/sf/1680961 + +.. [#remove-operator-funcs] Remove deprecated functions from operator + http://www.python.org/sf/1516309 Copyright ========= From python-checkins at python.org Wed Mar 21 21:34:01 2007 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 21 Mar 2007 21:34:01 +0100 (CET) Subject: [Python-checkins] r54495 - in python/trunk: Lib/test/test_set.py Objects/dictobject.c Message-ID: <20070321203401.C3EB41E4010@bag.python.org> Author: raymond.hettinger Date: Wed Mar 21 21:33:57 2007 New Revision: 54495 Modified: python/trunk/Lib/test/test_set.py python/trunk/Objects/dictobject.c Log: Add test and fix for fromkeys() optional argument. Modified: python/trunk/Lib/test/test_set.py ============================================================================== --- python/trunk/Lib/test/test_set.py (original) +++ python/trunk/Lib/test/test_set.py Wed Mar 21 21:33:57 2007 @@ -293,6 +293,9 @@ self.assertEqual(sum(elem.hash_count for elem in d), n) d3 = dict.fromkeys(frozenset(d)) self.assertEqual(sum(elem.hash_count for elem in d), n) + d3 = dict.fromkeys(frozenset(d), 123) + self.assertEqual(sum(elem.hash_count for elem in d), n) + self.assertEqual(d3, dict.fromkeys(d, 123)) class TestSet(TestJointOps): thetype = set Modified: python/trunk/Objects/dictobject.c ============================================================================== --- python/trunk/Objects/dictobject.c (original) +++ python/trunk/Objects/dictobject.c Wed Mar 21 21:33:57 2007 @@ -1186,8 +1186,8 @@ while (_PySet_NextEntry(seq, &pos, &key, &hash)) { Py_INCREF(key); - Py_INCREF(Py_None); - if (insertdict(mp, key, hash, Py_None)) + Py_INCREF(value); + if (insertdict(mp, key, hash, value)) return NULL; } return d; From python-checkins at python.org Wed Mar 21 21:36:54 2007 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 21 Mar 2007 21:36:54 +0100 (CET) Subject: [Python-checkins] r54496 - in python/branches/release25-maint: Lib/test/test_set.py Objects/dictobject.c Message-ID: <20070321203654.5591C1E400D@bag.python.org> Author: raymond.hettinger Date: Wed Mar 21 21:36:45 2007 New Revision: 54496 Modified: python/branches/release25-maint/Lib/test/test_set.py python/branches/release25-maint/Objects/dictobject.c Log: Test and fix fromkeys optional argument. Modified: python/branches/release25-maint/Lib/test/test_set.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_set.py (original) +++ python/branches/release25-maint/Lib/test/test_set.py Wed Mar 21 21:36:45 2007 @@ -293,6 +293,9 @@ self.assertEqual(sum(elem.hash_count for elem in d), n) d3 = dict.fromkeys(frozenset(d)) self.assertEqual(sum(elem.hash_count for elem in d), n) + d3 = dict.fromkeys(frozenset(d), 123) + self.assertEqual(sum(elem.hash_count for elem in d), n) + self.assertEqual(d3, dict.fromkeys(d, 123)) class TestSet(TestJointOps): thetype = set Modified: python/branches/release25-maint/Objects/dictobject.c ============================================================================== --- python/branches/release25-maint/Objects/dictobject.c (original) +++ python/branches/release25-maint/Objects/dictobject.c Wed Mar 21 21:36:45 2007 @@ -1186,8 +1186,8 @@ while (_PySet_NextEntry(seq, &pos, &key, &hash)) { Py_INCREF(key); - Py_INCREF(Py_None); - if (insertdict(mp, key, hash, Py_None)) + Py_INCREF(value); + if (insertdict(mp, key, hash, value)) return NULL; } return d; From python-checkins at python.org Wed Mar 21 21:37:43 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Wed, 21 Mar 2007 21:37:43 +0100 (CET) Subject: [Python-checkins] r54497 - in python/branches/release25-maint: Lib/sre.py Lib/test/test_re.py Misc/NEWS Message-ID: <20070321203743.6A12A1E4014@bag.python.org> Author: ziga.seilnacht Date: Wed Mar 21 21:37:39 2007 New Revision: 54497 Modified: python/branches/release25-maint/Lib/sre.py python/branches/release25-maint/Lib/test/test_re.py python/branches/release25-maint/Misc/NEWS Log: Bug #1675967: re patterns pickled with older Python versions can now be unpickled. (backport form rev. 54492) Modified: python/branches/release25-maint/Lib/sre.py ============================================================================== --- python/branches/release25-maint/Lib/sre.py (original) +++ python/branches/release25-maint/Lib/sre.py Wed Mar 21 21:37:39 2007 @@ -8,3 +8,6 @@ from re import * from re import __all__ + +# old pickles expect the _compile() reconstructor in this module +from re import _compile Modified: python/branches/release25-maint/Lib/test/test_re.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_re.py (original) +++ python/branches/release25-maint/Lib/test/test_re.py Wed Mar 21 21:37:39 2007 @@ -414,6 +414,15 @@ self.pickle_test(pickle) import cPickle self.pickle_test(cPickle) + # old pickles expect the _compile() reconstructor in sre module + import warnings + original_filters = warnings.filters[:] + try: + warnings.filterwarnings("ignore", "The sre module is deprecated", + DeprecationWarning) + from sre import _compile + finally: + warnings.filters = original_filters def pickle_test(self, pickle): oldpat = re.compile('a(?:b|(c|e){1,2}?|d)+?(.)') Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Wed Mar 21 21:37:39 2007 @@ -217,6 +217,9 @@ Library ------- +- Bug #1675967: re patterns pickled with Python 2.4 and earlier can + now be unpickled with Python 2.5. + - Bug #1684254: webbrowser now uses shlex to split any command lines given to get(). It also detects when you use '&' as the last argument and creates a BackgroundBrowser then. From python-checkins at python.org Wed Mar 21 21:56:36 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 21:56:36 +0100 (CET) Subject: [Python-checkins] r54498 - in sandbox/trunk/2to3: pytree.py tests/test_pytree.py Message-ID: <20070321205636.E5C681E4011@bag.python.org> Author: collin.winter Date: Wed Mar 21 21:56:31 2007 New Revision: 54498 Modified: sandbox/trunk/2to3/pytree.py sandbox/trunk/2to3/tests/test_pytree.py Log: Add a prefix keyword argument to Node and Leaf constructors. Modified: sandbox/trunk/2to3/pytree.py ============================================================================== --- sandbox/trunk/2to3/pytree.py (original) +++ sandbox/trunk/2to3/pytree.py Wed Mar 21 21:56:31 2007 @@ -137,7 +137,7 @@ """Concrete implementation for interior nodes.""" - def __init__(self, type, children, context=None): + def __init__(self, type, children, context=None, prefix=None): """Initializer. Takes a type constant (a symbol number >= 256), a sequence of @@ -151,6 +151,8 @@ for ch in self.children: assert ch.parent is None, repr(ch) ch.parent = self + if prefix is not None: + self.set_prefix(prefix) def __repr__(self): """Returns a canonical string representation.""" @@ -207,7 +209,7 @@ lineno = 0 # Line where this token starts in the input column = 0 # Column where this token tarts in the input - def __init__(self, type, value, context=None): + def __init__(self, type, value, context=None, prefix=None): """Initializer. Takes a type constant (a token number < 256), a string value, @@ -218,6 +220,8 @@ self.prefix, (self.lineno, self.column) = context self.type = type self.value = value + if prefix is not None: + self.prefix = prefix def __repr__(self): """Returns a canonical string representation.""" Modified: sandbox/trunk/2to3/tests/test_pytree.py ============================================================================== --- sandbox/trunk/2to3/tests/test_pytree.py (original) +++ sandbox/trunk/2to3/tests/test_pytree.py Wed Mar 21 21:56:31 2007 @@ -163,6 +163,22 @@ self.failUnless(n1.was_changed) self.failUnless(n2.was_changed) self.failIf(l1.was_changed) + + def testLeafConstructorPrefix(self): + for prefix in ("xyz_", ""): + l1 = pytree.Leaf(100, "self", prefix=prefix) + self.failUnless(str(l1), prefix + "self") + self.assertEqual(l1.get_prefix(), prefix) + + def testNodeConstructorPrefix(self): + for prefix in ("xyz_", ""): + l1 = pytree.Leaf(100, "self") + l2 = pytree.Leaf(100, "foo", prefix="_") + n1 = pytree.Node(1000, [l1, l2], prefix=prefix) + self.failUnless(str(n1), prefix + "self_foo") + self.assertEqual(n1.get_prefix(), prefix) + self.assertEqual(l1.get_prefix(), prefix) + self.assertEqual(l2.get_prefix(), "_") class TestPatterns(support.TestCase): From buildbot at python.org Wed Mar 21 22:01:11 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 21 Mar 2007 21:01:11 +0000 Subject: [Python-checkins] buildbot warnings in x86 W2k trunk Message-ID: <20070321210111.E9CB11E4007@bag.python.org> The Buildbot has detected a new failure of x86 W2k trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520W2k%2520trunk/builds/147 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: raymond.hettinger Build had warnings: warnings test Excerpt from the test logfile: 7 tests failed: test_class test_frozen test_os test_posixpath test_pyexpat test_urllib test_winreg ====================================================================== ERROR: test_makedir (test.test_os.MakedirTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 376, in setUp os.mkdir(test_support.TESTFN) WindowsError: [Error 183] Cannot create a file when that file already exists: '@test' ====================================================================== ERROR: test_access (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 443, in test_access self.assertRaises(WindowsError, os.utime, test_support.TESTFN, 0) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\unittest.py", line 329, in failUnlessRaises callableObj(*args, **kwargs) TypeError: utime() arg 2 must be a tuple (atime, mtime) ====================================================================== FAIL: test_traversal (test.test_os.WalkTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 313, in test_traversal self.assertEqual(len(all), 4) AssertionError: 5 != 4 ====================================================================== FAIL: test_chdir (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 434, in test_chdir self.assertRaises(WindowsError, os.chdir, test_support.TESTFN) AssertionError: WindowsError not raised ====================================================================== FAIL: test_relpath (test.test_posixpath.PosixPathTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_posixpath.py", line 486, in test_relpath self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a") AssertionError: 'C:\\trentm\\data\\buildbot\\python-slave\\trunk.mick-windows\\build\\PCbuild\\@test\\@test\\a' != 'a' sincerely, -The Buildbot From python-checkins at python.org Wed Mar 21 22:08:56 2007 From: python-checkins at python.org (georg.brandl) Date: Wed, 21 Mar 2007 22:08:56 +0100 (CET) Subject: [Python-checkins] r54499 - sandbox/trunk/2to3/fixes/fix_numliterals.py Message-ID: <20070321210856.464411E4007@bag.python.org> Author: georg.brandl Date: Wed Mar 21 22:08:52 2007 New Revision: 54499 Added: sandbox/trunk/2to3/fixes/fix_numliterals.py Log: A fixer for numeric literals. Added: sandbox/trunk/2to3/fixes/fix_numliterals.py ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/fixes/fix_numliterals.py Wed Mar 21 22:08:52 2007 @@ -0,0 +1,41 @@ +"""Fixer that turns 1L into 1, 0755 into 0o755, +0XABC into 0xABC, 1E5 into 1e5, 1J into 1j. + +This is so simple that we don't need the pattern compiler. +""" + +# Local imports +import pytree +from pgen2 import token +from fixes import basefix + + +class FixNumliterals(basefix.BaseFix): + + def compile_pattern(self): + # Override + pass + + def match(self, node): + # Override + return (node.type == token.NUMBER and + (node.value.startswith("0") or + 'E' in node.value or + 'J' in node.value)) + + def transform(self, node): + val = node.value + if val[-1] in 'Ll': + val = val[:-1] + if 'J' in val: + val = val.replace('J', 'j') + if 'E' in val: + val = val.replace('E', 'e') + if val.startswith('0X'): + val = '0x' + val[2:] + elif val.startswith('0') and val.isdigit() and len(set(val)) > 1: + val = "0o" + val[1:] + + new = pytree.Leaf(token.NUMBER, val) + new.set_prefix(node.get_prefix()) + return new From python-checkins at python.org Wed Mar 21 22:17:52 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 22:17:52 +0100 (CET) Subject: [Python-checkins] r54500 - sandbox/trunk/2to3/fixes/util.py Message-ID: <20070321211752.EA2C71E4007@bag.python.org> Author: collin.winter Date: Wed Mar 21 22:17:48 2007 New Revision: 54500 Modified: sandbox/trunk/2to3/fixes/util.py Log: Have Name() and Number() take advantage of Leaf's prefix keyword arg. Modified: sandbox/trunk/2to3/fixes/util.py ============================================================================== --- sandbox/trunk/2to3/fixes/util.py (original) +++ sandbox/trunk/2to3/fixes/util.py Wed Mar 21 22:17:48 2007 @@ -25,11 +25,9 @@ return Node(syms.atom, target + (ass_leaf.clone(),) + source) -def Name(name, prefix=""): +def Name(name, prefix=None): """Return a NAME leaf""" - l = Leaf(token.NAME, name) - l.set_prefix(prefix) - return l + return Leaf(token.NAME, name, prefix=prefix) def Attr(obj, attr): """A node tuple for obj.attr""" @@ -56,8 +54,8 @@ """A newline literal""" return Leaf(token.NEWLINE, "\n") -def Number(n): - return Leaf(token.NUMBER, n) +def Number(n, prefix=None): + return Leaf(token.NUMBER, n, prefix=prefix) def Subscript(index_node): """A numeric or string subscript""" From python-checkins at python.org Wed Mar 21 22:21:04 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 22:21:04 +0100 (CET) Subject: [Python-checkins] r54501 - sandbox/trunk/2to3/fixes/fix_print.py sandbox/trunk/2to3/fixes/util.py Message-ID: <20070321212104.98A431E4007@bag.python.org> Author: collin.winter Date: Wed Mar 21 22:20:59 2007 New Revision: 54501 Modified: sandbox/trunk/2to3/fixes/fix_print.py sandbox/trunk/2to3/fixes/util.py Log: Add a String() leaf construction macro. Modified: sandbox/trunk/2to3/fixes/fix_print.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_print.py (original) +++ sandbox/trunk/2to3/fixes/fix_print.py Wed Mar 21 22:20:59 2007 @@ -14,7 +14,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.util import Name, Call, Comma +from fixes.util import Name, Call, Comma, String class FixPrint(basefix.BaseFix): @@ -56,11 +56,9 @@ l_args[0].set_prefix("") if sep is not None or end is not None or file is not None: if sep is not None: - self.add_kwarg(l_args, "sep", - pytree.Leaf(token.STRING, repr(sep))) + self.add_kwarg(l_args, "sep", String(repr(sep))) if end is not None: - self.add_kwarg(l_args, "end", - pytree.Leaf(token.STRING, repr(end))) + self.add_kwarg(l_args, "end", String(repr(end))) if file is not None: self.add_kwarg(l_args, "file", file) n_stmt = Call(Name("print"), l_args) Modified: sandbox/trunk/2to3/fixes/util.py ============================================================================== --- sandbox/trunk/2to3/fixes/util.py (original) +++ sandbox/trunk/2to3/fixes/util.py Wed Mar 21 22:20:59 2007 @@ -62,6 +62,10 @@ return Node(syms.trailer, [Leaf(token.LBRACE, '['), index_node, Leaf(token.RBRACE, ']')]) + +def String(string, prefix=None): + """A string leaf""" + return Leaf(token.STRING, string, prefix=prefix) def is_tuple(node): """Does the node represent a tuple literal?""" From python-checkins at python.org Wed Mar 21 22:53:29 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 22:53:29 +0100 (CET) Subject: [Python-checkins] r54503 - in sandbox/trunk/2to3: fixes/fix_numliterals.py pgen2/tokenize.py Message-ID: <20070321215329.82EFA1E400C@bag.python.org> Author: collin.winter Date: Wed Mar 21 22:53:25 2007 New Revision: 54503 Modified: sandbox/trunk/2to3/fixes/fix_numliterals.py sandbox/trunk/2to3/pgen2/tokenize.py Log: Changes needed to make fix_numliterals work correctly. Modified: sandbox/trunk/2to3/fixes/fix_numliterals.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_numliterals.py (original) +++ sandbox/trunk/2to3/fixes/fix_numliterals.py Wed Mar 21 22:53:25 2007 @@ -21,7 +21,8 @@ return (node.type == token.NUMBER and (node.value.startswith("0") or 'E' in node.value or - 'J' in node.value)) + 'J' in node.value or + node.value[-1] in "Ll")) def transform(self, node): val = node.value Modified: sandbox/trunk/2to3/pgen2/tokenize.py ============================================================================== --- sandbox/trunk/2to3/pgen2/tokenize.py (original) +++ sandbox/trunk/2to3/pgen2/tokenize.py Wed Mar 21 22:53:25 2007 @@ -47,7 +47,7 @@ Name = r'[a-zA-Z_]\w*' Hexnumber = r'0[xX][\da-fA-F]*[lL]?' -Octnumber = r'0[0-7]*[lL]?' +Octnumber = r'0[o]?[0-7]*[lL]?' Decnumber = r'[1-9]\d*[lL]?' Intnumber = group(Hexnumber, Octnumber, Decnumber) Exponent = r'[eE][-+]?\d+' From python-checkins at python.org Wed Mar 21 22:54:11 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 22:54:11 +0100 (CET) Subject: [Python-checkins] r54504 - sandbox/trunk/2to3/tests/test_fixers.py Message-ID: <20070321215411.C84A51E4004@bag.python.org> Author: collin.winter Date: Wed Mar 21 22:54:10 2007 New Revision: 54504 Modified: sandbox/trunk/2to3/tests/test_fixers.py Log: Add a test suite for fix_numliterals. Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Wed Mar 21 22:54:10 2007 @@ -1690,6 +1690,98 @@ pass """ self.check(s, s) + +class Test_numliterals(FixerTestCase): + fixer = "numliterals" + + def test_complex_bare_int(self): + b = """4J""" + a = """4j""" + self.check(b, a) + + def test_complex_bare_float(self): + b = """4.4J""" + a = """4.4j""" + self.check(b, a) + + def test_complex_int(self): + b = """5 + 4J""" + a = """5 + 4j""" + self.check(b, a) + + def test_complex_float(self): + b = """5.4 + 4.9J""" + a = """5.4 + 4.9j""" + self.check(b, a) + + def test_exp_1(self): + b = """5E10""" + a = """5e10""" + self.check(b, a) + + def test_exp_2(self): + b = """5.0E10""" + a = """5.0e10""" + self.check(b, a) + + def test_octal_1(self): + b = """0755""" + a = """0o755""" + self.check(b, a) + + def test_hex_1(self): + b = """0XABC""" + a = """0xABC""" + self.check(b, a) + + def test_long_int_1(self): + b = """a = 12L""" + a = """a = 12""" + self.check(b, a) + + def test_long_int_2(self): + b = """a = 12l""" + a = """a = 12""" + self.check(b, a) + + def test_long_hex(self): + b = """b = 0x12l""" + a = """b = 0x12""" + self.check(b, a) + + def test_unchanged_int(self): + s = """5""" + self.check(s, s) + + def test_unchanged_float(self): + s = """5.0""" + self.check(s, s) + + def test_unchanged_octal(self): + s = """0o755""" + self.check(s, s) + + def test_unchanged_hex(self): + s = """0xABC""" + self.check(s, s) + + def test_unchanged_exp(self): + s = """5.0e10""" + self.check(s, s) + + def test_unchanged_complex_int(self): + s = """5 + 4j""" + self.check(s, s) + + def test_unchanged_complex_float(self): + s = """5.4 + 4.9j""" + self.check(s, s) + + def test_unchanged_complex_bare(self): + s = """4j""" + self.check(s, s) + s = """4.4j""" + self.check(s, s) if __name__ == "__main__": From python-checkins at python.org Wed Mar 21 22:55:52 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 22:55:52 +0100 (CET) Subject: [Python-checkins] r54505 - sandbox/trunk/2to3/fixes/basefix.py sandbox/trunk/2to3/fixes/fix_ne.py sandbox/trunk/2to3/fixes/fix_numliterals.py Message-ID: <20070321215552.A37821E400A@bag.python.org> Author: collin.winter Date: Wed Mar 21 22:55:52 2007 New Revision: 54505 Modified: sandbox/trunk/2to3/fixes/basefix.py sandbox/trunk/2to3/fixes/fix_ne.py sandbox/trunk/2to3/fixes/fix_numliterals.py Log: Remove the requirement for simple fixers (those that don't require PATTERN) to override compile_pattern(). Modified: sandbox/trunk/2to3/fixes/basefix.py ============================================================================== --- sandbox/trunk/2to3/fixes/basefix.py (original) +++ sandbox/trunk/2to3/fixes/basefix.py Wed Mar 21 22:55:52 2007 @@ -14,7 +14,7 @@ from sets import Set as set # Local imports -import patcomp +from patcomp import PatternCompiler import pygram class BaseFix(object): @@ -27,7 +27,7 @@ FixHasKey. """ - PATTERN = None # Subclass *must* override with a string literal + PATTERN = None # Most subclasses should override with a string literal pattern = None # Compiled pattern, set by compile_pattern() options = None # Options object passed to initializer filename = None # The filename (set by set_filename) @@ -53,7 +53,8 @@ Subclass may override if it doesn't want to use self.{pattern,PATTERN} in .match(). """ - self.pattern = patcomp.PatternCompiler().compile_pattern(self.PATTERN) + if self.PATTERN is not None: + self.pattern = PatternCompiler().compile_pattern(self.PATTERN) def set_filename(self, filename): """Set the filename, and a logger derived from it. Modified: sandbox/trunk/2to3/fixes/fix_ne.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_ne.py (original) +++ sandbox/trunk/2to3/fixes/fix_ne.py Wed Mar 21 22:55:52 2007 @@ -14,10 +14,6 @@ class FixNe(basefix.BaseFix): - def compile_pattern(self): - # Override - pass - def match(self, node): # Override return node.type == token.NOTEQUAL and node.value == "<>" Modified: sandbox/trunk/2to3/fixes/fix_numliterals.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_numliterals.py (original) +++ sandbox/trunk/2to3/fixes/fix_numliterals.py Wed Mar 21 22:55:52 2007 @@ -12,10 +12,6 @@ class FixNumliterals(basefix.BaseFix): - def compile_pattern(self): - # Override - pass - def match(self, node): # Override return (node.type == token.NUMBER and From python-checkins at python.org Wed Mar 21 22:56:47 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 22:56:47 +0100 (CET) Subject: [Python-checkins] r54506 - sandbox/trunk/2to3/README Message-ID: <20070321215647.738001E4004@bag.python.org> Author: collin.winter Date: Wed Mar 21 22:56:47 2007 New Revision: 54506 Modified: sandbox/trunk/2to3/README Log: Add fix_numliterals to the README. Modified: sandbox/trunk/2to3/README ============================================================================== --- sandbox/trunk/2to3/README (original) +++ sandbox/trunk/2to3/README Wed Mar 21 22:56:47 2007 @@ -54,6 +54,8 @@ * **fix_nonzero** - convert __nonzero__() methods to __bool__() methods. +* **fix_numliterals** - tweak certain numeric literals to be 3.0-compliant. + * **fix_print** - convert "print" statements to print() function calls. * **fix_raise** - convert "raise" statements to Python 3 syntax (PEP 3109). From python-checkins at python.org Wed Mar 21 23:03:07 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 23:03:07 +0100 (CET) Subject: [Python-checkins] r54507 - sandbox/trunk/2to3/fixes/fix_numliterals.py Message-ID: <20070321220307.5321E1E4004@bag.python.org> Author: collin.winter Date: Wed Mar 21 23:03:02 2007 New Revision: 54507 Modified: sandbox/trunk/2to3/fixes/fix_numliterals.py Log: Take advantage of fixes.util.Number(); add copyright, authorship information. Modified: sandbox/trunk/2to3/fixes/fix_numliterals.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_numliterals.py (original) +++ sandbox/trunk/2to3/fixes/fix_numliterals.py Wed Mar 21 23:03:02 2007 @@ -3,11 +3,14 @@ This is so simple that we don't need the pattern compiler. """ +# Copyright 2007 Georg Brandl. +# Licensed to PSF under a Contributor Agreement. # Local imports import pytree from pgen2 import token from fixes import basefix +from fixes.util import Number class FixNumliterals(basefix.BaseFix): @@ -33,6 +36,4 @@ elif val.startswith('0') and val.isdigit() and len(set(val)) > 1: val = "0o" + val[1:] - new = pytree.Leaf(token.NUMBER, val) - new.set_prefix(node.get_prefix()) - return new + return Number(val, prefix=node.get_prefix()) From python-checkins at python.org Wed Mar 21 23:06:22 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 23:06:22 +0100 (CET) Subject: [Python-checkins] r54508 - sandbox/trunk/2to3/fixes/fix_ne.py sandbox/trunk/2to3/fixes/fix_numliterals.py Message-ID: <20070321220622.277AD1E4004@bag.python.org> Author: collin.winter Date: Wed Mar 21 23:06:20 2007 New Revision: 54508 Modified: sandbox/trunk/2to3/fixes/fix_ne.py sandbox/trunk/2to3/fixes/fix_numliterals.py Log: Comment cleanup. Modified: sandbox/trunk/2to3/fixes/fix_ne.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_ne.py (original) +++ sandbox/trunk/2to3/fixes/fix_ne.py Wed Mar 21 23:06:20 2007 @@ -1,10 +1,7 @@ # Copyright 2006 Google, Inc. All Rights Reserved. # Licensed to PSF under a Contributor Agreement. -"""Fixer that turns <> into !=. - -This is so simple that we don't need the pattern compiler. -""" +"""Fixer that turns <> into !=.""" # Local imports import pytree @@ -13,6 +10,7 @@ class FixNe(basefix.BaseFix): + # This is so simple that we don't need the pattern compiler. def match(self, node): # Override Modified: sandbox/trunk/2to3/fixes/fix_numliterals.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_numliterals.py (original) +++ sandbox/trunk/2to3/fixes/fix_numliterals.py Wed Mar 21 23:06:20 2007 @@ -1,7 +1,5 @@ """Fixer that turns 1L into 1, 0755 into 0o755, 0XABC into 0xABC, 1E5 into 1e5, 1J into 1j. - -This is so simple that we don't need the pattern compiler. """ # Copyright 2007 Georg Brandl. # Licensed to PSF under a Contributor Agreement. @@ -14,6 +12,7 @@ class FixNumliterals(basefix.BaseFix): + # This is so simple that we don't need the pattern compiler. def match(self, node): # Override From buildbot at python.org Wed Mar 21 23:17:31 2007 From: buildbot at python.org (buildbot at python.org) Date: Wed, 21 Mar 2007 22:17:31 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070321221731.6C9CA1E4004@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/341 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: raymond.hettinger Build had warnings: warnings test Excerpt from the test logfile: 3 tests failed: test_os test_posixpath test_urllib ====================================================================== ERROR: test_makedir (test.test_os.MakedirTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 376, in setUp os.mkdir(test_support.TESTFN) WindowsError: [Error 183] Cannot create a file when that file already exists: '@test' ====================================================================== ERROR: test_access (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 443, in test_access self.assertRaises(WindowsError, os.utime, test_support.TESTFN, 0) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\unittest.py", line 329, in failUnlessRaises callableObj(*args, **kwargs) TypeError: utime() arg 2 must be a tuple (atime, mtime) ====================================================================== FAIL: test_traversal (test.test_os.WalkTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 313, in test_traversal self.assertEqual(len(all), 4) AssertionError: 5 != 4 ====================================================================== FAIL: test_chdir (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 434, in test_chdir self.assertRaises(WindowsError, os.chdir, test_support.TESTFN) AssertionError: WindowsError not raised ====================================================================== FAIL: test_relpath (test.test_posixpath.PosixPathTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_posixpath.py", line 486, in test_relpath self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a") AssertionError: 'C:\\buildbot_py25\\trunk.mcintyre-windows\\build\\PCbuild\\@test\\@test\\a' != 'a' sincerely, -The Buildbot From python-checkins at python.org Wed Mar 21 23:18:32 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 23:18:32 +0100 (CET) Subject: [Python-checkins] r54509 - sandbox/trunk/2to3/tests/test_grammar.py Message-ID: <20070321221832.D69E61E4004@bag.python.org> Author: collin.winter Date: Wed Mar 21 23:18:27 2007 New Revision: 54509 Modified: sandbox/trunk/2to3/tests/test_grammar.py Log: Add an explicit test for py3k's new octal literal syntax. Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Wed Mar 21 23:18:27 2007 @@ -126,7 +126,12 @@ def test_4(self): self.validate("""x = {2, 3, 4,}""") - + + +class TestNumericLiterals(GrammarTest): + def test_new_octal_notation(self): + self.validate("""0o7777777777777""") + class TestGrammarFiles(GrammarTest): def test_python2(self): From collinw at gmail.com Wed Mar 21 23:23:02 2007 From: collinw at gmail.com (Collin Winter) Date: Wed, 21 Mar 2007 17:23:02 -0500 Subject: [Python-checkins] buildbot warnings in x86 XP trunk In-Reply-To: <20070321221731.6C9CA1E4004@bag.python.org> References: <20070321221731.6C9CA1E4004@bag.python.org> Message-ID: <43aa6ff70703211523y467674c4g91f1d98b0f93a661@mail.gmail.com> On 3/21/07, buildbot at python.org wrote: > Excerpt from the test logfile: > 3 tests failed: > test_os test_posixpath test_urllib [snip] > FAIL: test_relpath (test.test_posixpath.PosixPathTest) > ---------------------------------------------------------------------- > > Traceback (most recent call last): > File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_posixpath.py", line 486, in test_relpath > self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a") > AssertionError: 'C:\\buildbot_py25\\trunk.mcintyre-windows\\build\\PCbuild\\@test\\@test\\a' != 'a' The attached patch should fix this test failure. I'd greatly appreciate it if someone with access to Windows could apply it and let me know if it works before I commit it. Thanks, Collin Winter -------------- next part -------------- A non-text attachment was scrubbed... Name: test_posixpath.py.diff Type: application/octet-stream Size: 1720 bytes Desc: not available Url : http://mail.python.org/pipermail/python-checkins/attachments/20070321/07e2eaaa/attachment.obj From python-checkins at python.org Wed Mar 21 23:37:04 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 23:37:04 +0100 (CET) Subject: [Python-checkins] r54511 - in sandbox/trunk/2to3: pgen2/tokenize.py tests/test_grammar.py Message-ID: <20070321223704.8B4331E4011@bag.python.org> Author: collin.winter Date: Wed Mar 21 23:36:59 2007 New Revision: 54511 Modified: sandbox/trunk/2to3/pgen2/tokenize.py sandbox/trunk/2to3/tests/test_grammar.py Log: Add support for py3k's binary literals. Modified: sandbox/trunk/2to3/pgen2/tokenize.py ============================================================================== --- sandbox/trunk/2to3/pgen2/tokenize.py (original) +++ sandbox/trunk/2to3/pgen2/tokenize.py Wed Mar 21 23:36:59 2007 @@ -46,10 +46,11 @@ Ignore = Whitespace + any(r'\\\r?\n' + Whitespace) + maybe(Comment) Name = r'[a-zA-Z_]\w*' +Binnumber = r'0b[01]*' Hexnumber = r'0[xX][\da-fA-F]*[lL]?' Octnumber = r'0[o]?[0-7]*[lL]?' Decnumber = r'[1-9]\d*[lL]?' -Intnumber = group(Hexnumber, Octnumber, Decnumber) +Intnumber = group(Binnumber, Hexnumber, Octnumber, Decnumber) Exponent = r'[eE][-+]?\d+' Pointfloat = group(r'\d+\.\d*', r'\.\d+') + maybe(Exponent) Expfloat = r'\d+' + Exponent Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Wed Mar 21 23:36:59 2007 @@ -131,6 +131,12 @@ class TestNumericLiterals(GrammarTest): def test_new_octal_notation(self): self.validate("""0o7777777777777""") + + def test_new_binary_notation(self): + self.validate("""0b101010""") + self.invalid_syntax("""0b""") + self.invalid_syntax("""0b0101021""") + self.invalid_syntax("""b010101""") class TestGrammarFiles(GrammarTest): From python-checkins at python.org Wed Mar 21 23:38:20 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 23:38:20 +0100 (CET) Subject: [Python-checkins] r54512 - sandbox/trunk/2to3/tests/test_grammar.py Message-ID: <20070321223820.2CCDE1E4004@bag.python.org> Author: collin.winter Date: Wed Mar 21 23:38:18 2007 New Revision: 54512 Modified: sandbox/trunk/2to3/tests/test_grammar.py Log: More tests for py3k-style octal literals. Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Wed Mar 21 23:38:18 2007 @@ -131,6 +131,9 @@ class TestNumericLiterals(GrammarTest): def test_new_octal_notation(self): self.validate("""0o7777777777777""") + self.invalid_syntax("""0o""") + self.invalid_syntax("""0o7324528887""") + self.invalid_syntax("""o7324527""") def test_new_binary_notation(self): self.validate("""0b101010""") From python-checkins at python.org Wed Mar 21 23:39:40 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 23:39:40 +0100 (CET) Subject: [Python-checkins] r54513 - sandbox/trunk/2to3/tests/test_grammar.py Message-ID: <20070321223940.15D5F1E4004@bag.python.org> Author: collin.winter Date: Wed Mar 21 23:39:38 2007 New Revision: 54513 Modified: sandbox/trunk/2to3/tests/test_grammar.py Log: Back out two over-zealous (read: wrong) syntax tests. Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Wed Mar 21 23:39:38 2007 @@ -35,6 +35,8 @@ self.validate(code) except ParseError: pass + else: + raise AssertionError("Syntax shouldn't have been valid") class TestRaiseChanges(GrammarTest): @@ -133,13 +135,11 @@ self.validate("""0o7777777777777""") self.invalid_syntax("""0o""") self.invalid_syntax("""0o7324528887""") - self.invalid_syntax("""o7324527""") def test_new_binary_notation(self): self.validate("""0b101010""") self.invalid_syntax("""0b""") self.invalid_syntax("""0b0101021""") - self.invalid_syntax("""b010101""") class TestGrammarFiles(GrammarTest): From python-checkins at python.org Wed Mar 21 23:45:01 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 23:45:01 +0100 (CET) Subject: [Python-checkins] r54514 - sandbox/trunk/2to3/tests/test_grammar.py Message-ID: <20070321224501.A75431E4007@bag.python.org> Author: collin.winter Date: Wed Mar 21 23:45:00 2007 New Revision: 54514 Modified: sandbox/trunk/2to3/tests/test_grammar.py Log: Remove invalid tests. Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Wed Mar 21 23:45:00 2007 @@ -133,12 +133,10 @@ class TestNumericLiterals(GrammarTest): def test_new_octal_notation(self): self.validate("""0o7777777777777""") - self.invalid_syntax("""0o""") self.invalid_syntax("""0o7324528887""") def test_new_binary_notation(self): self.validate("""0b101010""") - self.invalid_syntax("""0b""") self.invalid_syntax("""0b0101021""") From python-checkins at python.org Wed Mar 21 23:59:43 2007 From: python-checkins at python.org (collin.winter) Date: Wed, 21 Mar 2007 23:59:43 +0100 (CET) Subject: [Python-checkins] r54515 - sandbox/trunk/2to3/fixes/util.py Message-ID: <20070321225943.8BDBE1E400F@bag.python.org> Author: collin.winter Date: Wed Mar 21 23:59:39 2007 New Revision: 54515 Modified: sandbox/trunk/2to3/fixes/util.py Log: Add is_list() to complement is_tuple(). Modified: sandbox/trunk/2to3/fixes/util.py ============================================================================== --- sandbox/trunk/2to3/fixes/util.py (original) +++ sandbox/trunk/2to3/fixes/util.py Wed Mar 21 23:59:39 2007 @@ -69,10 +69,18 @@ def is_tuple(node): """Does the node represent a tuple literal?""" - + return _is_seq_literal(node, "(", ")") + +def is_list(node): + """Does the node represent a list literal?""" + return _is_seq_literal(node, "[", "]") + +def _is_seq_literal(node, first, last): + """Abstract common parts of is_list, is_tuple""" return (isinstance(node, Node) and len(node.children) > 1 and isinstance(node.children[0], Leaf) and isinstance(node.children[-1], Leaf) - and node.children[0].value == "(" - and node.children[-1].value == ")") + and node.children[0].value == first + and node.children[-1].value == last) + From python-checkins at python.org Thu Mar 22 00:02:41 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 22 Mar 2007 00:02:41 +0100 (CET) Subject: [Python-checkins] r54516 - in sandbox/trunk/2to3: fixes/fix_except.py tests/test_fixers.py Message-ID: <20070321230241.476CB1E4004@bag.python.org> Author: collin.winter Date: Thu Mar 22 00:02:39 2007 New Revision: 54516 Modified: sandbox/trunk/2to3/fixes/fix_except.py sandbox/trunk/2to3/tests/test_fixers.py Log: Update fix_except, per Guido's decision that e.args will stay in py3k (http://mail.python.org/pipermail/python-3000/2007-March/006508.html). Modified: sandbox/trunk/2to3/fixes/fix_except.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_except.py (original) +++ sandbox/trunk/2to3/fixes/fix_except.py Thu Mar 22 00:02:39 2007 @@ -17,9 +17,7 @@ - "except E, T:" where T is a tuple or list literal: except E as t: - T = t.message - - This transformation is still under consideration. + T = t.args """ # Author: Collin Winter @@ -27,7 +25,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.util import Assign, Attr, Name +from fixes.util import Assign, Attr, Name, is_tuple, is_list def find_excepts(nodes): for i, n in enumerate(nodes): @@ -74,10 +72,10 @@ if isinstance(stmt, pytree.Node): break - # The assignment is different if old_N is a tuple - # In that case, the assignment is old_N = new_N.message - if str(N).strip()[0] == '(': - assign = Assign(target, Attr(new_N, Name('message'))) + # The assignment is different if old_N is a tuple or list + # In that case, the assignment is old_N = new_N.args + if is_tuple(N) or is_list(N): + assign = Assign(target, Attr(new_N, Name('args'))) else: assign = Assign(target, new_N) Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Thu Mar 22 00:02:39 2007 @@ -497,7 +497,7 @@ try: pass except Exception as xxx_todo_changeme: - (f, e) = xxx_todo_changeme.message + (f, e) = xxx_todo_changeme.args pass except ImportError as e: pass""" @@ -521,14 +521,14 @@ b = """ try: pass - except Exception, (a, b): + except Exception, [a, b]: pass""" a = """ try: pass except Exception as xxx_todo_changeme: - (a, b) = xxx_todo_changeme.message + [a, b] = xxx_todo_changeme.args pass""" self.check(b, a) From python-checkins at python.org Thu Mar 22 00:09:48 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 22 Mar 2007 00:09:48 +0100 (CET) Subject: [Python-checkins] r54517 - sandbox/trunk/2to3/tests/support.py sandbox/trunk/2to3/tests/test_fixers.py sandbox/trunk/2to3/tests/test_grammar.py sandbox/trunk/2to3/tests/test_pytree.py Message-ID: <20070321230948.734681E4004@bag.python.org> Author: collin.winter Date: Thu Mar 22 00:09:43 2007 New Revision: 54517 Modified: sandbox/trunk/2to3/tests/support.py sandbox/trunk/2to3/tests/test_fixers.py sandbox/trunk/2to3/tests/test_grammar.py sandbox/trunk/2to3/tests/test_pytree.py Log: Consolidate testing boilerplate. Modified: sandbox/trunk/2to3/tests/support.py ============================================================================== --- sandbox/trunk/2to3/tests/support.py (original) +++ sandbox/trunk/2to3/tests/support.py Thu Mar 22 00:09:43 2007 @@ -20,10 +20,7 @@ tests = unittest.TestLoader().loadTestsFromModule(test_mod) unittest.TextTestRunner(verbosity=2).run(tests) - -def adjust_path(): - parent_dir = os.path.split(sys.path[0])[0] - sys.path = [parent_dir] + sys.path - def reformat(string): return dedent(string) + "\n\n" + +sys.path.insert(0, os.path.dirname(__file__)) Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Thu Mar 22 00:09:43 2007 @@ -4,8 +4,6 @@ # Testing imports import support -if __name__ == '__main__': - support.adjust_path() # Python imports from StringIO import StringIO Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Thu Mar 22 00:09:43 2007 @@ -10,8 +10,6 @@ # Testing imports import support -if __name__ == '__main__': - support.adjust_path() # Python imports import os.path Modified: sandbox/trunk/2to3/tests/test_pytree.py ============================================================================== --- sandbox/trunk/2to3/tests/test_pytree.py (original) +++ sandbox/trunk/2to3/tests/test_pytree.py Thu Mar 22 00:09:43 2007 @@ -12,8 +12,6 @@ # Testing imports import support -if __name__ == '__main__': - support.adjust_path() # Local imports (XXX should become a package) import pytree From python-checkins at python.org Thu Mar 22 00:21:29 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 22 Mar 2007 00:21:29 +0100 (CET) Subject: [Python-checkins] r54518 - sandbox/trunk/2to3/tests/__init__.py sandbox/trunk/2to3/tests/support.py Message-ID: <20070321232129.29E2C1E400D@bag.python.org> Author: collin.winter Date: Thu Mar 22 00:21:24 2007 New Revision: 54518 Modified: sandbox/trunk/2to3/tests/__init__.py sandbox/trunk/2to3/tests/support.py Log: Fix broken sys.path manipulation. Modified: sandbox/trunk/2to3/tests/__init__.py ============================================================================== --- sandbox/trunk/2to3/tests/__init__.py (original) +++ sandbox/trunk/2to3/tests/__init__.py Thu Mar 22 00:21:24 2007 @@ -12,7 +12,7 @@ all_tests = unittest.TestSuite() -tests_dir = os.path.join(os.getcwd(), 'tests') +tests_dir = os.path.join(os.path.dirname(__file__), '..', 'tests') tests = [t[0:-3] for t in os.listdir(tests_dir) if t.startswith('test_') and t.endswith('.py')] Modified: sandbox/trunk/2to3/tests/support.py ============================================================================== --- sandbox/trunk/2to3/tests/support.py (original) +++ sandbox/trunk/2to3/tests/support.py Thu Mar 22 00:21:24 2007 @@ -23,4 +23,4 @@ def reformat(string): return dedent(string) + "\n\n" -sys.path.insert(0, os.path.dirname(__file__)) +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) From python-checkins at python.org Thu Mar 22 00:40:37 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 22 Mar 2007 00:40:37 +0100 (CET) Subject: [Python-checkins] r54519 - sandbox/trunk/2to3/fixes/util.py Message-ID: <20070321234037.8830B1E4004@bag.python.org> Author: collin.winter Date: Thu Mar 22 00:40:35 2007 New Revision: 54519 Modified: sandbox/trunk/2to3/fixes/util.py Log: Fix is_list(), tighten down is_tuple(). Modified: sandbox/trunk/2to3/fixes/util.py ============================================================================== --- sandbox/trunk/2to3/fixes/util.py (original) +++ sandbox/trunk/2to3/fixes/util.py Thu Mar 22 00:40:35 2007 @@ -69,18 +69,20 @@ def is_tuple(node): """Does the node represent a tuple literal?""" - return _is_seq_literal(node, "(", ")") + return (isinstance(node, Node) + and len(node.children) == 3 + and isinstance(node.children[0], Leaf) + and isinstance(node.children[1], Node) + and isinstance(node.children[2], Leaf) + and node.children[0].value == "(" + and node.children[2].value == ")") def is_list(node): """Does the node represent a list literal?""" - return _is_seq_literal(node, "[", "]") - -def _is_seq_literal(node, first, last): - """Abstract common parts of is_list, is_tuple""" return (isinstance(node, Node) - and len(node.children) > 1 - and isinstance(node.children[0], Leaf) - and isinstance(node.children[-1], Leaf) - and node.children[0].value == first - and node.children[-1].value == last) - + and len(node.children) > 1 + and isinstance(node.children[0], Leaf) + and isinstance(node.children[-1], Leaf) + and node.children[0].value == "[" + and node.children[-1].value == "]") + From python-checkins at python.org Thu Mar 22 00:41:23 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 22 Mar 2007 00:41:23 +0100 (CET) Subject: [Python-checkins] r54520 - sandbox/trunk/2to3/tests/test_util.py Message-ID: <20070321234123.AE46B1E4004@bag.python.org> Author: collin.winter Date: Thu Mar 22 00:41:22 2007 New Revision: 54520 Added: sandbox/trunk/2to3/tests/test_util.py (contents, props changed) Log: Start working on a test suite for the code in fixes.util. Added: sandbox/trunk/2to3/tests/test_util.py ============================================================================== --- (empty file) +++ sandbox/trunk/2to3/tests/test_util.py Thu Mar 22 00:41:22 2007 @@ -0,0 +1,53 @@ +#!/usr/bin/env python2.5 +""" Test suite for the code in fixes.util """ +# Author: Collin Winter + +# Testing imports +import support + +# Python imports +import os.path + +# Local imports +import pytree +from fixes import util +from pgen2 import driver +from pgen2.parse import ParseError + +test_dir = os.path.dirname(__file__) +grammar_path = os.path.join(test_dir, "..", "Grammar.txt") +grammar = driver.load_grammar(grammar_path) +driver = driver.Driver(grammar, convert=pytree.convert) + +def parse(code): + # The topmost node is file_input, which we don't care about. + # The next-topmost node is a *_stmt node, which we also don't care about + tree = driver.parse_string(support.reformat(code), debug=True) + return tree.children[0].children[0] + +class Test_is_tuple(support.TestCase): + def test_valid(self): + self.failUnless(util.is_tuple(parse("(a, b)"))) + self.failUnless(util.is_tuple(parse("(a, (b, c))"))) + self.failUnless(util.is_tuple(parse("((a, (b, c)),)"))) + self.failUnless(util.is_tuple(parse("(a,)"))) + + def test_invalid(self): + self.failIf(util.is_tuple(parse("(a)"))) + self.failIf(util.is_tuple(parse("('foo') % (b, c)"))) + +class Test_is_list(support.TestCase): + def test_valid(self): + self.failUnless(util.is_list(parse("[]"))) + self.failUnless(util.is_list(parse("[a]"))) + self.failUnless(util.is_list(parse("[a, b]"))) + self.failUnless(util.is_list(parse("[a, [b, c]]"))) + self.failUnless(util.is_list(parse("[[a, [b, c]],]"))) + + def test_invalid(self): + self.failIf(util.is_list(parse("[]+[]"))) + + +if __name__ == "__main__": + import __main__ + support.run_all_tests(__main__) From python-checkins at python.org Thu Mar 22 00:57:12 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 22 Mar 2007 00:57:12 +0100 (CET) Subject: [Python-checkins] r54521 - sandbox/trunk/2to3/tests/test_util.py Message-ID: <20070321235712.3D7351E4004@bag.python.org> Author: collin.winter Date: Thu Mar 22 00:57:08 2007 New Revision: 54521 Modified: sandbox/trunk/2to3/tests/test_util.py Log: More tests, better infrastructure. Modified: sandbox/trunk/2to3/tests/test_util.py ============================================================================== --- sandbox/trunk/2to3/tests/test_util.py (original) +++ sandbox/trunk/2to3/tests/test_util.py Thu Mar 22 00:57:08 2007 @@ -23,29 +23,69 @@ # The topmost node is file_input, which we don't care about. # The next-topmost node is a *_stmt node, which we also don't care about tree = driver.parse_string(support.reformat(code), debug=True) - return tree.children[0].children[0] + node = tree.children[0].children[0] + node.parent = None + return node + +class MacroTestCase(support.TestCase): + def assertStr(self, node, string): + if isinstance(node, (tuple, list)): + node = pytree.Node(util.syms.simple_stmt, node) + self.assertEqual(str(node), string) + class Test_is_tuple(support.TestCase): + def is_tuple(self, string): + return util.is_tuple(parse(string)) + def test_valid(self): - self.failUnless(util.is_tuple(parse("(a, b)"))) - self.failUnless(util.is_tuple(parse("(a, (b, c))"))) - self.failUnless(util.is_tuple(parse("((a, (b, c)),)"))) - self.failUnless(util.is_tuple(parse("(a,)"))) + self.failUnless(self.is_tuple("(a, b)")) + self.failUnless(self.is_tuple("(a, (b, c))")) + self.failUnless(self.is_tuple("((a, (b, c)),)")) + self.failUnless(self.is_tuple("(a,)")) def test_invalid(self): - self.failIf(util.is_tuple(parse("(a)"))) - self.failIf(util.is_tuple(parse("('foo') % (b, c)"))) + self.failIf(self.is_tuple("(a)")) + self.failIf(self.is_tuple("('foo') % (b, c)")) + class Test_is_list(support.TestCase): + def is_list(self, string): + return util.is_list(parse(string)) + def test_valid(self): - self.failUnless(util.is_list(parse("[]"))) - self.failUnless(util.is_list(parse("[a]"))) - self.failUnless(util.is_list(parse("[a, b]"))) - self.failUnless(util.is_list(parse("[a, [b, c]]"))) - self.failUnless(util.is_list(parse("[[a, [b, c]],]"))) + self.failUnless(self.is_list("[]")) + self.failUnless(self.is_list("[a]")) + self.failUnless(self.is_list("[a, b]")) + self.failUnless(self.is_list("[a, [b, c]]")) + self.failUnless(self.is_list("[[a, [b, c]],]")) def test_invalid(self): - self.failIf(util.is_list(parse("[]+[]"))) + self.failIf(self.is_list("[]+[]")) + + +class Test_Attr(MacroTestCase): + def test(self): + from fixes.util import Attr, Name + call = parse("foo()") + + self.assertStr(Attr(Name("a"), Name("b")), "a.b") + self.assertStr(Attr(call, Name("b")), "foo().b") + + def test_returns(self): + from fixes.util import Attr, Name + + attr = Attr(Name("a"), Name("b")) + self.assertEqual(type(attr), tuple) + + +class Test_Name(MacroTestCase): + def test(self): + from fixes.util import Name + + self.assertStr(Name("a"), "a") + self.assertStr(Name("foo.foo().bar"), "foo.foo().bar") + self.assertStr(Name("a", prefix="b"), "ba") if __name__ == "__main__": From python-checkins at python.org Thu Mar 22 01:15:59 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 22 Mar 2007 01:15:59 +0100 (CET) Subject: [Python-checkins] r54522 - sandbox/trunk/2to3/tests/test_fixers.py Message-ID: <20070322001559.5EF631E4008@bag.python.org> Author: collin.winter Date: Thu Mar 22 01:15:55 2007 New Revision: 54522 Modified: sandbox/trunk/2to3/tests/test_fixers.py Log: More descriptive test names. Modified: sandbox/trunk/2to3/tests/test_fixers.py ============================================================================== --- sandbox/trunk/2to3/tests/test_fixers.py (original) +++ sandbox/trunk/2to3/tests/test_fixers.py Thu Mar 22 01:15:55 2007 @@ -73,7 +73,7 @@ class Test_ne(FixerTestCase): fixer = "ne" - def test_1(self): + def test_basic(self): b = """if x <> y: pass""" @@ -81,7 +81,7 @@ pass""" self.check(b, a) - def test_2(self): + def test_no_spaces(self): b = """if x<>y: pass""" @@ -89,7 +89,7 @@ pass""" self.check(b, a) - def test_3(self): + def test_chained(self): b = """if x<>y<>z: pass""" @@ -190,46 +190,46 @@ # Test that complex functions are parenthesized - def test_7(self): + def test_complex_1(self): b = """x = apply(f+g, args)""" a = """x = (f+g)(*args)""" self.check(b, a) - def test_8(self): + def test_complex_2(self): b = """x = apply(f*g, args)""" a = """x = (f*g)(*args)""" self.check(b, a) - def test_9(self): + def test_complex_3(self): b = """x = apply(f**g, args)""" a = """x = (f**g)(*args)""" self.check(b, a) # But dotted names etc. not - def test_10(self): + def test_dotted_name(self): b = """x = apply(f.g, args)""" a = """x = f.g(*args)""" self.check(b, a) - def test_11(self): + def test_subscript(self): b = """x = apply(f[x], args)""" a = """x = f[x](*args)""" self.check(b, a) - def test_12(self): + def test_call(self): b = """x = apply(f(), args)""" a = """x = f()(*args)""" self.check(b, a) # Extreme case - def test_13(self): + def test_extreme(self): b = """x = apply(a.b.c.d.e.f, args, kwds)""" a = """x = a.b.c.d.e.f(*args, **kwds)""" self.check(b, a) # XXX Comments in weird places still get lost - def test_14(self): + def test_weird_comments(self): b = """apply( # foo f, # bar args)""" @@ -238,50 +238,41 @@ # These should *not* be touched - def test_15(self): - b = """apply()""" - a = """apply()""" - self.check(b, a) + def test_unchanged_1(self): + s = """apply()""" + self.check(s, s) - def test_16(self): - b = """apply(f)""" - a = """apply(f)""" - self.check(b, a) + def test_unchanged_2(self): + s = """apply(f)""" + self.check(s, s) - def test_17(self): - b = """apply(f,)""" - a = """apply(f,)""" - self.check(b, a) + def test_unchanged_3(self): + s = """apply(f,)""" + self.check(s, s) - def test_18(self): - b = """apply(f, args, kwds, extras)""" - a = """apply(f, args, kwds, extras)""" - self.check(b, a) + def test_unchanged_4(self): + s = """apply(f, args, kwds, extras)""" + self.check(s, s) - def test_19(self): - b = """apply(f, *args, **kwds)""" - a = """apply(f, *args, **kwds)""" - self.check(b, a) + def test_unchanged_5(self): + s = """apply(f, *args, **kwds)""" + self.check(s, s) - def test_20(self): - b = """apply(f, *args)""" - a = """apply(f, *args)""" - self.check(b, a) + def test_unchanged_6(self): + s = """apply(f, *args)""" + self.check(s, s) - def test_21(self): - b = """apply(func=f, args=args, kwds=kwds)""" - a = """apply(func=f, args=args, kwds=kwds)""" - self.check(b, a) + def test_unchanged_7(self): + s = """apply(func=f, args=args, kwds=kwds)""" + self.check(s, s) - def test_22(self): - b = """apply(f, args=args, kwds=kwds)""" - a = """apply(f, args=args, kwds=kwds)""" - self.check(b, a) + def test_unchanged_8(self): + s = """apply(f, args=args, kwds=kwds)""" + self.check(s, s) - def test_23(self): - b = """apply(f, args, kwds=kwds)""" - a = """apply(f, args, kwds=kwds)""" - self.check(b, a) + def test_unchanged_9(self): + s = """apply(f, args, kwds=kwds)""" + self.check(s, s) class Test_intern(FixerTestCase): @@ -311,25 +302,21 @@ # These should not be refactored - def test_5(self): - b = """intern(a=1)""" - a = """intern(a=1)""" - self.check(b, a) + def test_unchanged_1(self): + s = """intern(a=1)""" + self.check(s, s) - def test_6(self): - b = """intern(f, g)""" - a = """intern(f, g)""" - self.check(b, a) + def test_unchanged_2(self): + s = """intern(f, g)""" + self.check(s, s) - def test_7(self): - b = """intern(*h)""" - a = """intern(*h)""" - self.check(b, a) + def test_unchanged_3(self): + s = """intern(*h)""" + self.check(s, s) - def test_8(self): - b = """intern(**i)""" - a = """intern(**i)""" - self.check(b, a) + def test_unchanged_4(self): + s = """intern(**i)""" + self.check(s, s) class Test_print(FixerTestCase): fixer = "print" @@ -351,43 +338,39 @@ # trailing commas - def test_4(self): + def test_trailing_comma_1(self): b = """print 1, 2, 3,""" a = """print(1, 2, 3, end=' ')""" self.check(b, a) - def test_5(self): + def test_trailing_comma_2(self): b = """print 1, 2,""" a = """print(1, 2, end=' ')""" self.check(b, a) - def test_6(self): + def test_trailing_comma_3(self): b = """print 1,""" a = """print(1, end=' ')""" self.check(b, a) # >> stuff - # no trailing comma - def test_7(self): + def test_vargs_without_trailing_comma(self): b = """print >>sys.stderr, 1, 2, 3""" a = """print(1, 2, 3, file=sys.stderr)""" self.check(b, a) - # trailing comma - def test_8(self): + def test_with_trailing_comma(self): b = """print >>sys.stderr, 1, 2,""" a = """print(1, 2, end=' ', file=sys.stderr)""" self.check(b, a) - # no trailing comma - def test_9(self): + def test_no_trailing_comma(self): b = """print >>sys.stderr, 1+1""" a = """print(1+1, file=sys.stderr)""" self.check(b, a) - # spaces before sys.stderr - def test_10(self): + def test_spaces_before_file(self): b = """print >> sys.stderr""" a = """print(file=sys.stderr)""" self.check(b, a) @@ -396,83 +379,79 @@ class Test_exec(FixerTestCase): fixer = "exec" - def test_1(self): + def test_basic(self): b = """exec code""" a = """exec(code)""" self.check(b, a) - def test_2(self): + def test_with_globals(self): b = """exec code in ns""" a = """exec(code, ns)""" self.check(b, a) - def test_3(self): + def test_with_globals_locals(self): b = """exec code in ns1, ns2""" a = """exec(code, ns1, ns2)""" self.check(b, a) - def test_4(self): + def test_complex_1(self): b = """exec (a.b()) in ns""" a = """exec((a.b()), ns)""" self.check(b, a) - def test_5(self): + def test_complex_2(self): b = """exec a.b() + c in ns""" a = """exec(a.b() + c, ns)""" self.check(b, a) # These should not be touched - def test_6(self): - b = """exec(code)""" - a = """exec(code)""" - self.check(b, a) + def test_unchanged_1(self): + s = """exec(code)""" + self.check(s, s) - def test_7(self): - b = """exec (code)""" - a = """exec (code)""" - self.check(b, a) + def test_unchanged_2(self): + s = """exec (code)""" + self.check(s, s) - def test_8(self): - b = """exec(code, ns)""" - a = """exec(code, ns)""" - self.check(b, a) + def test_unchanged_3(self): + s = """exec(code, ns)""" + self.check(s, s) - def test_9(self): - b = """exec(code, ns1, ns2)""" - a = """exec(code, ns1, ns2)""" - self.check(b, a) + def test_unchanged_4(self): + s = """exec(code, ns1, ns2)""" + self.check(s, s) class Test_repr(FixerTestCase): fixer = "repr" - def test_1(self): + def test_simple_1(self): b = """x = `1 + 2`""" a = """x = repr(1 + 2)""" self.check(b, a) - def test_2(self): + def test_simple_2(self): b = """y = `x`""" a = """y = repr(x)""" self.check(b, a) - def test_3(self): + def test_complex(self): b = """z = `y`.__repr__()""" a = """z = repr(y).__repr__()""" self.check(b, a) - def test_4(self): + def test_tuple(self): b = """x = `1, 2, 3`""" a = """x = repr((1, 2, 3))""" self.check(b, a) - def test_5(self): + def test_nested(self): b = """x = `1 + `2``""" a = """x = repr(1 + repr(2))""" self.check(b, a) - def test_6(self): + def test_nested_tuples(self): b = """x = `1, 2 + `3, 4``""" a = """x = repr((1, 2 + repr((3, 4))))""" self.check(b, a) @@ -480,7 +459,7 @@ class Test_except(FixerTestCase): fixer = "except" - def test_1(self): + def test_tuple_unpack(self): b = """ def foo(): try: @@ -501,7 +480,7 @@ pass""" self.check(b, a) - def test_2(self): + def test_multi_class(self): b = """ try: pass @@ -515,7 +494,7 @@ pass""" self.check(b, a) - def test_3(self): + def test_list_unpack(self): b = """ try: pass @@ -530,7 +509,7 @@ pass""" self.check(b, a) - def test_4(self): + def test_weird_target_1(self): b = """ try: pass @@ -545,7 +524,7 @@ pass""" self.check(b, a) - def test_5(self): + def test_weird_target_2(self): b = """ try: pass @@ -560,7 +539,7 @@ pass""" self.check(b, a) - def test_6(self): + def test_weird_target_3(self): b = """ try: pass @@ -577,7 +556,7 @@ # These should not be touched: - def test_7(self): + def test_unchanged_1(self): b = """ try: pass @@ -591,7 +570,7 @@ pass""" self.check(b, a) - def test_8(self): + def test_unchanged_2(self): b = """ try: pass @@ -605,7 +584,7 @@ pass""" self.check(b, a) - def test_9(self): + def test_unchanged_3(self): b = """ try: pass @@ -623,47 +602,47 @@ class Test_raise(FixerTestCase): fixer = "raise" - def test_1(self): + def test_basic(self): b = """raise Exception, 5""" a = """raise Exception(5)""" self.check(b, a) - def test_2(self): + def test_prefix(self): b = """raise Exception,5""" a = """raise Exception(5)""" self.check(b, a) - def test_3(self): + def test_tuple_value(self): b = """raise Exception, (5, 6, 7)""" a = """raise Exception(5, 6, 7)""" self.check(b, a) - def test_4(self): + def test_tuple_detection(self): b = """raise E, (5, 6) % (a, b)""" a = """raise E((5, 6) % (a, b))""" self.check(b, a) - def test_5(self): + def test_tuple_exc_1(self): b = """raise (((E1, E2), E3), E4), V""" a = """raise E1(V)""" self.check(b, a) - def test_6(self): + def test_tuple_exc_2(self): b = """raise (E1, (E2, E3), E4), V""" a = """raise E1(V)""" self.check(b, a) # These should produce a warning - def test_warn_1(self): + def test_string_exc(self): s = """raise 'foo'""" self.warns(s, s, "Python 3 does not support string exceptions") - def test_warn_2(self): + def test_string_exc_val(self): s = """raise "foo", 5""" self.warns(s, s, "Python 3 does not support string exceptions") - def test_warn_3(self): + def test_string_exc_val_tb(self): s = """raise "foo", 5, 6""" self.warns(s, s, "Python 3 does not support string exceptions") From python-checkins at python.org Thu Mar 22 01:31:13 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 22 Mar 2007 01:31:13 +0100 (CET) Subject: [Python-checkins] r54523 - sandbox/trunk/2to3/tests/support.py sandbox/trunk/2to3/tests/test_grammar.py sandbox/trunk/2to3/tests/test_util.py Message-ID: <20070322003113.4DFE01E4004@bag.python.org> Author: collin.winter Date: Thu Mar 22 01:31:11 2007 New Revision: 54523 Modified: sandbox/trunk/2to3/tests/support.py sandbox/trunk/2to3/tests/test_grammar.py sandbox/trunk/2to3/tests/test_util.py Log: Refactor common parsing code into tests.support.parse_string(). Modified: sandbox/trunk/2to3/tests/support.py ============================================================================== --- sandbox/trunk/2to3/tests/support.py (original) +++ sandbox/trunk/2to3/tests/support.py Thu Mar 22 01:31:11 2007 @@ -1,13 +1,26 @@ """Support code for test_*.py files""" # Author: Collin Winter +# Python imports import unittest import sys import os.path import re from textwrap import dedent -TestCase = unittest.TestCase +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) + +# Local imports +import pytree +from pgen2 import driver + +test_dir = os.path.dirname(__file__) +grammar_path = os.path.join(test_dir, "..", "Grammar.txt") +grammar = driver.load_grammar(grammar_path) +driver = driver.Driver(grammar, convert=pytree.convert) + +def parse_string(string): + return driver.parse_string(reformat(string), debug=True) # Python 2.3's TestSuite is not iter()-able if sys.version_info < (2, 4): @@ -23,4 +36,4 @@ def reformat(string): return dedent(string) + "\n\n" -sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) +TestCase = unittest.TestCase Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Thu Mar 22 01:31:11 2007 @@ -10,23 +10,17 @@ # Testing imports import support +from support import driver, test_dir # Python imports import os.path # Local imports -import pytree -from pgen2 import driver from pgen2.parse import ParseError -test_dir = os.path.dirname(__file__) -grammar_path = os.path.join(test_dir, "..", "Grammar.txt") -grammar = driver.load_grammar(grammar_path) -driver = driver.Driver(grammar, convert=pytree.convert) - class GrammarTest(support.TestCase): def validate(self, code): - driver.parse_string(support.reformat(code), debug=True) + support.parse_string(code) def invalid_syntax(self, code): try: Modified: sandbox/trunk/2to3/tests/test_util.py ============================================================================== --- sandbox/trunk/2to3/tests/test_util.py (original) +++ sandbox/trunk/2to3/tests/test_util.py Thu Mar 22 01:31:11 2007 @@ -11,18 +11,11 @@ # Local imports import pytree from fixes import util -from pgen2 import driver -from pgen2.parse import ParseError - -test_dir = os.path.dirname(__file__) -grammar_path = os.path.join(test_dir, "..", "Grammar.txt") -grammar = driver.load_grammar(grammar_path) -driver = driver.Driver(grammar, convert=pytree.convert) def parse(code): # The topmost node is file_input, which we don't care about. # The next-topmost node is a *_stmt node, which we also don't care about - tree = driver.parse_string(support.reformat(code), debug=True) + tree = support.parse_string(code) node = tree.children[0].children[0] node.parent = None return node From python-checkins at python.org Thu Mar 22 09:05:47 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 22 Mar 2007 09:05:47 +0100 (CET) Subject: [Python-checkins] r54524 - python/trunk/Doc/lib/libtimeit.tex Message-ID: <20070322080547.E64EE1E4002@bag.python.org> Author: georg.brandl Date: Thu Mar 22 09:05:45 2007 New Revision: 54524 Modified: python/trunk/Doc/lib/libtimeit.tex Log: Bug #1685704: use -m switch in timeit docs. Modified: python/trunk/Doc/lib/libtimeit.tex ============================================================================== --- python/trunk/Doc/lib/libtimeit.tex (original) +++ python/trunk/Doc/lib/libtimeit.tex Thu Mar 22 09:05:45 2007 @@ -127,7 +127,7 @@ When called as a program from the command line, the following form is used: \begin{verbatim} -python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...] +python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...] \end{verbatim} where the following options are understood: From python-checkins at python.org Thu Mar 22 09:05:53 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 22 Mar 2007 09:05:53 +0100 (CET) Subject: [Python-checkins] r54525 - python/branches/release25-maint/Doc/lib/libtimeit.tex Message-ID: <20070322080553.F27961E4002@bag.python.org> Author: georg.brandl Date: Thu Mar 22 09:05:53 2007 New Revision: 54525 Modified: python/branches/release25-maint/Doc/lib/libtimeit.tex Log: Bug #1685704: use -m switch in timeit docs. (backport from rev. 54524) Modified: python/branches/release25-maint/Doc/lib/libtimeit.tex ============================================================================== --- python/branches/release25-maint/Doc/lib/libtimeit.tex (original) +++ python/branches/release25-maint/Doc/lib/libtimeit.tex Thu Mar 22 09:05:53 2007 @@ -102,7 +102,7 @@ When called as a program from the command line, the following form is used: \begin{verbatim} -python timeit.py [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...] +python -m timeit [-n N] [-r N] [-s S] [-t] [-c] [-h] [statement ...] \end{verbatim} where the following options are understood: From buildbot at python.org Thu Mar 22 12:41:59 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 22 Mar 2007 11:41:59 +0000 Subject: [Python-checkins] buildbot failure in x86 gentoo trunk Message-ID: <20070322114159.F3E0A1E4002@bag.python.org> The Buildbot has detected a new failure of x86 gentoo trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520gentoo%2520trunk/builds/2076 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: The web-page 'force build' button was pressed by 'Chandra': test Build Source Stamp: [branch ALL] HEAD Blamelist: BUILD FAILED: failed svn sincerely, -The Buildbot From python-checkins at python.org Thu Mar 22 20:43:43 2007 From: python-checkins at python.org (thomas.heller) Date: Thu, 22 Mar 2007 20:43:43 +0100 (CET) Subject: [Python-checkins] r54532 - in python/branches/release25-maint: Misc/NEWS Modules/_ctypes/cfield.c Message-ID: <20070322194343.5775D1E4004@bag.python.org> Author: thomas.heller Date: Thu Mar 22 20:43:37 2007 New Revision: 54532 Modified: python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Modules/_ctypes/cfield.c Log: Back out "Patch #1643874: memory leak in ctypes fixed." The code in this patch leaves no way to give up the ownership of a BSTR instance. Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Thu Mar 22 20:43:37 2007 @@ -287,8 +287,6 @@ - Bug #1643943: Fix %U handling for time.strptime. -- Patch #1643874: memory leak in ctypes fixed. - - Bug #1598181: Avoid O(N**2) bottleneck in subprocess communicate(). - Patch #1627441: close sockets properly in urllib2. Modified: python/branches/release25-maint/Modules/_ctypes/cfield.c ============================================================================== --- python/branches/release25-maint/Modules/_ctypes/cfield.c (original) +++ python/branches/release25-maint/Modules/_ctypes/cfield.c Thu Mar 22 20:43:37 2007 @@ -1424,19 +1424,10 @@ #endif #ifdef MS_WIN32 -/* We cannot use SysFreeString as the PyCObject_FromVoidPtr - because of different calling convention -*/ -static void _my_SysFreeString(void *p) -{ - SysFreeString((BSTR)p); -} - static PyObject * BSTR_set(void *ptr, PyObject *value, unsigned size) { BSTR bstr; - PyObject *result; /* convert value into a PyUnicodeObject or NULL */ if (Py_None == value) { @@ -1464,19 +1455,15 @@ } else bstr = NULL; - if (bstr) { - result = PyCObject_FromVoidPtr((void *)bstr, _my_SysFreeString); - if (result == NULL) { - SysFreeString(bstr); - return NULL; - } - } else { - result = Py_None; - Py_INCREF(result); - } - + /* free the previous contents, if any */ + if (*(BSTR *)ptr) + SysFreeString(*(BSTR *)ptr); + + /* and store it */ *(BSTR *)ptr = bstr; - return result; + + /* We don't need to keep any other object */ + _RET(value); } From python-checkins at python.org Thu Mar 22 20:44:35 2007 From: python-checkins at python.org (thomas.heller) Date: Thu, 22 Mar 2007 20:44:35 +0100 (CET) Subject: [Python-checkins] r54533 - in python/trunk: Misc/NEWS Modules/_ctypes/cfield.c Message-ID: <20070322194435.0BD141E4004@bag.python.org> Author: thomas.heller Date: Thu Mar 22 20:44:31 2007 New Revision: 54533 Modified: python/trunk/Misc/NEWS python/trunk/Modules/_ctypes/cfield.c Log: Back out "Patch #1643874: memory leak in ctypes fixed." The code in this patch leaves no way to give up the ownership of a BSTR instance. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Thu Mar 22 20:44:31 2007 @@ -361,8 +361,6 @@ - Bug #1643943: Fix time.strptime's support for the %U directive. -- Patch #1643874: memory leak in ctypes fixed. - - Patch #1507247: tarfile.py: use current umask for intermediate directories. Modified: python/trunk/Modules/_ctypes/cfield.c ============================================================================== --- python/trunk/Modules/_ctypes/cfield.c (original) +++ python/trunk/Modules/_ctypes/cfield.c Thu Mar 22 20:44:31 2007 @@ -1461,19 +1461,10 @@ #endif #ifdef MS_WIN32 -/* We cannot use SysFreeString as the PyCObject_FromVoidPtr - because of different calling convention -*/ -static void _my_SysFreeString(void *p) -{ - SysFreeString((BSTR)p); -} - static PyObject * BSTR_set(void *ptr, PyObject *value, unsigned size) { BSTR bstr; - PyObject *result; /* convert value into a PyUnicodeObject or NULL */ if (Py_None == value) { @@ -1501,19 +1492,15 @@ } else bstr = NULL; - if (bstr) { - result = PyCObject_FromVoidPtr((void *)bstr, _my_SysFreeString); - if (result == NULL) { - SysFreeString(bstr); - return NULL; - } - } else { - result = Py_None; - Py_INCREF(result); - } - + /* free the previous contents, if any */ + if (*(BSTR *)ptr) + SysFreeString(*(BSTR *)ptr); + + /* and store it */ *(BSTR *)ptr = bstr; - return result; + + /* We don't need to keep any other object */ + _RET(value); } From python-checkins at python.org Thu Mar 22 21:33:10 2007 From: python-checkins at python.org (thomas.heller) Date: Thu, 22 Mar 2007 21:33:10 +0100 (CET) Subject: [Python-checkins] r54537 - python/branches/release25-maint/Modules/_ctypes/_ctypes.c Message-ID: <20070322203310.5B1361E4004@bag.python.org> Author: thomas.heller Date: Thu Mar 22 21:33:04 2007 New Revision: 54537 Modified: python/branches/release25-maint/Modules/_ctypes/_ctypes.c Log: Explain the purpose of the b_needsfree flag. This answers Neals question (well, two months too late). Modified: python/branches/release25-maint/Modules/_ctypes/_ctypes.c ============================================================================== --- python/branches/release25-maint/Modules/_ctypes/_ctypes.c (original) +++ python/branches/release25-maint/Modules/_ctypes/_ctypes.c Thu Mar 22 21:33:04 2007 @@ -2181,7 +2181,12 @@ if ((size_t)dict->size <= sizeof(obj->b_value)) { /* No need to call malloc, can use the default buffer */ obj->b_ptr = (char *)&obj->b_value; - /* XXX(nnorwitz): shouldn't b_needsfree be 0? */ + /* The b_needsfree flag does not mean that we actually did + call PyMem_Malloc to allocate the memory block; instead it + means we are the *owner* of the memory and are responsible + for freeing resources associated with the memory. This is + also the reason that b_needsfree is exposed to Python. + */ obj->b_needsfree = 1; } else { /* In python 2.4, and ctypes 0.9.6, the malloc call took about From python-checkins at python.org Thu Mar 22 21:34:38 2007 From: python-checkins at python.org (thomas.heller) Date: Thu, 22 Mar 2007 21:34:38 +0100 (CET) Subject: [Python-checkins] r54538 - python/trunk/Modules/_ctypes/_ctypes.c Message-ID: <20070322203438.AD0D61E4004@bag.python.org> Author: thomas.heller Date: Thu Mar 22 21:34:37 2007 New Revision: 54538 Modified: python/trunk/Modules/_ctypes/_ctypes.c Log: Explain the purpose of the b_needsfree flag (forward ported from release25-maint). Modified: python/trunk/Modules/_ctypes/_ctypes.c ============================================================================== --- python/trunk/Modules/_ctypes/_ctypes.c (original) +++ python/trunk/Modules/_ctypes/_ctypes.c Thu Mar 22 21:34:37 2007 @@ -2181,6 +2181,12 @@ if ((size_t)dict->size <= sizeof(obj->b_value)) { /* No need to call malloc, can use the default buffer */ obj->b_ptr = (char *)&obj->b_value; + /* The b_needsfree flag does not mean that we actually did + call PyMem_Malloc to allocate the memory block; instead it + means we are the *owner* of the memory and are responsible + for freeing resources associated with the memory. This is + also the reason that b_needsfree is exposed to Python. + */ obj->b_needsfree = 1; } else { /* In python 2.4, and ctypes 0.9.6, the malloc call took about From python-checkins at python.org Fri Mar 23 05:58:46 2007 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 23 Mar 2007 05:58:46 +0100 (CET) Subject: [Python-checkins] r54539 - in python/trunk: Lib/string.py Misc/NEWS Objects/typeobject.c Message-ID: <20070323045846.0C6001E4005@bag.python.org> Author: guido.van.rossum Date: Fri Mar 23 05:58:42 2007 New Revision: 54539 Modified: python/trunk/Lib/string.py python/trunk/Misc/NEWS python/trunk/Objects/typeobject.c Log: - Bug #1683368: The object.__init__() and object.__new__() methods are now stricter in rejecting excess arguments. The only time when either allows excess arguments is when it is not overridden and the other one is. For backwards compatibility, when both are overridden, it is a deprecation warning (for now; maybe a Py3k warning later). When merging this into 3.0, the warnings should become errors. Note: without the change to string.py, lots of spurious warnings happen. What's going on there? Modified: python/trunk/Lib/string.py ============================================================================== --- python/trunk/Lib/string.py (original) +++ python/trunk/Lib/string.py Fri Mar 23 05:58:42 2007 @@ -108,7 +108,9 @@ """ def __init__(cls, name, bases, dct): - super(_TemplateMetaclass, cls).__init__(name, bases, dct) + # A super call makes no sense since type() doesn't define __init__(). + # (Or does it? And should type.__init__() accept three args?) + # super(_TemplateMetaclass, cls).__init__(name, bases, dct) if 'pattern' in dct: pattern = cls.pattern else: Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 23 05:58:42 2007 @@ -1,4 +1,4 @@ -+++++++++++ +__init+++++++++++ Python News +++++++++++ @@ -17,6 +17,13 @@ - Remove unused file Python/fmod.c. +- Bug #1683368: The object.__init__() and object.__new__() methods are + now stricter in rejecting excess arguments. The only time when + either allows excess arguments is when it is not overridden and the + other one is. For backwards compatibility, when both are + overridden, it is a deprecation warning (for now; maybe a Py3k + warning later). + - Patch #1675423: PyComplex_AsCComplex() now tries to convert an object to complex using its __complex__() method before falling back to the __float__() method. Therefore, the functions in the cmath module now Modified: python/trunk/Objects/typeobject.c ============================================================================== --- python/trunk/Objects/typeobject.c (original) +++ python/trunk/Objects/typeobject.c Fri Mar 23 05:58:42 2007 @@ -2391,27 +2391,103 @@ /* The base type of all types (eventually)... except itself. */ +/* You may wonder why object.__new__() only complains about arguments + when object.__init__() is not overridden, and vice versa. + + Consider the use cases: + + 1. When neither is overridden, we want to hear complaints about + excess (i.e., any) arguments, since their presence could + indicate there's a bug. + + 2. When defining an Immutable type, we are likely to override only + __new__(), since __init__() is called too late to initialize an + Immutable object. Since __new__() defines the signature for the + type, it would be a pain to have to override __init__() just to + stop it from complaining about excess arguments. + + 3. When defining a Mutable type, we are likely to override only + __init__(). So here the converse reasoning applies: we don't + want to have to override __new__() just to stop it from + complaining. + + 4. When __init__() is overridden, and the subclass __init__() calls + object.__init__(), the latter should complain about excess + arguments; ditto for __new__(). + + Use cases 2 and 3 make it unattractive to unconditionally check for + excess arguments. The best solution that addresses all four use + cases is as follows: __init__() complains about excess arguments + unless __new__() is overridden and __init__() is not overridden + (IOW, if __init__() is overridden or __new__() is not overridden); + symmetrically, __new__() complains about excess arguments unless + __init__() is overridden and __new__() is not overridden + (IOW, if __new__() is overridden or __init__() is not overridden). + + However, for backwards compatibility, this breaks too much code. + Therefore, in 2.6, we'll *warn* about excess arguments when both + methods are overridden; for all other cases we'll use the above + rules. + +*/ + +/* Forward */ +static PyObject * +object_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + +static int +excess_args(PyObject *args, PyObject *kwds) +{ + return PyTuple_GET_SIZE(args) || + (kwds && PyDict_Check(kwds) && PyDict_Size(kwds)); +} + static int object_init(PyObject *self, PyObject *args, PyObject *kwds) { - return 0; + int err = 0; + if (excess_args(args, kwds)) { + PyTypeObject *type = self->ob_type; + if (type->tp_init != object_init && + type->tp_new != object_new) + { + err = PyErr_WarnEx(PyExc_DeprecationWarning, + "object.__init__() takes no parameters", + 1); + } + else if (type->tp_init != object_init || + type->tp_new == object_new) + { + PyErr_SetString(PyExc_TypeError, + "object.__init__() takes no parameters"); + err = -1; + } + } + return err; } -/* If we don't have a tp_new for a new-style class, new will use this one. - Therefore this should take no arguments/keywords. However, this new may - also be inherited by objects that define a tp_init but no tp_new. These - objects WILL pass argumets to tp_new, because it gets the same args as - tp_init. So only allow arguments if we aren't using the default init, in - which case we expect init to handle argument parsing. */ static PyObject * object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - if (type->tp_init == object_init && (PyTuple_GET_SIZE(args) || - (kwds && PyDict_Check(kwds) && PyDict_Size(kwds)))) { - PyErr_SetString(PyExc_TypeError, - "default __new__ takes no parameters"); - return NULL; + int err = 0; + if (excess_args(args, kwds)) { + if (type->tp_new != object_new && + type->tp_init != object_init) + { + err = PyErr_WarnEx(PyExc_DeprecationWarning, + "object.__new__() takes no parameters", + 1); + } + else if (type->tp_new != object_new || + type->tp_init == object_init) + { + PyErr_SetString(PyExc_TypeError, + "object.__new__() takes no parameters"); + err = -1; + } } + if (err < 0) + return NULL; return type->tp_alloc(type, 0); } From python-checkins at python.org Fri Mar 23 06:17:27 2007 From: python-checkins at python.org (neal.norwitz) Date: Fri, 23 Mar 2007 06:17:27 +0100 (CET) Subject: [Python-checkins] r54540 - python/trunk/Misc/ACKS Message-ID: <20070323051727.9BC831E4015@bag.python.org> Author: neal.norwitz Date: Fri Mar 23 06:17:23 2007 New Revision: 54540 Modified: python/trunk/Misc/ACKS Log: Add Mark Dickinson for SF # 1675423. Modified: python/trunk/Misc/ACKS ============================================================================== --- python/trunk/Misc/ACKS (original) +++ python/trunk/Misc/ACKS Fri Mar 23 06:17:23 2007 @@ -160,6 +160,7 @@ Erik Demaine Roger Dev Toby Dickenson +Mark Dickinson Yves Dionne Daniel Dittmar Walter D?rwald From buildbot at python.org Fri Mar 23 06:38:07 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 23 Mar 2007 05:38:07 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070323053808.298251E4005@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/344 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: guido.van.rossum Build had warnings: warnings test Excerpt from the test logfile: 3 tests failed: test_os test_posixpath test_urllib ====================================================================== ERROR: test_makedir (test.test_os.MakedirTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 376, in setUp os.mkdir(test_support.TESTFN) WindowsError: [Error 183] Cannot create a file when that file already exists: '@test' ====================================================================== ERROR: test_access (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 443, in test_access self.assertRaises(WindowsError, os.utime, test_support.TESTFN, 0) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\unittest.py", line 329, in failUnlessRaises callableObj(*args, **kwargs) TypeError: utime() arg 2 must be a tuple (atime, mtime) ====================================================================== FAIL: test_traversal (test.test_os.WalkTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 313, in test_traversal self.assertEqual(len(all), 4) AssertionError: 5 != 4 ====================================================================== FAIL: test_chdir (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 434, in test_chdir self.assertRaises(WindowsError, os.chdir, test_support.TESTFN) AssertionError: WindowsError not raised ====================================================================== FAIL: test_relpath (test.test_posixpath.PosixPathTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_posixpath.py", line 486, in test_relpath self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a") AssertionError: 'C:\\buildbot_py25\\trunk.mcintyre-windows\\build\\PCbuild\\@test\\@test\\a' != 'a' sincerely, -The Buildbot From python-checkins at python.org Fri Mar 23 11:35:56 2007 From: python-checkins at python.org (martin.v.loewis) Date: Fri, 23 Mar 2007 11:35:56 +0100 (CET) Subject: [Python-checkins] r54541 - in python/trunk: Doc/api/abstract.tex Misc/NEWS Message-ID: <20070323103556.017F51E4011@bag.python.org> Author: martin.v.loewis Date: Fri Mar 23 11:35:49 2007 New Revision: 54541 Modified: python/trunk/Doc/api/abstract.tex python/trunk/Misc/NEWS Log: Patch #1686451: Fix return type for PySequence_{Count,Index,Fast_GET_SIZE}. Will backport. Modified: python/trunk/Doc/api/abstract.tex ============================================================================== --- python/trunk/Doc/api/abstract.tex (original) +++ python/trunk/Doc/api/abstract.tex Fri Mar 23 11:35:49 2007 @@ -810,7 +810,7 @@ the Python statement \samp{del \var{o}[\var{i1}:\var{i2}]}. \end{cfuncdesc} -\begin{cfuncdesc}{int}{PySequence_Count}{PyObject *o, PyObject *value} +\begin{cfuncdesc}{Py_ssize_t}{PySequence_Count}{PyObject *o, PyObject *value} Return the number of occurrences of \var{value} in \var{o}, that is, return the number of keys for which \code{\var{o}[\var{key}] == \var{value}}. On failure, return \code{-1}. This is equivalent to @@ -824,7 +824,7 @@ expression \samp{\var{value} in \var{o}}. \end{cfuncdesc} -\begin{cfuncdesc}{int}{PySequence_Index}{PyObject *o, PyObject *value} +\begin{cfuncdesc}{Py_ssize_t}{PySequence_Index}{PyObject *o, PyObject *value} Return the first index \var{i} for which \code{\var{o}[\var{i}] == \var{value}}. On error, return \code{-1}. This is equivalent to the Python expression \samp{\var{o}.index(\var{value})}. @@ -874,7 +874,7 @@ \versionadded{2.3} \end{cfuncdesc} -\begin{cfuncdesc}{int}{PySequence_Fast_GET_SIZE}{PyObject *o} +\begin{cfuncdesc}{Py_ssize_t}{PySequence_Fast_GET_SIZE}{PyObject *o} Returns the length of \var{o}, assuming that \var{o} was returned by \cfunction{PySequence_Fast()} and that \var{o} is not \NULL. The size can also be gotten by calling Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 23 11:35:49 2007 @@ -711,6 +711,9 @@ Documentation ------------- +- Patch #1686451: Fix return type for + PySequence_{Count,Index,Fast_GET_SIZE}. + - Patch #1679379: add documentation for fnmatch.translate(). - Bug #1629566: clarify the docs on the return values of parsedate() From python-checkins at python.org Fri Mar 23 11:36:01 2007 From: python-checkins at python.org (martin.v.loewis) Date: Fri, 23 Mar 2007 11:36:01 +0100 (CET) Subject: [Python-checkins] r54542 - in python/branches/release25-maint: Doc/api/abstract.tex Misc/NEWS Message-ID: <20070323103601.2E0531E4008@bag.python.org> Author: martin.v.loewis Date: Fri Mar 23 11:35:57 2007 New Revision: 54542 Modified: python/branches/release25-maint/Doc/api/abstract.tex python/branches/release25-maint/Misc/NEWS Log: Patch #1686451: Fix return type for PySequence_{Count,Index,Fast_GET_SIZE}. Modified: python/branches/release25-maint/Doc/api/abstract.tex ============================================================================== --- python/branches/release25-maint/Doc/api/abstract.tex (original) +++ python/branches/release25-maint/Doc/api/abstract.tex Fri Mar 23 11:35:57 2007 @@ -810,7 +810,7 @@ the Python statement \samp{del \var{o}[\var{i1}:\var{i2}]}. \end{cfuncdesc} -\begin{cfuncdesc}{int}{PySequence_Count}{PyObject *o, PyObject *value} +\begin{cfuncdesc}{Py_ssize_t}{PySequence_Count}{PyObject *o, PyObject *value} Return the number of occurrences of \var{value} in \var{o}, that is, return the number of keys for which \code{\var{o}[\var{key}] == \var{value}}. On failure, return \code{-1}. This is equivalent to @@ -824,7 +824,7 @@ expression \samp{\var{value} in \var{o}}. \end{cfuncdesc} -\begin{cfuncdesc}{int}{PySequence_Index}{PyObject *o, PyObject *value} +\begin{cfuncdesc}{Py_ssize_t}{PySequence_Index}{PyObject *o, PyObject *value} Return the first index \var{i} for which \code{\var{o}[\var{i}] == \var{value}}. On error, return \code{-1}. This is equivalent to the Python expression \samp{\var{o}.index(\var{value})}. @@ -874,7 +874,7 @@ \versionadded{2.3} \end{cfuncdesc} -\begin{cfuncdesc}{int}{PySequence_Fast_GET_SIZE}{PyObject *o} +\begin{cfuncdesc}{Py_ssize_t}{PySequence_Fast_GET_SIZE}{PyObject *o} Returns the length of \var{o}, assuming that \var{o} was returned by \cfunction{PySequence_Fast()} and that \var{o} is not \NULL. The size can also be gotten by calling Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Fri Mar 23 11:35:57 2007 @@ -447,6 +447,13 @@ and _CRT_NONSTDC_NO_DEPRECATE. +Documentation +------------- + +- Patch #1686451: Fix return type for + PySequence_{Count,Index,Fast_GET_SIZE}. + + What's New in Python 2.5 (final) ================================ From python-checkins at python.org Fri Mar 23 14:27:16 2007 From: python-checkins at python.org (martin.v.loewis) Date: Fri, 23 Mar 2007 14:27:16 +0100 (CET) Subject: [Python-checkins] r54543 - in python/trunk: Lib/httplib.py Lib/socket.py Misc/NEWS Message-ID: <20070323132716.A0D601E4007@bag.python.org> Author: martin.v.loewis Date: Fri Mar 23 14:27:15 2007 New Revision: 54543 Modified: python/trunk/Lib/httplib.py python/trunk/Lib/socket.py python/trunk/Misc/NEWS Log: Bug #978833: Revert r50844, as it broke _socketobject.dup. Will backport. Modified: python/trunk/Lib/httplib.py ============================================================================== --- python/trunk/Lib/httplib.py (original) +++ python/trunk/Lib/httplib.py Fri Mar 23 14:27:15 2007 @@ -948,8 +948,8 @@ self.__state = _CS_IDLE if response.will_close: - # Pass the socket to the response - self.sock = None + # this effectively passes the connection to the response + self.close() else: # remember this, so we can tell when it is complete self.__response = response Modified: python/trunk/Lib/socket.py ============================================================================== --- python/trunk/Lib/socket.py (original) +++ python/trunk/Lib/socket.py Fri Mar 23 14:27:15 2007 @@ -139,8 +139,6 @@ __slots__ = [] def _dummy(*args): raise error(EBADF, 'Bad file descriptor') - def close(self): - pass # All _delegate_methods must also be initialized here. send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy __getattr__ = _dummy @@ -159,7 +157,6 @@ setattr(self, method, getattr(_sock, method)) def close(self): - self._sock.close() self._sock = _closedsocket() dummy = self._sock._dummy for method in _delegate_methods: Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 23 14:27:15 2007 @@ -199,6 +199,8 @@ Library ------- +- Bug #978833: Revert r50844, as it broke _socketobject.dup. + - Bug #1675967: re patterns pickled with Python 2.4 and earlier can now be unpickled with Python 2.5 and newer. From python-checkins at python.org Fri Mar 23 14:27:30 2007 From: python-checkins at python.org (martin.v.loewis) Date: Fri, 23 Mar 2007 14:27:30 +0100 (CET) Subject: [Python-checkins] r54544 - in python/branches/release25-maint: Lib/httplib.py Lib/socket.py Misc/NEWS Message-ID: <20070323132730.026641E4007@bag.python.org> Author: martin.v.loewis Date: Fri Mar 23 14:27:29 2007 New Revision: 54544 Modified: python/branches/release25-maint/Lib/httplib.py python/branches/release25-maint/Lib/socket.py python/branches/release25-maint/Misc/NEWS Log: Bug #978833: Revert r50844, as it broke _socketobject.dup. Modified: python/branches/release25-maint/Lib/httplib.py ============================================================================== --- python/branches/release25-maint/Lib/httplib.py (original) +++ python/branches/release25-maint/Lib/httplib.py Fri Mar 23 14:27:29 2007 @@ -926,8 +926,8 @@ self.__state = _CS_IDLE if response.will_close: - # Pass the socket to the response - self.sock = None + # this effectively passes the connection to the response + self.close() else: # remember this, so we can tell when it is complete self.__response = response Modified: python/branches/release25-maint/Lib/socket.py ============================================================================== --- python/branches/release25-maint/Lib/socket.py (original) +++ python/branches/release25-maint/Lib/socket.py Fri Mar 23 14:27:29 2007 @@ -139,8 +139,6 @@ __slots__ = [] def _dummy(*args): raise error(EBADF, 'Bad file descriptor') - def close(self): - pass # All _delegate_methods must also be initialized here. send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy __getattr__ = _dummy @@ -159,7 +157,6 @@ setattr(self, method, getattr(_sock, method)) def close(self): - self._sock.close() self._sock = _closedsocket() dummy = self._sock._dummy for method in _delegate_methods: Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Fri Mar 23 14:27:29 2007 @@ -217,6 +217,8 @@ Library ------- +- Bug #978833: Revert r50844, as it broke _socketobject.dup. + - Bug #1675967: re patterns pickled with Python 2.4 and earlier can now be unpickled with Python 2.5. From buildbot at python.org Fri Mar 23 15:36:10 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 23 Mar 2007 14:36:10 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 2.5 Message-ID: <20070323143610.212A31E4007@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%25202.5/builds/227 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: martin.v.loewis Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_socket ====================================================================== FAIL: testInterruptedTimeout (test.test_socket.TCPTimeoutTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/net/ringneck/scratch1/nnorwitz/python/2.5.norwitz-tru64/build/Lib/test/test_socket.py", line 872, in testInterruptedTimeout self.fail("got Alarm in wrong place") AssertionError: got Alarm in wrong place sincerely, -The Buildbot From jimjjewett at gmail.com Fri Mar 23 18:48:52 2007 From: jimjjewett at gmail.com (Jim Jewett) Date: Fri, 23 Mar 2007 13:48:52 -0400 Subject: [Python-checkins] r54539 - in python/trunk: Lib/string.py Misc/NEWS Objects/typeobject.c In-Reply-To: <20070323045846.0C6001E4005@bag.python.org> References: <20070323045846.0C6001E4005@bag.python.org> Message-ID: (Please note that most replies should trim at least one list from the Cc) On 3/23/07, guido.van.rossum wrote: > Note: without the change to string.py, lots of spurious warnings happen. > What's going on there? I assume it was a defensive measure for subclasses of both Template and X, where X has its own metaclass (which might have an __init__ that shouldn't be ignored). This is where cooperative classes get ugly. You could argue that the "correct" code is to not bother making the super call if it would go all the way to object (or even type), but there isn't a good way to spell that. > + # A super call makes no sense since type() doesn't define __init__(). > + # (Or does it? And should type.__init__() accept three args?) > + # super(_TemplateMetaclass, cls).__init__(name, bases, dct) In this particular case, you could define a type.__init__ that did nothing. (If the signature were wrong, type.__new__ would have already caught it. If __new__ and __init__ are seeing something different, then the change was probably intentional.) The problem isn't really limited to type.__init__ though. You'll sometimes see similar patterns for __del__, close, save, etc. The main difference is that they have to either catch an error or check first, since object doesn't have an implementation of those methods. object.__init__ doesn't really do anything either, except check for errors. Getting rid of it should have the same effect as complaining about parameters. The ideal solution (discussion of which probably ought to stay on python-ideas) might be to replace object.__init__ with some sort of PlaceHolder object that raises an error *unless* called through a cooperative super. This PlaceHolder would also be useful for AbstractBaseClasses/Interfaces. PlaceHolder still wouldn't deal with the original concern of verifying that all arguments had already been stripped and used; but the ABCs might be able to. -jJ > Modified: python/trunk/Lib/string.py > ============================================================================== > --- python/trunk/Lib/string.py (original) > +++ python/trunk/Lib/string.py Fri Mar 23 05:58:42 2007 > @@ -108,7 +108,9 @@ > """ > > def __init__(cls, name, bases, dct): > - super(_TemplateMetaclass, cls).__init__(name, bases, dct) > + # A super call makes no sense since type() doesn't define __init__(). > + # (Or does it? And should type.__init__() accept three args?) > + # super(_TemplateMetaclass, cls).__init__(name, bases, dct) > if 'pattern' in dct: > pattern = cls.pattern > else: From guido at python.org Fri Mar 23 19:41:47 2007 From: guido at python.org (Guido van Rossum) Date: Fri, 23 Mar 2007 11:41:47 -0700 Subject: [Python-checkins] r54539 - in python/trunk: Lib/string.py Misc/NEWS Objects/typeobject.c In-Reply-To: References: <20070323045846.0C6001E4005@bag.python.org> Message-ID: On 3/23/07, Jim Jewett wrote: > (Please note that most replies should trim at least one list from the Cc) [-dev, -ideas] > On 3/23/07, guido.van.rossum wrote: > > Note: without the change to string.py, lots of spurious warnings happen. > > What's going on there? > > I assume it was a defensive measure for subclasses of both Template > and X, where X has its own metaclass (which might have an __init__ > that shouldn't be ignored). > > This is where cooperative classes get ugly. You could argue that the > "correct" code is to not bother making the super call if it would go > all the way to object (or even type), but there isn't a good way to > spell that. *Correct* code knows whether it is defining or extending a method, so it always knows whether to call the super method or not. > > + # A super call makes no sense since type() doesn't define __init__(). > > + # (Or does it? And should type.__init__() accept three args?) > > + # super(_TemplateMetaclass, cls).__init__(name, bases, dct) > > In this particular case, you could define a type.__init__ that did > nothing. (If the signature were wrong, type.__new__ would have > already caught it. If __new__ and __init__ are seeing something > different, then the change was probably intentional.) No, super calls to __init__ may see different arguments than __new__. I'm adding a type_init() that insists on the minimal (default) signature and calls object.__init__() with no args (just in case object.__init__() ever grows useful functionality :-). > The problem isn't really limited to type.__init__ though. You'll > sometimes see similar patterns for __del__, close, save, etc. Again, it seems to be caused by confusion about whether one is defining or extending the method. This is probably not clearly documented for __del__(), but the intention was that object does *not* define __del__(). For close() and save() I would venture it is definitely a bug in the application if they don't know whether they are defining or extending it. You can't fix problems caused by muddled thinking. > The > main difference is that they have to either catch an error or check > first, since object doesn't have an implementation of those methods. > object.__init__ doesn't really do anything either, except check for > errors. Getting rid of it should have the same effect as complaining > about parameters. Getting rid of what? > The ideal solution (discussion of which probably ought to stay on > python-ideas) might be to replace object.__init__ with some sort of > PlaceHolder object that raises an error *unless* called through a > cooperative super. This PlaceHolder would also be useful for > AbstractBaseClasses/Interfaces. PlaceHolder still wouldn't deal with > the original concern of verifying that all arguments had already been > stripped and used; but the ABCs might be able to. Sounds more like something certain cooperative frameworks might want to add than something the core language should provide. -- --Guido van Rossum (home page: http://www.python.org/~guido/) From python-checkins at python.org Fri Mar 23 19:53:08 2007 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 23 Mar 2007 19:53:08 +0100 (CET) Subject: [Python-checkins] r54545 - in python/trunk: Lib/string.py Objects/typeobject.c Message-ID: <20070323185308.05B371E4008@bag.python.org> Author: guido.van.rossum Date: Fri Mar 23 19:53:03 2007 New Revision: 54545 Modified: python/trunk/Lib/string.py python/trunk/Objects/typeobject.c Log: Add a type.__init__() method that enforces the same signature as type.__new__(), and then calls object.__init__(cls), just to be anal. This allows us to restore the code in string.py's _TemplateMetaclass that called super(...).__init__(name, bases, dct), which I commented out yesterday since it broke due to the stricter argument checking added to object.__init__(). Modified: python/trunk/Lib/string.py ============================================================================== --- python/trunk/Lib/string.py (original) +++ python/trunk/Lib/string.py Fri Mar 23 19:53:03 2007 @@ -108,9 +108,7 @@ """ def __init__(cls, name, bases, dct): - # A super call makes no sense since type() doesn't define __init__(). - # (Or does it? And should type.__init__() accept three args?) - # super(_TemplateMetaclass, cls).__init__(name, bases, dct) + super(_TemplateMetaclass, cls).__init__(name, bases, dct) if 'pattern' in dct: pattern = cls.pattern else: Modified: python/trunk/Objects/typeobject.c ============================================================================== --- python/trunk/Objects/typeobject.c (original) +++ python/trunk/Objects/typeobject.c Fri Mar 23 19:53:03 2007 @@ -1684,6 +1684,39 @@ } #endif +/* Forward */ +static int +object_init(PyObject *self, PyObject *args, PyObject *kwds); + +static int +type_init(PyObject *cls, PyObject *args, PyObject *kwds) +{ + int res; + + assert(args != NULL && PyTuple_Check(args)); + assert(kwds == NULL || PyDict_Check(kwds)); + + if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds) != 0) { + PyErr_SetString(PyExc_TypeError, + "type.__init__() takes no keyword arguments"); + return -1; + } + + if (args != NULL && PyTuple_Check(args) && + (PyTuple_GET_SIZE(args) != 1 && PyTuple_GET_SIZE(args) != 3)) { + PyErr_SetString(PyExc_TypeError, + "type.__init__() takes 1 or 3 arguments"); + return -1; + } + + /* Call object.__init__(self) now. */ + /* XXX Could call super(type, cls).__init__() but what's the point? */ + args = PyTuple_GetSlice(args, 0, 0); + res = object_init(cls, args, NULL); + Py_DECREF(args); + return res; +} + static PyObject * type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) { @@ -2381,7 +2414,7 @@ 0, /* tp_descr_get */ 0, /* tp_descr_set */ offsetof(PyTypeObject, tp_dict), /* tp_dictoffset */ - 0, /* tp_init */ + type_init, /* tp_init */ 0, /* tp_alloc */ type_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ From python-checkins at python.org Fri Mar 23 19:54:13 2007 From: python-checkins at python.org (facundo.batista) Date: Fri, 23 Mar 2007 19:54:13 +0100 (CET) Subject: [Python-checkins] r54546 - in python/trunk: Doc/lib/libhttplib.tex Doc/lib/libsocket.tex Lib/httplib.py Lib/socket.py Lib/test/test_httplib.py Lib/test/test_socket.py Misc/NEWS Message-ID: <20070323185413.35BCE1E4008@bag.python.org> Author: facundo.batista Date: Fri Mar 23 19:54:07 2007 New Revision: 54546 Modified: python/trunk/Doc/lib/libhttplib.tex python/trunk/Doc/lib/libsocket.tex python/trunk/Lib/httplib.py python/trunk/Lib/socket.py python/trunk/Lib/test/test_httplib.py python/trunk/Lib/test/test_socket.py python/trunk/Misc/NEWS Log: Added a 'create_connect()' function to socket.py, which creates a connection with an optional timeout, and modified httplib.py to use this function in HTTPConnection. Applies patch 1676823. Modified: python/trunk/Doc/lib/libhttplib.tex ============================================================================== --- python/trunk/Doc/lib/libhttplib.tex (original) +++ python/trunk/Doc/lib/libhttplib.tex Fri Mar 23 19:54:07 2007 @@ -26,18 +26,28 @@ The module provides the following classes: -\begin{classdesc}{HTTPConnection}{host\optional{, port}} +\begin{classdesc}{HTTPConnection}{host\optional{, port\optional{, + strict\optional{, timeout}}}} An \class{HTTPConnection} instance represents one transaction with an HTTP server. It should be instantiated passing it a host and optional port number. If no port number is passed, the port is extracted from the host string if it has the form \code{\var{host}:\var{port}}, else the default HTTP port (80) is -used. For example, the following calls all create instances that connect to +used. +When True the optional parameter \var{strict} +causes \code{BadStatusLine} to be raised if the status line can't be parsed +as a valid HTTP/1.0 or 1.1 status line. If the optional \var{timeout} +parameter is given, connection attempts will timeout after that many +seconds (if no timeout is passed, or is passed as None, the global default +timeout setting is used). + +For example, the following calls all create instances that connect to the server at the same host and port: \begin{verbatim} >>> h1 = httplib.HTTPConnection('www.cwi.nl') >>> h2 = httplib.HTTPConnection('www.cwi.nl:80') >>> h3 = httplib.HTTPConnection('www.cwi.nl', 80) +>>> h3 = httplib.HTTPConnection('www.cwi.nl', 80, timeout=10) \end{verbatim} \versionadded{2.0} \end{classdesc} Modified: python/trunk/Doc/lib/libsocket.tex ============================================================================== --- python/trunk/Doc/lib/libsocket.tex (original) +++ python/trunk/Doc/lib/libsocket.tex Fri Mar 23 19:54:07 2007 @@ -170,6 +170,15 @@ \versionadded{2.3} \end{datadesc} +\begin{funcdesc}{create_connection}{address\optional{, timeout}} +Connects to the \var{address} received (as usual, a pair host/port), with +an optional timeout for the connection. Specially useful for higher-level +protocols, it is not normally used directly from application-level code. +Passing the optional \var{timeout} parameter will set the timeout on the +socket instance (if not present, or passed as None, the global default +timeout setting is used). +\end{funcdesc} + \begin{funcdesc}{getaddrinfo}{host, port\optional{, family\optional{, socktype\optional{, proto\optional{, flags}}}}} Modified: python/trunk/Lib/httplib.py ============================================================================== --- python/trunk/Lib/httplib.py (original) +++ python/trunk/Lib/httplib.py Fri Mar 23 19:54:07 2007 @@ -625,7 +625,8 @@ debuglevel = 0 strict = 0 - def __init__(self, host, port=None, strict=None): + def __init__(self, host, port=None, strict=None, timeout=None): + self.timeout = timeout self.sock = None self._buffer = [] self.__response = None @@ -658,25 +659,7 @@ def connect(self): """Connect to the host and port specified in __init__.""" - msg = "getaddrinfo returns an empty list" - for res in socket.getaddrinfo(self.host, self.port, 0, - socket.SOCK_STREAM): - af, socktype, proto, canonname, sa = res - try: - self.sock = socket.socket(af, socktype, proto) - if self.debuglevel > 0: - print "connect: (%s, %s)" % (self.host, self.port) - self.sock.connect(sa) - except socket.error, msg: - if self.debuglevel > 0: - print 'connect fail:', (self.host, self.port) - if self.sock: - self.sock.close() - self.sock = None - continue - break - if not self.sock: - raise socket.error, msg + self.sock = socket.create_connection((self.host,self.port), self.timeout) def close(self): """Close the connection to the HTTP server.""" Modified: python/trunk/Lib/socket.py ============================================================================== --- python/trunk/Lib/socket.py (original) +++ python/trunk/Lib/socket.py Fri Mar 23 19:54:07 2007 @@ -24,6 +24,7 @@ ssl() -- secure socket layer support (only available if configured) socket.getdefaulttimeout() -- get the default timeout value socket.setdefaulttimeout() -- set the default timeout value +create_connection() -- connects to an address, with an optional timeout [*] not available on all platforms! @@ -412,3 +413,31 @@ if not line: raise StopIteration return line + + +def create_connection(address, timeout=None): + """Connect to address (host, port) with an optional timeout. + + Provides access to socketobject timeout for higher-level + protocols. Passing a timeout will set the timeout on the + socket instance (if not present, or passed as None, the + default global timeout setting will be used). + """ + + msg = "getaddrinfo returns an empty list" + host, port = address + for res in getaddrinfo(host, port, 0, SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket(af, socktype, proto) + if timeout is not None: + sock.settimeout(timeout) + sock.connect(sa) + return sock + + except error, msg: + if sock is not None: + sock.close() + + raise error, msg Modified: python/trunk/Lib/test/test_httplib.py ============================================================================== --- python/trunk/Lib/test/test_httplib.py (original) +++ python/trunk/Lib/test/test_httplib.py Fri Mar 23 19:54:07 2007 @@ -1,6 +1,7 @@ import httplib import StringIO import sys +import socket from unittest import TestCase @@ -149,8 +150,47 @@ def test_responses(self): self.assertEquals(httplib.responses[httplib.NOT_FOUND], "Not Found") +PORT = 50003 +HOST = "localhost" + +class TimeoutTest(TestCase): + + def setUp(self): + self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + global PORT + PORT = test_support.bind_port(self.serv, HOST, PORT) + self.serv.listen(1) + + def tearDown(self): + self.serv.close() + self.serv = None + + def testTimeoutAttribute(self): + '''This will prove that the timeout gets through + HTTPConnection and into the socket. + ''' + # default + httpConn = httplib.HTTPConnection(HOST, PORT) + httpConn.connect() + self.assertTrue(httpConn.sock.gettimeout() is None) + + # a value + httpConn = httplib.HTTPConnection(HOST, PORT, timeout=10) + httpConn.connect() + self.assertEqual(httpConn.sock.gettimeout(), 10) + + # None, having other default + previous = socket.getdefaulttimeout() + socket.setdefaulttimeout(10) + httpConn = httplib.HTTPConnection(HOST, PORT, timeout=None) + httpConn.connect() + socket.setdefaulttimeout(previous) + self.assertEqual(httpConn.sock.gettimeout(), 10) + + def test_main(verbose=None): - test_support.run_unittest(HeaderTests, OfflineTest, BasicTest) + test_support.run_unittest(HeaderTests, OfflineTest, BasicTest, TimeoutTest) if __name__ == '__main__': test_main() Modified: python/trunk/Lib/test/test_socket.py ============================================================================== --- python/trunk/Lib/test/test_socket.py (original) +++ python/trunk/Lib/test/test_socket.py Fri Mar 23 19:54:07 2007 @@ -75,7 +75,7 @@ Note, the server setup function cannot call any blocking functions that rely on the client thread during setup, - unless serverExplicityReady() is called just before + unless serverExplicitReady() is called just before the blocking call (such as in setting up a client/server connection and performing the accept() in setUp(). """ @@ -810,6 +810,85 @@ bufsize = 2 # Exercise the buffering code +class NetworkConnectionTest(object): + """Prove network connection.""" + def clientSetUp(self): + self.cli = socket.create_connection((HOST, PORT)) + self.serv_conn = self.cli + +class BasicTCPTest2(NetworkConnectionTest, BasicTCPTest): + """Tests that NetworkConnection does not break existing TCP functionality. + """ + +class NetworkConnectionAttributesTest(unittest.TestCase): + + def setUp(self): + self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + global PORT + PORT = test_support.bind_port(self.serv, HOST, PORT) + self.serv.listen(1) + + def tearDown(self): + if self.serv: + self.serv.close() + self.serv = None + + def testWithoutServer(self): + self.tearDown() + self.failUnlessRaises(socket.error, lambda: socket.create_connection((HOST, PORT))) + + def testTimeoutAttribute(self): + # default + sock = socket.create_connection((HOST, PORT)) + self.assertTrue(sock.gettimeout() is None) + + # a value, named + sock = socket.create_connection((HOST, PORT), timeout=10) + self.assertEqual(sock.gettimeout(), 10) + + # a value, just the value + sock = socket.create_connection((HOST, PORT), 10) + self.assertEqual(sock.gettimeout(), 10) + + # None, having other default + previous = socket.getdefaulttimeout() + socket.setdefaulttimeout(10) + sock = socket.create_connection((HOST, PORT), timeout=None) + socket.setdefaulttimeout(previous) + self.assertEqual(sock.gettimeout(), 10) + + def testFamily(self): + sock = socket.create_connection((HOST, PORT), timeout=10) + self.assertEqual(sock.family, 2) + + +def threadedServer(delay): + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + global PORT + PORT = test_support.bind_port(serv, HOST, PORT) + serv.listen(1) + conn, addr = serv.accept() + time.sleep(delay) + conn.send("done!") + conn.close() + +class NetworkConnectionBehaviourTest(unittest.TestCase): + def testInsideTimeout(self): + threading.Thread(target=threadedServer, args=(3,)).start() + time.sleep(.1) + sock = socket.create_connection((HOST, PORT)) + data = sock.recv(5) + self.assertEqual(data, "done!") + + def testOutsideTimeout(self): + threading.Thread(target=threadedServer, args=(3,)).start() + time.sleep(.1) + sock = socket.create_connection((HOST, PORT), timeout=1) + self.failUnlessRaises(socket.timeout, lambda: sock.recv(5)) + + class Urllib2FileobjectTest(unittest.TestCase): # urllib2.HTTPHandler has "borrowed" socket._fileobject, and requires that @@ -977,7 +1056,7 @@ def test_main(): tests = [GeneralModuleTests, BasicTCPTest, TCPCloserTest, TCPTimeoutTest, - TestExceptions, BufferIOTest] + TestExceptions, BufferIOTest, BasicTCPTest2] if sys.platform != 'mac': tests.extend([ BasicUDPTest, UDPTimeoutTest ]) @@ -988,6 +1067,8 @@ LineBufferedFileObjectClassTestCase, SmallBufferedFileObjectClassTestCase, Urllib2FileobjectTest, + NetworkConnectionAttributesTest, + NetworkConnectionBehaviourTest, ]) if hasattr(socket, "socketpair"): tests.append(BasicSocketPairTest) Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 23 19:54:07 2007 @@ -199,6 +199,10 @@ Library ------- +- Patch #1676823: Added create_connection() to socket.py, which may be + called with a timeout, and use it from httplib (whose HTTPConnection + now accepts an optional timeout). + - Bug #978833: Revert r50844, as it broke _socketobject.dup. - Bug #1675967: re patterns pickled with Python 2.4 and earlier can From python-checkins at python.org Fri Mar 23 20:39:09 2007 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 23 Mar 2007 20:39:09 +0100 (CET) Subject: [Python-checkins] r54547 - python/trunk/Misc/NEWS Message-ID: <20070323193909.23A731E400A@bag.python.org> Author: guido.van.rossum Date: Fri Mar 23 20:39:01 2007 New Revision: 54547 Modified: python/trunk/Misc/NEWS Log: Add note about type.__init__(). Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Fri Mar 23 20:39:01 2007 @@ -22,7 +22,8 @@ either allows excess arguments is when it is not overridden and the other one is. For backwards compatibility, when both are overridden, it is a deprecation warning (for now; maybe a Py3k - warning later). + warning later). Also, type.__init__() insists on the same signature + as supported by type.__new__(). - Patch #1675423: PyComplex_AsCComplex() now tries to convert an object to complex using its __complex__() method before falling back to the From buildbot at python.org Fri Mar 23 20:41:08 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 23 Mar 2007 19:41:08 +0000 Subject: [Python-checkins] buildbot warnings in g4 osx.4 trunk Message-ID: <20070323194108.502691E400D@bag.python.org> The Buildbot has detected a new failure of g4 osx.4 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/g4%2520osx.4%2520trunk/builds/1893 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: facundo.batista,guido.van.rossum Build had warnings: warnings test Excerpt from the test logfile: 2 tests failed: test_httplib test_socket ====================================================================== ERROR: This will prove that the timeout gets through ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/buildslave/bb/trunk.psf-g4/build/Lib/test/test_httplib.py", line 187, in testTimeoutAttribute httpConn.connect() File "/Users/buildslave/bb/trunk.psf-g4/build/Lib/httplib.py", line 662, in connect self.sock = socket.create_connection((self.host,self.port), self.timeout) File "/Users/buildslave/bb/trunk.psf-g4/build/Lib/socket.py", line 443, in create_connection raise error, msg timeout: timed out ====================================================================== FAIL: testDefaultTimeout (test.test_socket.GeneralModuleTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/buildslave/bb/trunk.psf-g4/build/Lib/test/test_socket.py", line 366, in testDefaultTimeout self.assertEqual(socket.getdefaulttimeout(), None) AssertionError: 10.0 != None ====================================================================== FAIL: testTimeoutAttribute (test.test_socket.NetworkConnectionAttributesTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "/Users/buildslave/bb/trunk.psf-g4/build/Lib/test/test_socket.py", line 844, in testTimeoutAttribute self.assertTrue(sock.gettimeout() is None) AssertionError make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Fri Mar 23 20:55:29 2007 From: python-checkins at python.org (thomas.heller) Date: Fri, 23 Mar 2007 20:55:29 +0100 (CET) Subject: [Python-checkins] r54553 - python/trunk/Modules/_ctypes/_ctypes.c Message-ID: <20070323195529.9D4E51E400D@bag.python.org> Author: thomas.heller Date: Fri Mar 23 20:55:27 2007 New Revision: 54553 Modified: python/trunk/Modules/_ctypes/_ctypes.c Log: Prevent creation (followed by a segfault) of array types when the size overflows the valid Py_ssize_t range. Check return values of PyMem_Malloc. Will backport to release25-maint. Modified: python/trunk/Modules/_ctypes/_ctypes.c ============================================================================== --- python/trunk/Modules/_ctypes/_ctypes.c (original) +++ python/trunk/Modules/_ctypes/_ctypes.c Fri Mar 23 20:55:27 2007 @@ -1002,6 +1002,12 @@ } itemsize = itemdict->size; + if (length * itemsize < 0) { + PyErr_SetString(PyExc_OverflowError, + "array too large"); + return NULL; + } + itemalign = itemdict->align; stgdict->size = itemsize * length; @@ -2176,7 +2182,7 @@ 0, /* tp_free */ }; -static void CData_MallocBuffer(CDataObject *obj, StgDictObject *dict) +static int CData_MallocBuffer(CDataObject *obj, StgDictObject *dict) { if ((size_t)dict->size <= sizeof(obj->b_value)) { /* No need to call malloc, can use the default buffer */ @@ -2193,10 +2199,15 @@ 33% of the creation time for c_int(). */ obj->b_ptr = (char *)PyMem_Malloc(dict->size); + if (obj->b_ptr == NULL) { + PyErr_NoMemory(); + return -1; + } obj->b_needsfree = 1; memset(obj->b_ptr, 0, dict->size); } obj->b_size = dict->size; + return 0; } PyObject * @@ -2228,7 +2239,10 @@ cmem->b_base = (CDataObject *)base; cmem->b_index = index; } else { /* copy contents of adr */ - CData_MallocBuffer(cmem, dict); + if (-1 == CData_MallocBuffer(cmem, dict)) { + return NULL; + Py_DECREF(cmem); + } memcpy(cmem->b_ptr, adr, dict->size); cmem->b_index = index; } @@ -2441,7 +2455,10 @@ obj->b_objects = NULL; obj->b_length = dict->length; - CData_MallocBuffer(obj, dict); + if (-1 == CData_MallocBuffer(obj, dict)) { + Py_DECREF(obj); + return NULL; + } return (PyObject *)obj; } /*****************************************************************/ From jimjjewett at gmail.com Fri Mar 23 20:55:50 2007 From: jimjjewett at gmail.com (Jim Jewett) Date: Fri, 23 Mar 2007 15:55:50 -0400 Subject: [Python-checkins] r54539 - in python/trunk: Lib/string.py Misc/NEWS Objects/typeobject.c In-Reply-To: References: <20070323045846.0C6001E4005@bag.python.org> Message-ID: On 3/23/07, Guido van Rossum wrote: > On 3/23/07, Jim Jewett wrote: > > (Please note that most replies should trim at least one list from the Cc) > > [-dev, -ideas] > > > On 3/23/07, guido.van.rossum wrote: > > > Note: without the change to string.py, lots of spurious warnings happen. > > > What's going on there? > > > > I assume it was a defensive measure for subclasses of both Template > > and X, where X has its own metaclass (which might have an __init__ > > that shouldn't be ignored). > > > > This is where cooperative classes get ugly. You could argue that the > > "correct" code is to not bother making the super call if it would go > > all the way to object (or even type), but there isn't a good way to > > spell that. > > *Correct* code knows whether it is defining or extending a method, so > it always knows whether to call the super method or not. class Window: def close(): # No supertype but object class DBConnection: def close(): # No supertype but object class DBView(DBConnection, Window): ??? DBConnection is defining close. There is no super.close on most instances. So it can't call close blindly. But if it doesn't call super.close, then DBView has to call both superclasses by name -- and there isn't much point to super. One workaround is to make both Window and DBConnection subclasses of (Abstract Base Class/Interface) LimitedResource. LimitedResource.close wouldn't do anything, but it would know not to pass the call on any farther. This is arguably the most correct, but perhaps the worst in practice. You lose duck-typing, you need to agree on a framework, and you get lots of extra do-nothing function calls. > > > + # A super call makes no sense since type() doesn't define __init__(). > > > + # (Or does it? And should type.__init__() accept three args?) > > > + # super(_TemplateMetaclass, cls).__init__(name, bases, dct) > > In this particular case, you could define a type.__init__ that did > > nothing. (If the signature were wrong, type.__new__ would have > > already caught it. If __new__ and __init__ are seeing something > > different, then the change was probably intentional.) > No, super calls to __init__ may see different arguments than __new__. Yeah, but only if the arguments to at least one of them are intentionally modified. > I'm adding a type_init() that insists on the minimal (default) > signature and calls object.__init__() with no args (just in case > object.__init__() ever grows useful functionality :-). And you get the same "that would be annoying" problem you were trying to avoid. class MyMeta(type): def __new__(cls, name, bases, dict, myflags): ... return super(MyMeta, cls).__new__(name, bases, dict) def __init__(cls, name, bases, dict, myflags): """Do-nothing junk function to shut up type.__init__. Warning: This will still fail if there are any other metaclasses that wanted their own special argument like myflags...""" return super(MyMeta, cls).__init__(name, bases, dict) > > The problem isn't really limited to type.__init__ though. You'll > > sometimes see similar patterns for __del__, close, save, etc. > Again, it seems to be caused by confusion about whether one is > defining or extending the method. This is probably not clearly > documented for __del__(), but the intention was that object does *not* > define __del__(). The example abouve makes just as much sense with __del__. Most __del__ methods boil down to self.close(). > For close() and save() I would venture it is > definitely a bug in the application if they don't know whether they > are defining or extending it. With single-inheritance, yes. For a (java) final class, yes. For a class that might be on one branch of multiple inheritance, it depends on the instance. > > The > > main difference is that they have to either catch an error or check > > first, since object doesn't have an implementation of those methods. > > object.__init__ doesn't really do anything either, except check for > > errors. Getting rid of it should have the same effect as complaining > > about parameters. > Getting rid of what? Getting rid of object.__init__. >>> object(1,2,3) Traceback (most recent call last): File "", line 1, in object(1,2,3) TypeError: default __new__ takes no parameters >>> object.asdf(1,2,3) isn't all that much better than what you get for a missing method >>> object(1,2,3) Traceback (most recent call last): File "", line 1, in object(1,2,3) AttributeError: type object 'object' has no attribute '__init__' -jJ From python-checkins at python.org Fri Mar 23 20:56:46 2007 From: python-checkins at python.org (thomas.heller) Date: Fri, 23 Mar 2007 20:56:46 +0100 (CET) Subject: [Python-checkins] r54554 - python/branches/release25-maint/Modules/_ctypes/_ctypes.c Message-ID: <20070323195646.EC0CE1E400F@bag.python.org> Author: thomas.heller Date: Fri Mar 23 20:56:45 2007 New Revision: 54554 Modified: python/branches/release25-maint/Modules/_ctypes/_ctypes.c Log: Prevent creation (followed by a segfault) of array types when the size overflows the valid Py_ssize_t range. Check return values of PyMem_Malloc. Backported from trunk. Modified: python/branches/release25-maint/Modules/_ctypes/_ctypes.c ============================================================================== --- python/branches/release25-maint/Modules/_ctypes/_ctypes.c (original) +++ python/branches/release25-maint/Modules/_ctypes/_ctypes.c Fri Mar 23 20:56:45 2007 @@ -1002,6 +1002,12 @@ } itemsize = itemdict->size; + if (length * itemsize < 0) { + PyErr_SetString(PyExc_OverflowError, + "array too large"); + return NULL; + } + itemalign = itemdict->align; stgdict->size = itemsize * length; @@ -2176,7 +2182,7 @@ 0, /* tp_free */ }; -static void CData_MallocBuffer(CDataObject *obj, StgDictObject *dict) +static int CData_MallocBuffer(CDataObject *obj, StgDictObject *dict) { if ((size_t)dict->size <= sizeof(obj->b_value)) { /* No need to call malloc, can use the default buffer */ @@ -2193,10 +2199,15 @@ 33% of the creation time for c_int(). */ obj->b_ptr = (char *)PyMem_Malloc(dict->size); + if (obj->b_ptr == NULL) { + PyErr_NoMemory(); + return -1; + } obj->b_needsfree = 1; memset(obj->b_ptr, 0, dict->size); } obj->b_size = dict->size; + return 0; } PyObject * @@ -2228,7 +2239,10 @@ cmem->b_base = (CDataObject *)base; cmem->b_index = index; } else { /* copy contents of adr */ - CData_MallocBuffer(cmem, dict); + if (-1 == CData_MallocBuffer(cmem, dict)) { + return NULL; + Py_DECREF(cmem); + } memcpy(cmem->b_ptr, adr, dict->size); cmem->b_index = index; } @@ -2441,7 +2455,10 @@ obj->b_objects = NULL; obj->b_length = dict->length; - CData_MallocBuffer(obj, dict); + if (-1 == CData_MallocBuffer(obj, dict)) { + Py_DECREF(obj); + return NULL; + } return (PyObject *)obj; } /*****************************************************************/ From jimjjewett at gmail.com Fri Mar 23 21:19:34 2007 From: jimjjewett at gmail.com (Jim Jewett) Date: Fri, 23 Mar 2007 16:19:34 -0400 Subject: [Python-checkins] r54545 - in python/trunk: Lib/string.py Objects/typeobject.c In-Reply-To: <20070323185308.05B371E4008@bag.python.org> References: <20070323185308.05B371E4008@bag.python.org> Message-ID: Why just assert? You're checking it every run-time anyhow, so you might as well raise an error. Or is the assert secretly acting as a compiler directive as well? On 3/23/07, guido.van.rossum wrote: ============================================================================== > --- python/trunk/Objects/typeobject.c (original) > +++ python/trunk/Objects/typeobject.c Fri Mar 23 19:53:03 2007 > +type_init(PyObject *cls, PyObject *args, PyObject *kwds) > +{ ... > + assert(kwds == NULL || PyDict_Check(kwds)); ... > + if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds) != 0) { > + PyErr_SetString(PyExc_TypeError, > + "type.__init__() takes no keyword arguments"); > + return -1; > + } > + assert(args != NULL && PyTuple_Check(args)); ... > + if (args != NULL && PyTuple_Check(args) && > + (PyTuple_GET_SIZE(args) != 1 && PyTuple_GET_SIZE(args) != 3)) { > + PyErr_SetString(PyExc_TypeError, > + "type.__init__() takes 1 or 3 arguments"); > + return -1; > + } -jJ From python-checkins at python.org Fri Mar 23 21:23:15 2007 From: python-checkins at python.org (facundo.batista) Date: Fri, 23 Mar 2007 21:23:15 +0100 (CET) Subject: [Python-checkins] r54555 - python/trunk/Lib/test/test_httplib.py python/trunk/Lib/test/test_socket.py Message-ID: <20070323202315.E780B1E4008@bag.python.org> Author: facundo.batista Date: Fri Mar 23 21:23:08 2007 New Revision: 54555 Modified: python/trunk/Lib/test/test_httplib.py python/trunk/Lib/test/test_socket.py Log: Surrounded with try/finally to socket's default timeout setting changes in the tests, so failing one test won't produce strange results in others. Also relaxed the timeout settings in the test (where actually the value didn't mean anything). Modified: python/trunk/Lib/test/test_httplib.py ============================================================================== --- python/trunk/Lib/test/test_httplib.py (original) +++ python/trunk/Lib/test/test_httplib.py Fri Mar 23 21:23:08 2007 @@ -176,17 +176,19 @@ self.assertTrue(httpConn.sock.gettimeout() is None) # a value - httpConn = httplib.HTTPConnection(HOST, PORT, timeout=10) + httpConn = httplib.HTTPConnection(HOST, PORT, timeout=30) httpConn.connect() - self.assertEqual(httpConn.sock.gettimeout(), 10) + self.assertEqual(httpConn.sock.gettimeout(), 30) # None, having other default previous = socket.getdefaulttimeout() - socket.setdefaulttimeout(10) - httpConn = httplib.HTTPConnection(HOST, PORT, timeout=None) - httpConn.connect() - socket.setdefaulttimeout(previous) - self.assertEqual(httpConn.sock.gettimeout(), 10) + socket.setdefaulttimeout(30) + try: + httpConn = httplib.HTTPConnection(HOST, PORT, timeout=None) + httpConn.connect() + finally: + socket.setdefaulttimeout(previous) + self.assertEqual(httpConn.sock.gettimeout(), 30) def test_main(verbose=None): Modified: python/trunk/Lib/test/test_socket.py ============================================================================== --- python/trunk/Lib/test/test_socket.py (original) +++ python/trunk/Lib/test/test_socket.py Fri Mar 23 21:23:08 2007 @@ -844,22 +844,24 @@ self.assertTrue(sock.gettimeout() is None) # a value, named - sock = socket.create_connection((HOST, PORT), timeout=10) - self.assertEqual(sock.gettimeout(), 10) + sock = socket.create_connection((HOST, PORT), timeout=30) + self.assertEqual(sock.gettimeout(), 30) # a value, just the value - sock = socket.create_connection((HOST, PORT), 10) - self.assertEqual(sock.gettimeout(), 10) + sock = socket.create_connection((HOST, PORT), 30) + self.assertEqual(sock.gettimeout(), 30) # None, having other default previous = socket.getdefaulttimeout() - socket.setdefaulttimeout(10) - sock = socket.create_connection((HOST, PORT), timeout=None) - socket.setdefaulttimeout(previous) - self.assertEqual(sock.gettimeout(), 10) + socket.setdefaulttimeout(30) + try: + sock = socket.create_connection((HOST, PORT), timeout=None) + finally: + socket.setdefaulttimeout(previous) + self.assertEqual(sock.gettimeout(), 30) def testFamily(self): - sock = socket.create_connection((HOST, PORT), timeout=10) + sock = socket.create_connection((HOST, PORT), timeout=30) self.assertEqual(sock.family, 2) From guido at python.org Fri Mar 23 21:26:06 2007 From: guido at python.org (Guido van Rossum) Date: Fri, 23 Mar 2007 13:26:06 -0700 Subject: [Python-checkins] r54545 - in python/trunk: Lib/string.py Objects/typeobject.c In-Reply-To: References: <20070323185308.05B371E4008@bag.python.org> Message-ID: The asserts are checking that we haven't somehow gotten screwy arguments. If they ever trigger, some other C code (in the same file or in a user extension) is to blame, not the user's argument list. But asserts only trigger in debug builds; the other checks are for extra robustness against user extensions screwiness in non-debug builds. (Why did you rearrange the lines in your quotation? That confused the heck out of me.) On 3/23/07, Jim Jewett wrote: > Why just assert? You're checking it every run-time anyhow, so you > might as well raise an error. Or is the assert secretly acting as a > compiler directive as well? > > On 3/23/07, guido.van.rossum wrote: > ============================================================================== > > --- python/trunk/Objects/typeobject.c (original) > > +++ python/trunk/Objects/typeobject.c Fri Mar 23 19:53:03 2007 > > > +type_init(PyObject *cls, PyObject *args, PyObject *kwds) > > +{ > > ... > > > + assert(kwds == NULL || PyDict_Check(kwds)); > ... > > + if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds) != 0) { > > + PyErr_SetString(PyExc_TypeError, > > + "type.__init__() takes no keyword arguments"); > > + return -1; > > + } > > > > + assert(args != NULL && PyTuple_Check(args)); > ... > > + if (args != NULL && PyTuple_Check(args) && > > + (PyTuple_GET_SIZE(args) != 1 && PyTuple_GET_SIZE(args) != 3)) { > > + PyErr_SetString(PyExc_TypeError, > > + "type.__init__() takes 1 or 3 arguments"); > > + return -1; > > + } > > > -jJ > -- --Guido van Rossum (home page: http://www.python.org/~guido/) From buildbot at python.org Fri Mar 23 22:57:49 2007 From: buildbot at python.org (buildbot at python.org) Date: Fri, 23 Mar 2007 21:57:49 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070323215750.55E681E4008@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/348 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: facundo.batista Build had warnings: warnings test Excerpt from the test logfile: 6 tests failed: test_distutils test_extcall test_httplib test_os test_posixpath test_socket ====================================================================== ERROR: This will prove that the timeout gets through ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_httplib.py", line 180, in testTimeoutAttribute httpConn.connect() File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\httplib.py", line 662, in connect self.sock = socket.create_connection((self.host,self.port), self.timeout) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\socket.py", line 443, in create_connection raise error, msg error: (10061, 'Connection refused') ====================================================================== ERROR: test_makedir (test.test_os.MakedirTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 376, in setUp os.mkdir(test_support.TESTFN) WindowsError: [Error 183] Cannot create a file when that file already exists: '@test' ====================================================================== ERROR: test_access (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 443, in test_access self.assertRaises(WindowsError, os.utime, test_support.TESTFN, 0) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\unittest.py", line 329, in failUnlessRaises callableObj(*args, **kwargs) TypeError: utime() arg 2 must be a tuple (atime, mtime) ====================================================================== FAIL: test_traversal (test.test_os.WalkTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 313, in test_traversal self.assertEqual(len(all), 4) AssertionError: 5 != 4 ====================================================================== FAIL: test_chdir (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_os.py", line 434, in test_chdir self.assertRaises(WindowsError, os.chdir, test_support.TESTFN) AssertionError: WindowsError not raised ====================================================================== FAIL: test_relpath (test.test_posixpath.PosixPathTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_posixpath.py", line 486, in test_relpath self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a") AssertionError: 'C:\\buildbot_py25\\trunk.mcintyre-windows\\build\\PCbuild\\@test\\@test\\a' != 'a' ====================================================================== ERROR: testTimeoutAttribute (test.test_socket.NetworkConnectionAttributesTest) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\test\test_socket.py", line 847, in testTimeoutAttribute sock = socket.create_connection((HOST, PORT), timeout=30) File "C:\buildbot_py25\trunk.mcintyre-windows\build\lib\socket.py", line 443, in create_connection raise error, msg error: (10061, 'Connection refused') sincerely, -The Buildbot From python-checkins at python.org Fri Mar 23 23:24:40 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 23 Mar 2007 23:24:40 +0100 (CET) Subject: [Python-checkins] r54556 - python/trunk/Lib/test/test_posixpath.py Message-ID: <20070323222440.74A921E4008@bag.python.org> Author: collin.winter Date: Fri Mar 23 23:24:39 2007 New Revision: 54556 Modified: python/trunk/Lib/test/test_posixpath.py Log: Make test_relpath() pass on Windows. Modified: python/trunk/Lib/test/test_posixpath.py ============================================================================== --- python/trunk/Lib/test/test_posixpath.py (original) +++ python/trunk/Lib/test/test_posixpath.py Fri Mar 23 23:24:39 2007 @@ -480,15 +480,19 @@ safe_rmdir(ABSTFN) def test_relpath(self): - currentdir = os.path.split(os.getcwd())[-1] - self.assertRaises(ValueError, posixpath.relpath, "") - self.assertEqual(posixpath.relpath("a"), "a") - self.assertEqual(posixpath.relpath(os.path.abspath("a")), "a") - self.assertEqual(posixpath.relpath("a/b"), "a/b") - self.assertEqual(posixpath.relpath("../a/b"), "../a/b") - self.assertEqual(posixpath.relpath("a", "../b"), "../"+currentdir+"/a") - self.assertEqual(posixpath.relpath("a/b", "../c"), "../"+currentdir+"/a/b") - self.assertEqual(posixpath.relpath("a", "b/c"), "../../a") + (real_getcwd, os.getcwd) = (os.getcwd, lambda: r"/home/user/bar") + try: + curdir = os.path.split(os.getcwd())[-1] + self.assertRaises(ValueError, posixpath.relpath, "") + self.assertEqual(posixpath.relpath("a"), "a") + self.assertEqual(posixpath.relpath(posixpath.abspath("a")), "a") + self.assertEqual(posixpath.relpath("a/b"), "a/b") + self.assertEqual(posixpath.relpath("../a/b"), "../a/b") + self.assertEqual(posixpath.relpath("a", "../b"), "../"+curdir+"/a") + self.assertEqual(posixpath.relpath("a/b", "../c"), "../"+curdir+"/a/b") + self.assertEqual(posixpath.relpath("a", "b/c"), "../../a") + finally: + os.getcwd = real_getcwd def test_main(): test_support.run_unittest(PosixPathTest) From python-checkins at python.org Sat Mar 24 15:24:34 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Sat, 24 Mar 2007 15:24:34 +0100 (CET) Subject: [Python-checkins] r54559 - in python/trunk: Doc/ref/ref1.tex Doc/ref/ref5.tex Doc/ref/ref6.tex Doc/ref/ref7.tex Misc/NEWS Message-ID: <20070324142434.A40DD1E400F@bag.python.org> Author: ziga.seilnacht Date: Sat Mar 24 15:24:26 2007 New Revision: 54559 Modified: python/trunk/Doc/ref/ref1.tex python/trunk/Doc/ref/ref5.tex python/trunk/Doc/ref/ref6.tex python/trunk/Doc/ref/ref7.tex python/trunk/Misc/NEWS Log: Patch #1489771: update syntax rules in Python Reference Manual. Python 2.5 added support for explicit relative import statements and yield expressions, which were missing in the manual. Also fix grammar productions that used the names from the Grammar file, markup that broke the generated grammar.txt, and wrap some lines that broke the pdf output. Will backport. Modified: python/trunk/Doc/ref/ref1.tex ============================================================================== --- python/trunk/Doc/ref/ref1.tex (original) +++ python/trunk/Doc/ref/ref1.tex Sat Mar 24 15:24:26 2007 @@ -93,7 +93,7 @@ \index{syntax} \index{notation} -\begin{productionlist} +\begin{productionlist}[*] \production{name}{\token{lc_letter} (\token{lc_letter} | "_")*} \production{lc_letter}{"a"..."z"} \end{productionlist} Modified: python/trunk/Doc/ref/ref5.tex ============================================================================== --- python/trunk/Doc/ref/ref5.tex (original) +++ python/trunk/Doc/ref/ref5.tex Sat Mar 24 15:24:26 2007 @@ -56,7 +56,7 @@ \production{enclosure} {\token{parenth_form} | \token{list_display}} \productioncont{| \token{generator_expression} | \token{dict_display}} - \productioncont{| \token{string_conversion}} + \productioncont{| \token{string_conversion} | \token{yield_atom}} \end{productionlist} @@ -65,6 +65,7 @@ \index{identifier} An identifier occurring as an atom is a name. See +section \ref{identifiers} for lexical definition and section~\ref{naming} for documentation of naming and binding. When the name is bound to an object, evaluation of the atom yields @@ -154,22 +155,20 @@ square brackets: \begin{productionlist} - \production{test} - {\token{or_test} | \token{lambda_form}} - \production{testlist} - {\token{test} ( "," \token{test} )* [ "," ]} \production{list_display} - {"[" [\token{listmaker}] "]"} - \production{listmaker} - {\token{expression} ( \token{list_for} - | ( "," \token{expression} )* [","] )} - \production{list_iter} - {\token{list_for} | \token{list_if}} + {"[" [\token{expression_list} | \token{list_comprehension}] "]"} + \production{list_comprehension} + {\token{expression} \token{list_for}} \production{list_for} - {"for" \token{expression_list} "in" \token{testlist} + {"for" \token{target_list} "in" \token{old_expression_list} [\token{list_iter}]} + \production{old_expression_list} + {\token{old_expression} + [("," \token{old_expression})+ [","]]} + \production{list_iter} + {\token{list_for} | \token{list_if}} \production{list_if} - {"if" \token{test} [\token{list_iter}]} + {"if" \token{old_expression} [\token{list_iter}]} \end{productionlist} A list display yields a new list object. Its contents are specified @@ -200,19 +199,18 @@ \begin{productionlist} \production{generator_expression} - {"(" \token{test} \token{genexpr_for} ")"} + {"(" \token{expression} \token{genexpr_for} ")"} \production{genexpr_for} - {"for" \token{expression_list} "in" \token{test} + {"for" \token{target_list} "in" \token{or_test} [\token{genexpr_iter}]} \production{genexpr_iter} {\token{genexpr_for} | \token{genexpr_if}} \production{genexpr_if} - {"if" \token{test} [\token{genexpr_iter}]} + {"if" \token{old_expression} [\token{genexpr_iter}]} \end{productionlist} A generator expression yields a new generator object. \obindex{generator} -\obindex{generator expression} It consists of a single expression followed by at least one \keyword{for} clause and zero or more \keyword{for} or \keyword{if} clauses. The iterating values of the new generator are those that @@ -311,6 +309,142 @@ \bifuncindex{str} +\subsection{Yield expressions\label{yieldexpr}} +\kwindex{yield} +\indexii{yield}{expression} +\indexii{generator}{function} + +\begin{productionlist} + \production{yield_atom} + {"(" \token{yield_expression} ")"} + \production{yield_expression} + {"yield" [\token{expression_list}]} +\end{productionlist} + +\versionadded{2.5} + +The \keyword{yield} expression is only used when defining a generator +function, and can only be used in the body of a function definition. +Using a \keyword{yield} expression in a function definition is +sufficient to cause that definition to create a generator function +instead of a normal function. + +When a generator function is called, it returns an iterator known as a +generator. That generator then controls the execution of a generator +function. The execution starts when one of the generator's methods is +called. At that time, the execution proceeds to the first +\keyword{yield} expression, where it is suspended again, returning the +value of \grammartoken{expression_list} to generator's caller. By +suspended we mean that all local state is retained, including the +current bindings of local variables, the instruction pointer, and the +internal evaluation stack. When the execution is resumed by calling +one of the generator's methods, the function can proceed exactly as +if the \keyword{yield} expression was just another external call. +The value of the \keyword{yield} expression after resuming depends on +the method which resumed the execution. + +\index{coroutine} + +All of this makes generator functions quite similar to coroutines; they +yield multiple times, they have more than one entry point and their +execution can be suspended. The only difference is that a generator +function cannot control where should the execution continue after it +yields; the control is always transfered to the generator's caller. + +\obindex{generator} + +The following generator's methods can be used to control the execution +of a generator function: + +\exindex{StopIteration} + +\begin{methoddesc}[generator]{next}{} + Starts the execution of a generator function or resumes it at the + last executed \keyword{yield} expression. When a generator function + is resumed with a \method{next()} method, the current \keyword{yield} + expression always evaluates to \constant{None}. The execution then + continues to the next \keyword{yield} expression, where the generator + is suspended again, and the value of the + \grammartoken{expression_list} is returned to \method{next()}'s + caller. If the generator exits without yielding another value, a + \exception{StopIteration} exception is raised. +\end{methoddesc} + +\begin{methoddesc}[generator]{send}{value} + Resumes the execution and ``sends'' a value into the generator + function. The \code{value} argument becomes the result of the + current \keyword{yield} expression. The \method{send()} method + returns the next value yielded by the generator, or raises + \exception{StopIteration} if the generator exits without yielding + another value. + When \method{send()} is called to start the generator, it must be + called with \constant{None} as the argument, because there is no + \keyword{yield} expression that could receieve the value. +\end{methoddesc} + +\begin{methoddesc}[generator]{throw} + {type\optional{, value\optional{, traceback}}} + Raises an exception of type \code{type} at the point where generator + was paused, and returns the next value yielded by the generator + function. If the generator exits without yielding another value, a + \exception{StopIteration} exception is raised. If the generator + function does not catch the passed-in exception, or raises a + different exception, then that exception propagates to the caller. +\end{methoddesc} + +\exindex{GeneratorExit} + +\begin{methoddesc}[generator]{close}{} + Raises a \exception{GeneratorExit} at the point where the generator + function was paused. If the generator function then raises + \exception{StopIteration} (by exiting normally, or due to already + being closed) or \exception{GeneratorExit} (by not catching the + exception), close returns to its caller. If the generator yields a + value, a \exception{RuntimeError} is raised. If the generator raises + any other exception, it is propagated to the caller. \method{close} + does nothing if the generator has already exited due to an exception + or normal exit. +\end{methoddesc} + +Here is a simple example that demonstrates the behavior of generators +and generator functions: + +\begin{verbatim} +>>> def echo(value=None): +... print "Execution starts when 'next()' is called for the first time." +... try: +... while True: +... try: +... value = (yield value) +... except GeneratorExit: +... # never catch GeneratorExit +... raise +... except Exception, e: +... value = e +... finally: +... print "Don't forget to clean up when 'close()' is called." +... +>>> generator = echo(1) +>>> print generator.next() +Execution starts when 'next()' is called for the first time. +1 +>>> print generator.next() +None +>>> print generator.send(2) +2 +>>> generator.throw(TypeError, "spam") +TypeError('spam',) +>>> generator.close() +Don't forget to clean up when 'close()' is called. +\end{verbatim} + +\begin{seealso} + \seepep{0342}{Coroutines via Enhanced Generators} + {The proposal to enhance the API and syntax of generators, + making them usable as simple coroutines.} +\end{seealso} + + \section{Primaries\label{primaries}} \index{primary} @@ -474,9 +608,8 @@ \begin{productionlist} \production{call} - {\token{primary} "(" [\token{argument_list} [","]] ")"} - {\token{primary} "(" [\token{argument_list} [","] | - \token{test} \token{genexpr_for} ] ")"} + {\token{primary} "(" [\token{argument_list} [","]} + \productioncont{ | \token{expression} \token{genexpr_for}] ")"} \production{argument_list} {\token{positional_arguments} ["," \token{keyword_arguments}]} \productioncont{ ["," "*" \token{expression}]} @@ -809,10 +942,9 @@ operations: \begin{productionlist} - % The empty groups below prevent conversion to guillemets. \production{shift_expr} {\token{a_expr} - | \token{shift_expr} ( "<{}<" | ">{}>" ) \token{a_expr}} + | \token{shift_expr} ( "<<" | ">>" ) \token{a_expr}} \end{productionlist} These operators accept plain or long integers as arguments. The @@ -1015,14 +1147,18 @@ \section{Boolean operations\label{Booleans}} +\indexii{Conditional}{expression} \indexii{Boolean}{operation} Boolean operations have the lowest priority of all Python operations: \begin{productionlist} \production{expression} - {\token{or_test} [\token{if} \token{or_test} \token{else} - \token{test}] | \token{lambda_form}} + {\token{conditional_expression} | \token{lambda_form}} + \production{old_expression} + {\token{or_test} | \token{old_lambda_form}} + \production{conditional_expression} + {\token{or_test} ["if" \token{or_test} "else" \token{expression}]} \production{or_test} {\token{and_test} | \token{or_test} "or" \token{and_test}} \production{and_test} @@ -1074,6 +1210,8 @@ \begin{productionlist} \production{lambda_form} {"lambda" [\token{parameter_list}]: \token{expression}} + \production{old_lambda_form} + {"lambda" [\token{parameter_list}]: \token{old_expression}} \end{productionlist} Lambda forms (lambda expressions) have the same syntactic position as Modified: python/trunk/Doc/ref/ref6.tex ============================================================================== --- python/trunk/Doc/ref/ref6.tex (original) +++ python/trunk/Doc/ref/ref6.tex Sat Mar 24 15:24:26 2007 @@ -108,7 +108,8 @@ \begin{productionlist} \production{assignment_stmt} - {(\token{target_list} "=")+ \token{expression_list}} + {(\token{target_list} "=")+ + (\token{expression_list} | \token{yield_expression})} \production{target_list} {\token{target} ("," \token{target})* [","]} \production{target} @@ -273,11 +274,11 @@ \begin{productionlist} \production{augmented_assignment_stmt} - {\token{target} \token{augop} \token{expression_list}} + {\token{target} \token{augop} + (\token{expression_list} | \token{yield_expression})} \production{augop} {"+=" | "-=" | "*=" | "/=" | "\%=" | "**="} - % The empty groups below prevent conversion to guillemets. - \productioncont{| ">{}>=" | "<{}<=" | "\&=" | "\textasciicircum=" | "|="} + \productioncont{| ">>=" | "<<=" | "\&=" | "\textasciicircum=" | "|="} \end{productionlist} (See section~\ref{primaries} for the syntax definitions for the last @@ -376,9 +377,9 @@ \begin{productionlist} \production{print_stmt} - {"print" ( \optional{\token{expression} ("," \token{expression})* \optional{","}}} + {"print" ([\token{expression} ("," \token{expression})* [","]} \productioncont{| ">>" \token{expression} - \optional{("," \token{expression})+ \optional{","}} )} + [("," \token{expression})+ [","])} \end{productionlist} \keyword{print} evaluates each expression in turn and writes the @@ -460,7 +461,7 @@ \begin{productionlist} \production{yield_stmt} - {"yield" \token{expression_list}} + {\token{yield_expression}} \end{productionlist} \index{generator!function} @@ -630,15 +631,19 @@ \production{import_stmt} {"import" \token{module} ["as" \token{name}] ( "," \token{module} ["as" \token{name}] )*} - \productioncont{| "from" \token{module} "import" \token{identifier} + \productioncont{| "from" \token{relative_module} "import" \token{identifier} ["as" \token{name}]} \productioncont{ ( "," \token{identifier} ["as" \token{name}] )*} - \productioncont{| "from" \token{module} "import" "(" \token{identifier} - ["as" \token{name}]} + \productioncont{| "from" \token{relative_module} "import" "(" + \token{identifier} ["as" \token{name}]} \productioncont{ ( "," \token{identifier} ["as" \token{name}] )* [","] ")"} \productioncont{| "from" \token{module} "import" "*"} \production{module} {(\token{identifier} ".")* \token{identifier}} + \production{relative_module} + {"."* \token{module} | "."+} + \production{name} + {\token{identifier}} \end{productionlist} Import statements are executed in two steps: (1) find a module, and @@ -757,8 +762,10 @@ \begin{productionlist}[*] \production{future_statement} - {"from" "__future__" "import" feature ["as" name] ("," feature ["as" name])*} - \productioncont{| "from" "__future__" "import" "(" feature ["as" name] ("," feature ["as" name])* [","] ")"} + {"from" "__future__" "import" feature ["as" name]} + \productioncont{ ("," feature ["as" name])*} + \productioncont{| "from" "__future__" "import" "(" feature ["as" name]} + \productioncont{ ("," feature ["as" name])* [","] ")"} \production{feature}{identifier} \production{name}{identifier} \end{productionlist} @@ -775,9 +782,10 @@ \end{itemize} -The features recognized by Python 2.3 are \samp{generators}, -\samp{division} and \samp{nested_scopes}. \samp{generators} and -\samp{nested_scopes} are redundant in 2.3 because they are always +The features recognized by Python 2.5 are \samp{absolute_import}, +\samp{division}, \samp{generators}, \samp{nested_scopes} and +\samp{with_statement}. \samp{generators} and \samp{nested_scopes} +are redundant in Python version 2.3 and above because they are always enabled. A future statement is recognized and treated specially at compile @@ -872,7 +880,7 @@ \begin{productionlist} \production{exec_stmt} - {"exec" \token{expression} + {"exec" \token{or_expr} ["in" \token{expression} ["," \token{expression}]]} \end{productionlist} @@ -916,3 +924,5 @@ + + Modified: python/trunk/Doc/ref/ref7.tex ============================================================================== --- python/trunk/Doc/ref/ref7.tex (original) +++ python/trunk/Doc/ref/ref7.tex Sat Mar 24 15:24:26 2007 @@ -319,7 +319,7 @@ \begin{productionlist} \production{with_stmt} - {"with" \token{expression} ["as" target] ":" \token{suite}} + {"with" \token{expression} ["as" \token{target}] ":" \token{suite}} \end{productionlist} The execution of the \keyword{with} statement proceeds as follows: Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sat Mar 24 15:24:26 2007 @@ -718,6 +718,9 @@ Documentation ------------- +- Patch #1489771: the syntax rules in Python Reference Manual were + updated to reflect the current Python syntax. + - Patch #1686451: Fix return type for PySequence_{Count,Index,Fast_GET_SIZE}. From python-checkins at python.org Sat Mar 24 15:27:28 2007 From: python-checkins at python.org (ziga.seilnacht) Date: Sat, 24 Mar 2007 15:27:28 +0100 (CET) Subject: [Python-checkins] r54560 - in python/branches/release25-maint: Doc/ref/ref1.tex Doc/ref/ref5.tex Doc/ref/ref6.tex Doc/ref/ref7.tex Misc/NEWS Message-ID: <20070324142728.335E91E400F@bag.python.org> Author: ziga.seilnacht Date: Sat Mar 24 15:27:21 2007 New Revision: 54560 Modified: python/branches/release25-maint/Doc/ref/ref1.tex python/branches/release25-maint/Doc/ref/ref5.tex python/branches/release25-maint/Doc/ref/ref6.tex python/branches/release25-maint/Doc/ref/ref7.tex python/branches/release25-maint/Misc/NEWS Log: Patch #1489771: update syntax rules in Python Reference Manual. Python 2.5 added support for explicit relative import statements and yield expressions, which were missing in the manual. Also fix grammar productions that used the names from the Grammar file, markup that broke the generated grammar.txt, and wrap some lines that broke the pdf output. (backport from rev. 54559) Modified: python/branches/release25-maint/Doc/ref/ref1.tex ============================================================================== --- python/branches/release25-maint/Doc/ref/ref1.tex (original) +++ python/branches/release25-maint/Doc/ref/ref1.tex Sat Mar 24 15:27:21 2007 @@ -93,7 +93,7 @@ \index{syntax} \index{notation} -\begin{productionlist} +\begin{productionlist}[*] \production{name}{\token{lc_letter} (\token{lc_letter} | "_")*} \production{lc_letter}{"a"..."z"} \end{productionlist} Modified: python/branches/release25-maint/Doc/ref/ref5.tex ============================================================================== --- python/branches/release25-maint/Doc/ref/ref5.tex (original) +++ python/branches/release25-maint/Doc/ref/ref5.tex Sat Mar 24 15:27:21 2007 @@ -56,7 +56,7 @@ \production{enclosure} {\token{parenth_form} | \token{list_display}} \productioncont{| \token{generator_expression} | \token{dict_display}} - \productioncont{| \token{string_conversion}} + \productioncont{| \token{string_conversion} | \token{yield_atom}} \end{productionlist} @@ -65,6 +65,7 @@ \index{identifier} An identifier occurring as an atom is a name. See +section \ref{identifiers} for lexical definition and section~\ref{naming} for documentation of naming and binding. When the name is bound to an object, evaluation of the atom yields @@ -154,22 +155,20 @@ square brackets: \begin{productionlist} - \production{test} - {\token{or_test} | \token{lambda_form}} - \production{testlist} - {\token{test} ( "," \token{test} )* [ "," ]} \production{list_display} - {"[" [\token{listmaker}] "]"} - \production{listmaker} - {\token{expression} ( \token{list_for} - | ( "," \token{expression} )* [","] )} - \production{list_iter} - {\token{list_for} | \token{list_if}} + {"[" [\token{expression_list} | \token{list_comprehension}] "]"} + \production{list_comprehension} + {\token{expression} \token{list_for}} \production{list_for} - {"for" \token{expression_list} "in" \token{testlist} + {"for" \token{target_list} "in" \token{old_expression_list} [\token{list_iter}]} + \production{old_expression_list} + {\token{old_expression} + [("," \token{old_expression})+ [","]]} + \production{list_iter} + {\token{list_for} | \token{list_if}} \production{list_if} - {"if" \token{test} [\token{list_iter}]} + {"if" \token{old_expression} [\token{list_iter}]} \end{productionlist} A list display yields a new list object. Its contents are specified @@ -200,19 +199,18 @@ \begin{productionlist} \production{generator_expression} - {"(" \token{test} \token{genexpr_for} ")"} + {"(" \token{expression} \token{genexpr_for} ")"} \production{genexpr_for} - {"for" \token{expression_list} "in" \token{test} + {"for" \token{target_list} "in" \token{or_test} [\token{genexpr_iter}]} \production{genexpr_iter} {\token{genexpr_for} | \token{genexpr_if}} \production{genexpr_if} - {"if" \token{test} [\token{genexpr_iter}]} + {"if" \token{old_expression} [\token{genexpr_iter}]} \end{productionlist} A generator expression yields a new generator object. \obindex{generator} -\obindex{generator expression} It consists of a single expression followed by at least one \keyword{for} clause and zero or more \keyword{for} or \keyword{if} clauses. The iterating values of the new generator are those that @@ -311,6 +309,142 @@ \bifuncindex{str} +\subsection{Yield expressions\label{yieldexpr}} +\kwindex{yield} +\indexii{yield}{expression} +\indexii{generator}{function} + +\begin{productionlist} + \production{yield_atom} + {"(" \token{yield_expression} ")"} + \production{yield_expression} + {"yield" [\token{expression_list}]} +\end{productionlist} + +\versionadded{2.5} + +The \keyword{yield} expression is only used when defining a generator +function, and can only be used in the body of a function definition. +Using a \keyword{yield} expression in a function definition is +sufficient to cause that definition to create a generator function +instead of a normal function. + +When a generator function is called, it returns an iterator known as a +generator. That generator then controls the execution of a generator +function. The execution starts when one of the generator's methods is +called. At that time, the execution proceeds to the first +\keyword{yield} expression, where it is suspended again, returning the +value of \grammartoken{expression_list} to generator's caller. By +suspended we mean that all local state is retained, including the +current bindings of local variables, the instruction pointer, and the +internal evaluation stack. When the execution is resumed by calling +one of the generator's methods, the function can proceed exactly as +if the \keyword{yield} expression was just another external call. +The value of the \keyword{yield} expression after resuming depends on +the method which resumed the execution. + +\index{coroutine} + +All of this makes generator functions quite similar to coroutines; they +yield multiple times, they have more than one entry point and their +execution can be suspended. The only difference is that a generator +function cannot control where should the execution continue after it +yields; the control is always transfered to the generator's caller. + +\obindex{generator} + +The following generator's methods can be used to control the execution +of a generator function: + +\exindex{StopIteration} + +\begin{methoddesc}[generator]{next}{} + Starts the execution of a generator function or resumes it at the + last executed \keyword{yield} expression. When a generator function + is resumed with a \method{next()} method, the current \keyword{yield} + expression always evaluates to \constant{None}. The execution then + continues to the next \keyword{yield} expression, where the generator + is suspended again, and the value of the + \grammartoken{expression_list} is returned to \method{next()}'s + caller. If the generator exits without yielding another value, a + \exception{StopIteration} exception is raised. +\end{methoddesc} + +\begin{methoddesc}[generator]{send}{value} + Resumes the execution and ``sends'' a value into the generator + function. The \code{value} argument becomes the result of the + current \keyword{yield} expression. The \method{send()} method + returns the next value yielded by the generator, or raises + \exception{StopIteration} if the generator exits without yielding + another value. + When \method{send()} is called to start the generator, it must be + called with \constant{None} as the argument, because there is no + \keyword{yield} expression that could receieve the value. +\end{methoddesc} + +\begin{methoddesc}[generator]{throw} + {type\optional{, value\optional{, traceback}}} + Raises an exception of type \code{type} at the point where generator + was paused, and returns the next value yielded by the generator + function. If the generator exits without yielding another value, a + \exception{StopIteration} exception is raised. If the generator + function does not catch the passed-in exception, or raises a + different exception, then that exception propagates to the caller. +\end{methoddesc} + +\exindex{GeneratorExit} + +\begin{methoddesc}[generator]{close}{} + Raises a \exception{GeneratorExit} at the point where the generator + function was paused. If the generator function then raises + \exception{StopIteration} (by exiting normally, or due to already + being closed) or \exception{GeneratorExit} (by not catching the + exception), close returns to its caller. If the generator yields a + value, a \exception{RuntimeError} is raised. If the generator raises + any other exception, it is propagated to the caller. \method{close} + does nothing if the generator has already exited due to an exception + or normal exit. +\end{methoddesc} + +Here is a simple example that demonstrates the behavior of generators +and generator functions: + +\begin{verbatim} +>>> def echo(value=None): +... print "Execution starts when 'next()' is called for the first time." +... try: +... while True: +... try: +... value = (yield value) +... except GeneratorExit: +... # never catch GeneratorExit +... raise +... except Exception, e: +... value = e +... finally: +... print "Don't forget to clean up when 'close()' is called." +... +>>> generator = echo(1) +>>> print generator.next() +Execution starts when 'next()' is called for the first time. +1 +>>> print generator.next() +None +>>> print generator.send(2) +2 +>>> generator.throw(TypeError, "spam") +TypeError('spam',) +>>> generator.close() +Don't forget to clean up when 'close()' is called. +\end{verbatim} + +\begin{seealso} + \seepep{0342}{Coroutines via Enhanced Generators} + {The proposal to enhance the API and syntax of generators, + making them usable as simple coroutines.} +\end{seealso} + + \section{Primaries\label{primaries}} \index{primary} @@ -474,9 +608,8 @@ \begin{productionlist} \production{call} - {\token{primary} "(" [\token{argument_list} [","]] ")"} - {\token{primary} "(" [\token{argument_list} [","] | - \token{test} \token{genexpr_for} ] ")"} + {\token{primary} "(" [\token{argument_list} [","]} + \productioncont{ | \token{expression} \token{genexpr_for}] ")"} \production{argument_list} {\token{positional_arguments} ["," \token{keyword_arguments}]} \productioncont{ ["," "*" \token{expression}]} @@ -809,10 +942,9 @@ operations: \begin{productionlist} - % The empty groups below prevent conversion to guillemets. \production{shift_expr} {\token{a_expr} - | \token{shift_expr} ( "<{}<" | ">{}>" ) \token{a_expr}} + | \token{shift_expr} ( "<<" | ">>" ) \token{a_expr}} \end{productionlist} These operators accept plain or long integers as arguments. The @@ -1015,14 +1147,18 @@ \section{Boolean operations\label{Booleans}} +\indexii{Conditional}{expression} \indexii{Boolean}{operation} Boolean operations have the lowest priority of all Python operations: \begin{productionlist} \production{expression} - {\token{or_test} [\token{if} \token{or_test} \token{else} - \token{test}] | \token{lambda_form}} + {\token{conditional_expression} | \token{lambda_form}} + \production{old_expression} + {\token{or_test} | \token{old_lambda_form}} + \production{conditional_expression} + {\token{or_test} ["if" \token{or_test} "else" \token{expression}]} \production{or_test} {\token{and_test} | \token{or_test} "or" \token{and_test}} \production{and_test} @@ -1074,6 +1210,8 @@ \begin{productionlist} \production{lambda_form} {"lambda" [\token{parameter_list}]: \token{expression}} + \production{old_lambda_form} + {"lambda" [\token{parameter_list}]: \token{old_expression}} \end{productionlist} Lambda forms (lambda expressions) have the same syntactic position as Modified: python/branches/release25-maint/Doc/ref/ref6.tex ============================================================================== --- python/branches/release25-maint/Doc/ref/ref6.tex (original) +++ python/branches/release25-maint/Doc/ref/ref6.tex Sat Mar 24 15:27:21 2007 @@ -108,7 +108,8 @@ \begin{productionlist} \production{assignment_stmt} - {(\token{target_list} "=")+ \token{expression_list}} + {(\token{target_list} "=")+ + (\token{expression_list} | \token{yield_expression})} \production{target_list} {\token{target} ("," \token{target})* [","]} \production{target} @@ -273,11 +274,11 @@ \begin{productionlist} \production{augmented_assignment_stmt} - {\token{target} \token{augop} \token{expression_list}} + {\token{target} \token{augop} + (\token{expression_list} | \token{yield_expression})} \production{augop} {"+=" | "-=" | "*=" | "/=" | "\%=" | "**="} - % The empty groups below prevent conversion to guillemets. - \productioncont{| ">{}>=" | "<{}<=" | "\&=" | "\textasciicircum=" | "|="} + \productioncont{| ">>=" | "<<=" | "\&=" | "\textasciicircum=" | "|="} \end{productionlist} (See section~\ref{primaries} for the syntax definitions for the last @@ -376,9 +377,9 @@ \begin{productionlist} \production{print_stmt} - {"print" ( \optional{\token{expression} ("," \token{expression})* \optional{","}}} + {"print" ([\token{expression} ("," \token{expression})* [","]} \productioncont{| ">>" \token{expression} - \optional{("," \token{expression})+ \optional{","}} )} + [("," \token{expression})+ [","])} \end{productionlist} \keyword{print} evaluates each expression in turn and writes the @@ -460,7 +461,7 @@ \begin{productionlist} \production{yield_stmt} - {"yield" \token{expression_list}} + {\token{yield_expression}} \end{productionlist} \index{generator!function} @@ -630,15 +631,19 @@ \production{import_stmt} {"import" \token{module} ["as" \token{name}] ( "," \token{module} ["as" \token{name}] )*} - \productioncont{| "from" \token{module} "import" \token{identifier} + \productioncont{| "from" \token{relative_module} "import" \token{identifier} ["as" \token{name}]} \productioncont{ ( "," \token{identifier} ["as" \token{name}] )*} - \productioncont{| "from" \token{module} "import" "(" \token{identifier} - ["as" \token{name}]} + \productioncont{| "from" \token{relative_module} "import" "(" + \token{identifier} ["as" \token{name}]} \productioncont{ ( "," \token{identifier} ["as" \token{name}] )* [","] ")"} \productioncont{| "from" \token{module} "import" "*"} \production{module} {(\token{identifier} ".")* \token{identifier}} + \production{relative_module} + {"."* \token{module} | "."+} + \production{name} + {\token{identifier}} \end{productionlist} Import statements are executed in two steps: (1) find a module, and @@ -757,8 +762,10 @@ \begin{productionlist}[*] \production{future_statement} - {"from" "__future__" "import" feature ["as" name] ("," feature ["as" name])*} - \productioncont{| "from" "__future__" "import" "(" feature ["as" name] ("," feature ["as" name])* [","] ")"} + {"from" "__future__" "import" feature ["as" name]} + \productioncont{ ("," feature ["as" name])*} + \productioncont{| "from" "__future__" "import" "(" feature ["as" name]} + \productioncont{ ("," feature ["as" name])* [","] ")"} \production{feature}{identifier} \production{name}{identifier} \end{productionlist} @@ -775,9 +782,10 @@ \end{itemize} -The features recognized by Python 2.3 are \samp{generators}, -\samp{division} and \samp{nested_scopes}. \samp{generators} and -\samp{nested_scopes} are redundant in 2.3 because they are always +The features recognized by Python 2.5 are \samp{absolute_import}, +\samp{division}, \samp{generators}, \samp{nested_scopes} and +\samp{with_statement}. \samp{generators} and \samp{nested_scopes} +are redundant in Python version 2.3 and above because they are always enabled. A future statement is recognized and treated specially at compile @@ -872,7 +880,7 @@ \begin{productionlist} \production{exec_stmt} - {"exec" \token{expression} + {"exec" \token{or_expr} ["in" \token{expression} ["," \token{expression}]]} \end{productionlist} @@ -916,3 +924,5 @@ + + Modified: python/branches/release25-maint/Doc/ref/ref7.tex ============================================================================== --- python/branches/release25-maint/Doc/ref/ref7.tex (original) +++ python/branches/release25-maint/Doc/ref/ref7.tex Sat Mar 24 15:27:21 2007 @@ -319,7 +319,7 @@ \begin{productionlist} \production{with_stmt} - {"with" \token{expression} ["as" target] ":" \token{suite}} + {"with" \token{expression} ["as" \token{target}] ":" \token{suite}} \end{productionlist} The execution of the \keyword{with} statement proceeds as follows: Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sat Mar 24 15:27:21 2007 @@ -452,6 +452,9 @@ Documentation ------------- +- Patch #1489771: the syntax rules in Python Reference Manual were + updated to reflect the current Python syntax. + - Patch #1686451: Fix return type for PySequence_{Count,Index,Fast_GET_SIZE}. From python-checkins at python.org Sat Mar 24 21:17:11 2007 From: python-checkins at python.org (erik.forsberg) Date: Sat, 24 Mar 2007 21:17:11 +0100 (CET) Subject: [Python-checkins] r54561 - tracker/instances/python-dev/html/style.css Message-ID: <20070324201711.F184D1E4010@bag.python.org> Author: erik.forsberg Date: Sat Mar 24 21:17:11 2007 New Revision: 54561 Modified: tracker/instances/python-dev/html/style.css Log: Apply loewis patch for wrapping text in Safari. Resolves http://psf.upfronthosting.co.za/roundup/meta/issue108. Modified: tracker/instances/python-dev/html/style.css ============================================================================== --- tracker/instances/python-dev/html/style.css (original) +++ tracker/instances/python-dev/html/style.css Sat Mar 24 21:17:11 2007 @@ -267,6 +267,7 @@ border-right: 1px solid #afafaf; vertical-align: top; padding: 2px 5px 2px 5px; + max-width: 50em; } table.messages td:first-child { From python-checkins at python.org Sat Mar 24 21:43:28 2007 From: python-checkins at python.org (erik.forsberg) Date: Sat, 24 Mar 2007 21:43:28 +0100 (CET) Subject: [Python-checkins] r54562 - tracker/instances/python-dev/html/user.register.html Message-ID: <20070324204328.C75041E4010@bag.python.org> Author: erik.forsberg Date: Sat Mar 24 21:43:23 2007 New Revision: 54562 Modified: tracker/instances/python-dev/html/user.register.html Log: Mention that users that have used the sf bug tracker earlier already have an account. Resolves http://psf.upfronthosting.co.za/roundup/meta/issue107. Modified: tracker/instances/python-dev/html/user.register.html ============================================================================== --- tracker/instances/python-dev/html/user.register.html (original) +++ tracker/instances/python-dev/html/user.register.html Sat Mar 24 21:43:23 2007 @@ -7,6 +7,13 @@ tal:replace="db/config/TRACKER_NAME" /> +

    Please note that if you have previously created or modified issue +reports using the sourceforge issue tracker previously used for python +bugs, your username on sourceforge already exists in this tracker. Use +the Password recovery form to +get a password for your account.

    + + From python-checkins at python.org Sat Mar 24 21:47:21 2007 From: python-checkins at python.org (erik.forsberg) Date: Sat, 24 Mar 2007 21:47:21 +0100 (CET) Subject: [Python-checkins] r54563 - tracker/instances/python-dev/html/page.html Message-ID: <20070324204721.9A2531E4010@bag.python.org> Author: erik.forsberg Date: Sat Mar 24 21:47:19 2007 New Revision: 54563 Modified: tracker/instances/python-dev/html/page.html Log: Replace documentatio link with a link to TrackerDocs in the python wiki. Resolves http://psf.upfronthosting.co.za/roundup/meta/issue106. Modified: tracker/instances/python-dev/html/page.html ============================================================================== --- tracker/instances/python-dev/html/page.html (original) +++ tracker/instances/python-dev/html/page.html Sat Mar 24 21:47:19 2007 @@ -195,8 +195,8 @@
  • Help
    - Roundup docs + Tracker Documentation
  • From python-checkins at python.org Sat Mar 24 22:18:28 2007 From: python-checkins at python.org (erik.forsberg) Date: Sat, 24 Mar 2007 22:18:28 +0100 (CET) Subject: [Python-checkins] r54564 - in tracker/instances/python-dev: extensions/timestamp.py html/user.register.html Message-ID: <20070324211828.D9BD41E4010@bag.python.org> Author: erik.forsberg Date: Sat Mar 24 22:18:28 2007 New Revision: 54564 Added: tracker/instances/python-dev/extensions/timestamp.py Modified: tracker/instances/python-dev/html/user.register.html Log: Limit the registration form - make sure there's a reasonable delay between form generation and form submission. If not, there's a good chance that the submitter is not human, but rather a spambot. See http://psf.upfronthosting.co.za/roundup/meta/issue105. Added: tracker/instances/python-dev/extensions/timestamp.py ============================================================================== --- (empty file) +++ tracker/instances/python-dev/extensions/timestamp.py Sat Mar 24 22:18:28 2007 @@ -0,0 +1,28 @@ +import time, struct, base64 +from roundup.cgi.actions import RegisterAction +from roundup.cgi.exceptions import * + +def timestamp(): + return base64.encodestring(struct.pack("i", time.time())).strip() + +def unpack_timestamp(s): + return struct.unpack("i",base64.decodestring(s))[0] + +class Timestamped: + def check(self): + try: + created = unpack_timestamp(self.form['opaque'].value) + except KeyError: + raise FormError, "somebody tampered with the form" + if time.time() - created < 4: + raise FormError, "responding to the form too quickly" + return True + +class TimestampedRegister(Timestamped, RegisterAction): + def permission(self): + self.check() + RegisterAction.permission(self) + +def init(instance): + instance.registerUtil('timestamp', timestamp) + instance.registerAction('register', TimestampedRegister) Modified: tracker/instances/python-dev/html/user.register.html ============================================================================== --- tracker/instances/python-dev/html/user.register.html (original) +++ tracker/instances/python-dev/html/user.register.html Sat Mar 24 22:18:28 2007 @@ -18,6 +18,7 @@ enctype="multipart/form-data" tal:attributes="action context/designator"> + From python-checkins at python.org Sat Mar 24 23:20:36 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 24 Mar 2007 23:20:36 +0100 (CET) Subject: [Python-checkins] r54565 - python/trunk/Doc/lib/libctypes.tex Message-ID: <20070324222036.B604D1E4010@bag.python.org> Author: georg.brandl Date: Sat Mar 24 23:20:34 2007 New Revision: 54565 Modified: python/trunk/Doc/lib/libctypes.tex Log: Remove typo accent. Modified: python/trunk/Doc/lib/libctypes.tex ============================================================================== --- python/trunk/Doc/lib/libctypes.tex (original) +++ python/trunk/Doc/lib/libctypes.tex Sat Mar 24 23:20:34 2007 @@ -1,5 +1,5 @@ \ifx\locallinewidth\undefined\newlength{\locallinewidth}\fi -\setlength{\locallinewidth}{\linewidth} +%\setlength{\locallinewidth}{\linewidth} \section{\module{ctypes} --- A foreign function library for Python.} \declaremodule{standard}{ctypes} \moduleauthor{Thomas Heller}{theller at python.net} @@ -1242,7 +1242,7 @@ \programopt{-O} or \programopt{-OO} flag given on startup. \code{ctypes} can access values like this with the \method{in{\_}dll} class -methods of the type. \var{pythonapi} ?s a predefined symbol giving +methods of the type. \var{pythonapi} is a predefined symbol giving access to the Python C api: \begin{verbatim} >>> opt_flag = c_int.in_dll(pythonapi, "Py_OptimizeFlag") From python-checkins at python.org Sat Mar 24 23:28:00 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 24 Mar 2007 23:28:00 +0100 (CET) Subject: [Python-checkins] r54566 - python/trunk/Doc/lib/libctypes.tex Message-ID: <20070324222800.AE31F1E4010@bag.python.org> Author: georg.brandl Date: Sat Mar 24 23:27:56 2007 New Revision: 54566 Modified: python/trunk/Doc/lib/libctypes.tex Log: Revert accidental change. Modified: python/trunk/Doc/lib/libctypes.tex ============================================================================== --- python/trunk/Doc/lib/libctypes.tex (original) +++ python/trunk/Doc/lib/libctypes.tex Sat Mar 24 23:27:56 2007 @@ -1,5 +1,5 @@ \ifx\locallinewidth\undefined\newlength{\locallinewidth}\fi -%\setlength{\locallinewidth}{\linewidth} +\setlength{\locallinewidth}{\linewidth} \section{\module{ctypes} --- A foreign function library for Python.} \declaremodule{standard}{ctypes} \moduleauthor{Thomas Heller}{theller at python.net} From python-checkins at python.org Sun Mar 25 03:32:39 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 25 Mar 2007 03:32:39 +0200 (CEST) Subject: [Python-checkins] r54567 - python/trunk/Doc/lib/libtest.tex Message-ID: <20070325013239.9440E1E4010@bag.python.org> Author: brett.cannon Date: Sun Mar 25 03:32:36 2007 New Revision: 54567 Modified: python/trunk/Doc/lib/libtest.tex Log: Change the docs to no longer claim that unittest is preferred over doctest for regression tests. Modified: python/trunk/Doc/lib/libtest.tex ============================================================================== --- python/trunk/Doc/lib/libtest.tex (original) +++ python/trunk/Doc/lib/libtest.tex Sun Mar 25 03:32:36 2007 @@ -14,11 +14,11 @@ Each module in the \module{test} package whose name starts with \samp{test_} is a testing suite for a specific module or feature. -All new tests should be written using the \refmodule{unittest} module; -using \refmodule{unittest} is not required but makes the tests more -flexible and maintenance of the tests easier. Some older tests are -written to use \refmodule{doctest} and a ``traditional'' testing -style; these styles of tests will not be covered. +All new tests should be written using the \refmodule{unittest} or +\refmodule{doctest} module. Some older tests are +written using a ``traditional'' testing style that compares output +printed to \code{sys.stdout}; this style of test is considered +deprecated. \begin{seealso} \seemodule{unittest}{Writing PyUnit regression tests.} @@ -29,8 +29,8 @@ \subsection{Writing Unit Tests for the \module{test} package% \label{writing-tests}} -It is preferred that tests for the \module{test} package use the -\refmodule{unittest} module and follow a few guidelines. +It is preferred that tests that use the \refmodule{unittest} module +follow a few guidelines. One is to name the test module by starting it with \samp{test_} and end it with the name of the module being tested. The test methods in the test module should start with \samp{test_} and end with From python-checkins at python.org Sun Mar 25 03:53:25 2007 From: python-checkins at python.org (facundo.batista) Date: Sun, 25 Mar 2007 03:53:25 +0200 (CEST) Subject: [Python-checkins] r54568 - python/trunk/Lib/test/test_socket.py Message-ID: <20070325015325.5EF771E4010@bag.python.org> Author: facundo.batista Date: Sun Mar 25 03:53:21 2007 New Revision: 54568 Modified: python/trunk/Lib/test/test_socket.py Log: Redone the tests, using the infrastructure already present for threading and socket serving. Modified: python/trunk/Lib/test/test_socket.py ============================================================================== --- python/trunk/Lib/test/test_socket.py (original) +++ python/trunk/Lib/test/test_socket.py Sun Mar 25 03:53:21 2007 @@ -820,74 +820,85 @@ """Tests that NetworkConnection does not break existing TCP functionality. """ -class NetworkConnectionAttributesTest(unittest.TestCase): - - def setUp(self): - self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - global PORT - PORT = test_support.bind_port(self.serv, HOST, PORT) - self.serv.listen(1) - - def tearDown(self): - if self.serv: - self.serv.close() - self.serv = None - +class NetworkConnectionNoServer(unittest.TestCase): def testWithoutServer(self): - self.tearDown() self.failUnlessRaises(socket.error, lambda: socket.create_connection((HOST, PORT))) - def testTimeoutAttribute(self): - # default - sock = socket.create_connection((HOST, PORT)) - self.assertTrue(sock.gettimeout() is None) +class NetworkConnectionAttributesTest(SocketTCPTest, ThreadableTest): + + def __init__(self, methodName='runTest'): + SocketTCPTest.__init__(self, methodName=methodName) + ThreadableTest.__init__(self) + + def clientSetUp(self): + pass + + def clientTearDown(self): + self.cli.close() + self.cli = None + ThreadableTest.clientTearDown(self) + + def _justAccept(self): + conn, addr = self.serv.accept() + + testFamily = _justAccept + def _testFamily(self): + self.cli = socket.create_connection((HOST, PORT), timeout=30) + self.assertEqual(self.cli.family, 2) + + testTimeoutDefault = _justAccept + def _testTimeoutDefault(self): + self.cli = socket.create_connection((HOST, PORT)) + self.assertTrue(self.cli.gettimeout() is None) - # a value, named - sock = socket.create_connection((HOST, PORT), timeout=30) - self.assertEqual(sock.gettimeout(), 30) - - # a value, just the value - sock = socket.create_connection((HOST, PORT), 30) - self.assertEqual(sock.gettimeout(), 30) + testTimeoutValueNamed = _justAccept + def _testTimeoutValueNamed(self): + self.cli = socket.create_connection((HOST, PORT), timeout=30) + self.assertEqual(self.cli.gettimeout(), 30) + + testTimeoutValueNonamed = _justAccept + def _testTimeoutValueNonamed(self): + self.cli = socket.create_connection((HOST, PORT), 30) + self.assertEqual(self.cli.gettimeout(), 30) - # None, having other default + testTimeoutNone = _justAccept + def _testTimeoutNone(self): previous = socket.getdefaulttimeout() socket.setdefaulttimeout(30) try: - sock = socket.create_connection((HOST, PORT), timeout=None) + self.cli = socket.create_connection((HOST, PORT), timeout=None) finally: socket.setdefaulttimeout(previous) - self.assertEqual(sock.gettimeout(), 30) + self.assertEqual(self.cli.gettimeout(), 30) + + +class NetworkConnectionBehaviourTest(SocketTCPTest, ThreadableTest): + + def __init__(self, methodName='runTest'): + SocketTCPTest.__init__(self, methodName=methodName) + ThreadableTest.__init__(self) + + def clientSetUp(self): + pass + + def clientTearDown(self): + self.cli.close() + self.cli = None + ThreadableTest.clientTearDown(self) - def testFamily(self): - sock = socket.create_connection((HOST, PORT), timeout=30) - self.assertEqual(sock.family, 2) - - -def threadedServer(delay): - serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - global PORT - PORT = test_support.bind_port(serv, HOST, PORT) - serv.listen(1) - conn, addr = serv.accept() - time.sleep(delay) - conn.send("done!") - conn.close() - -class NetworkConnectionBehaviourTest(unittest.TestCase): def testInsideTimeout(self): - threading.Thread(target=threadedServer, args=(3,)).start() - time.sleep(.1) - sock = socket.create_connection((HOST, PORT)) + conn, addr = self.serv.accept() + time.sleep(3) + conn.send("done!") + testOutsideTimeout = testInsideTimeout + + def _testInsideTimeout(self): + self.cli = sock = socket.create_connection((HOST, PORT)) data = sock.recv(5) self.assertEqual(data, "done!") - def testOutsideTimeout(self): - threading.Thread(target=threadedServer, args=(3,)).start() - time.sleep(.1) - sock = socket.create_connection((HOST, PORT), timeout=1) + def _testOutsideTimeout(self): + self.cli = sock = socket.create_connection((HOST, PORT), timeout=1) self.failUnlessRaises(socket.timeout, lambda: sock.recv(5)) @@ -1069,6 +1080,7 @@ LineBufferedFileObjectClassTestCase, SmallBufferedFileObjectClassTestCase, Urllib2FileobjectTest, + NetworkConnectionNoServer, NetworkConnectionAttributesTest, NetworkConnectionBehaviourTest, ]) From buildbot at python.org Sun Mar 25 04:17:52 2007 From: buildbot at python.org (buildbot at python.org) Date: Sun, 25 Mar 2007 02:17:52 +0000 Subject: [Python-checkins] buildbot warnings in x86 XP trunk Message-ID: <20070325021752.1A9981E4010@bag.python.org> The Buildbot has detected a new failure of x86 XP trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520XP%2520trunk/builds/350 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: brett.cannon,facundo.batista,georg.brandl,ziga.seilnacht Build had warnings: warnings failed slave lost sincerely, -The Buildbot From python-checkins at python.org Sun Mar 25 05:06:22 2007 From: python-checkins at python.org (brett.cannon) Date: Sun, 25 Mar 2007 05:06:22 +0200 (CEST) Subject: [Python-checkins] r54569 - tracker/instances/python-dev/html/user.register.html Message-ID: <20070325030622.6ACA71E4010@bag.python.org> Author: brett.cannon Date: Sun Mar 25 05:06:16 2007 New Revision: 54569 Modified: tracker/instances/python-dev/html/user.register.html Log: Make warning about using an existing SF account more noticeable. Modified: tracker/instances/python-dev/html/user.register.html ============================================================================== --- tracker/instances/python-dev/html/user.register.html (original) +++ tracker/instances/python-dev/html/user.register.html Sun Mar 25 05:06:16 2007 @@ -7,7 +7,7 @@ tal:replace="db/config/TRACKER_NAME" /> - + From python-checkins at python.org Mon Mar 26 22:18:34 2007 From: python-checkins at python.org (facundo.batista) Date: Mon, 26 Mar 2007 22:18:34 +0200 (CEST) Subject: [Python-checkins] r54580 - python/trunk/Doc/lib/libftplib.tex Message-ID: <20070326201834.85AC31E4006@bag.python.org> Author: facundo.batista Date: Mon Mar 26 22:18:31 2007 New Revision: 54580 Modified: python/trunk/Doc/lib/libftplib.tex Log: Added an optional timeout to FTP class. Also I started a test_ftplib.py file to test the ftp lib (right now I included a basic test, the timeout one, and nothing else). Modified: python/trunk/Doc/lib/libftplib.tex ============================================================================== --- python/trunk/Doc/lib/libftplib.tex (original) +++ python/trunk/Doc/lib/libftplib.tex Mon Mar 26 22:18:31 2007 @@ -37,12 +37,15 @@ The module defines the following items: \begin{classdesc}{FTP}{\optional{host\optional{, user\optional{, - passwd\optional{, acct}}}}} + passwd\optional{, acct\optional{, timeout}}}}}} Return a new instance of the \class{FTP} class. When \var{host} is given, the method call \code{connect(\var{host})} is made. When \var{user} is given, additionally the method call \code{login(\var{user}, \var{passwd}, \var{acct})} is made (where \var{passwd} and \var{acct} default to the empty string when not given). +The optional \var{timeout} parameter specifies a timeout in seconds for the +connection attempt (if is not specified, or passed as None, the global +default timeout setting will be used). \end{classdesc} \begin{datadesc}{all_errors} From python-checkins at python.org Mon Mar 26 22:28:35 2007 From: python-checkins at python.org (georg.brandl) Date: Mon, 26 Mar 2007 22:28:35 +0200 (CEST) Subject: [Python-checkins] r54581 - in python/trunk: Doc/lib/libhttplib.tex Doc/lib/libsocket.tex Lib/httplib.py Message-ID: <20070326202835.A3F9D1E4006@bag.python.org> Author: georg.brandl Date: Mon Mar 26 22:28:28 2007 New Revision: 54581 Modified: python/trunk/Doc/lib/libhttplib.tex python/trunk/Doc/lib/libsocket.tex python/trunk/Lib/httplib.py Log: Some nits. Modified: python/trunk/Doc/lib/libhttplib.tex ============================================================================== --- python/trunk/Doc/lib/libhttplib.tex (original) +++ python/trunk/Doc/lib/libhttplib.tex Mon Mar 26 22:28:28 2007 @@ -32,12 +32,11 @@ server. It should be instantiated passing it a host and optional port number. If no port number is passed, the port is extracted from the host string if it has the form \code{\var{host}:\var{port}}, else the default HTTP port (80) is -used. -When True the optional parameter \var{strict} +used. When True, the optional parameter \var{strict} causes \code{BadStatusLine} to be raised if the status line can't be parsed as a valid HTTP/1.0 or 1.1 status line. If the optional \var{timeout} parameter is given, connection attempts will timeout after that many -seconds (if no timeout is passed, or is passed as None, the global default +seconds (if it is not given or \code{None}, the global default timeout setting is used). For example, the following calls all create instances that connect to Modified: python/trunk/Doc/lib/libsocket.tex ============================================================================== --- python/trunk/Doc/lib/libsocket.tex (original) +++ python/trunk/Doc/lib/libsocket.tex Mon Mar 26 22:28:28 2007 @@ -171,12 +171,12 @@ \end{datadesc} \begin{funcdesc}{create_connection}{address\optional{, timeout}} -Connects to the \var{address} received (as usual, a pair host/port), with -an optional timeout for the connection. Specially useful for higher-level -protocols, it is not normally used directly from application-level code. -Passing the optional \var{timeout} parameter will set the timeout on the -socket instance (if not present, or passed as None, the global default -timeout setting is used). +Connects to the \var{address} received (as usual, a \code{(host, port)} +pair), with an optional timeout for the connection. Specially useful for +higher-level protocols, it is not normally used directly from +application-level code. Passing the optional \var{timeout} parameter +will set the timeout on the socket instance (if it is not given or +\code{None}, the global default timeout setting is used). \end{funcdesc} \begin{funcdesc}{getaddrinfo}{host, port\optional{, family\optional{, Modified: python/trunk/Lib/httplib.py ============================================================================== --- python/trunk/Lib/httplib.py (original) +++ python/trunk/Lib/httplib.py Mon Mar 26 22:28:28 2007 @@ -659,7 +659,8 @@ def connect(self): """Connect to the host and port specified in __init__.""" - self.sock = socket.create_connection((self.host,self.port), self.timeout) + self.sock = socket.create_connection((self.host,self.port), + self.timeout) def close(self): """Close the connection to the HTTP server.""" From buildbot at python.org Mon Mar 26 22:34:41 2007 From: buildbot at python.org (buildbot at python.org) Date: Mon, 26 Mar 2007 20:34:41 +0000 Subject: [Python-checkins] buildbot failure in x86 OpenBSD trunk Message-ID: <20070326203441.628F91E4006@bag.python.org> The Buildbot has detected a new failure of x86 OpenBSD trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520OpenBSD%2520trunk/builds/1617 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: facundo.batista,georg.brandl BUILD FAILED: failed configure sincerely, -The Buildbot From python-checkins at python.org Mon Mar 26 22:56:10 2007 From: python-checkins at python.org (facundo.batista) Date: Mon, 26 Mar 2007 22:56:10 +0200 (CEST) Subject: [Python-checkins] r54582 - in python/trunk/Lib: ftplib.py test/test_ftplib.py Message-ID: <20070326205610.924801E4010@bag.python.org> Author: facundo.batista Date: Mon Mar 26 22:56:09 2007 New Revision: 54582 Added: python/trunk/Lib/test/test_ftplib.py Modified: python/trunk/Lib/ftplib.py Log: Forgot to add the file before the previous commit, here go the ftplib tests. Modified: python/trunk/Lib/ftplib.py ============================================================================== --- python/trunk/Lib/ftplib.py (original) +++ python/trunk/Lib/ftplib.py Mon Mar 26 22:56:09 2007 @@ -76,9 +76,15 @@ '''An FTP client class. - To create a connection, call the class using these argument: - host, user, passwd, acct - These are all strings, and have default value ''. + To create a connection, call the class using these arguments: + host, user, passwd, acct, timeout + + The first four arguments are all strings, and have default value ''. + timeout must be numeric and defaults to None if not passed, + meaning that no timeout will be set on any ftp socket(s) + If a timeout is passed, then this is now the default timeout for all ftp + socket operations for this instance. + Then use self.connect() with optional host and port argument. To download a file, use ftp.retrlines('RETR ' + filename), @@ -102,32 +108,24 @@ # Initialize host to localhost, port to standard ftp port # Optional arguments are host (for connect()), # and user, passwd, acct (for login()) - def __init__(self, host='', user='', passwd='', acct=''): + def __init__(self, host='', user='', passwd='', acct='', timeout=None): + self.timeout = timeout if host: self.connect(host) - if user: self.login(user, passwd, acct) + if user: + self.login(user, passwd, acct) - def connect(self, host = '', port = 0): + def connect(self, host='', port=0): '''Connect to host. Arguments are: - - host: hostname to connect to (string, default previous host) - - port: port to connect to (integer, default previous port)''' - if host: self.host = host - if port: self.port = port - msg = "getaddrinfo returns an empty list" - for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): - af, socktype, proto, canonname, sa = res - try: - self.sock = socket.socket(af, socktype, proto) - self.sock.connect(sa) - except socket.error, msg: - if self.sock: - self.sock.close() - self.sock = None - continue - break - if not self.sock: - raise socket.error, msg - self.af = af + - host: hostname to connect to (string, default previous host) + - port: port to connect to (integer, default previous port) + ''' + if host != '': + self.host = host + if port > 0: + self.port = port + self.sock = socket.create_connection((self.host, self.port), self.timeout) + self.af = self.sock.family self.file = self.sock.makefile('rb') self.welcome = self.getresp() return self.welcome Added: python/trunk/Lib/test/test_ftplib.py ============================================================================== --- (empty file) +++ python/trunk/Lib/test/test_ftplib.py Mon Mar 26 22:56:09 2007 @@ -0,0 +1,68 @@ +import socket +import threading +import ftplib +import time + +from unittest import TestCase +from test import test_support + +def server(evt): + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serv.bind(("", 9091)) + serv.listen(5) + conn, addr = serv.accept() + conn.send("1 Hola mundo\n") + conn.close() + serv.close() + evt.set() + +class GeneralTests(TestCase): + + def setUp(self): + ftplib.FTP.port = 9091 + self.evt = threading.Event() + threading.Thread(target=server, args=(self.evt,)).start() + time.sleep(.1) + + def tearDown(self): + self.evt.wait() + + def testBasic(self): + # do nothing + ftplib.FTP() + + # connects + ftp = ftplib.FTP("localhost") + ftp.sock.close() + + def testTimeoutDefault(self): + # default + ftp = ftplib.FTP("localhost") + self.assertTrue(ftp.sock.gettimeout() is None) + ftp.sock.close() + + def testTimeoutValue(self): + # a value + ftp = ftplib.FTP("localhost", timeout=30) + self.assertEqual(ftp.sock.gettimeout(), 30) + ftp.sock.close() + + def testTimeoutNone(self): + # None, having other default + previous = socket.getdefaulttimeout() + socket.setdefaulttimeout(30) + try: + ftp = ftplib.FTP("localhost", timeout=None) + finally: + socket.setdefaulttimeout(previous) + self.assertEqual(ftp.sock.gettimeout(), 30) + ftp.close() + + + +def test_main(verbose=None): + test_support.run_unittest(GeneralTests) + +if __name__ == '__main__': + test_main() From python-checkins at python.org Tue Mar 27 07:14:32 2007 From: python-checkins at python.org (paul.dubois) Date: Tue, 27 Mar 2007 07:14:32 +0200 (CEST) Subject: [Python-checkins] r54584 - tracker/instances/python-dev/scripts/roundup-summary Message-ID: <20070327051432.E9F391E4006@bag.python.org> Author: paul.dubois Date: Tue Mar 27 07:14:31 2007 New Revision: 54584 Modified: tracker/instances/python-dev/scripts/roundup-summary Log: Change 'from' address of the email. Modified: tracker/instances/python-dev/scripts/roundup-summary ============================================================================== --- tracker/instances/python-dev/scripts/roundup-summary (original) +++ tracker/instances/python-dev/scripts/roundup-summary Tue Mar 27 07:14:31 2007 @@ -844,8 +844,8 @@ writer = MimeWriter.MimeWriter(message) writer.addheader('Subject', 'Summary of %s Issues'%db.config.TRACKER_NAME) writer.addheader('To', recipient) - writer.addheader('From', '%s <%s>'%(db.config.TRACKER_NAME, db.config.ADMIN_EMAIL)) - writer.addheader('Reply-To', '%s <%s>'%(db.config.TRACKER_NAME, 'DONOTREPLY at NOWHERE.ORG')) + writer.addheader('From', '%s <%s>'%(db.config.TRACKER_NAME, 'status at bugs.python.org')) + writer.addheader('Reply-To', '%s <%s>'%(db.config.TRACKER_NAME, 'status at bugs.python.org')) writer.addheader('MIME-Version', '1.0') writer.addheader('X-Roundup-Name', db.config.TRACKER_NAME) From python-checkins at python.org Tue Mar 27 20:23:29 2007 From: python-checkins at python.org (facundo.batista) Date: Tue, 27 Mar 2007 20:23:29 +0200 (CEST) Subject: [Python-checkins] r54585 - in python/trunk: Doc/lib/libpoplib.tex Lib/poplib.py Message-ID: <20070327182329.8A4051E4013@bag.python.org> Author: facundo.batista Date: Tue Mar 27 20:23:21 2007 New Revision: 54585 Modified: python/trunk/Doc/lib/libpoplib.tex python/trunk/Lib/poplib.py Log: Added an optional timeout to poplib.POP3. Also created a test_poplib.py file with a basic test and the timeout ones. Docs are also updated. Modified: python/trunk/Doc/lib/libpoplib.tex ============================================================================== --- python/trunk/Doc/lib/libpoplib.tex (original) +++ python/trunk/Doc/lib/libpoplib.tex Tue Mar 27 20:23:21 2007 @@ -28,10 +28,13 @@ A single class is provided by the \module{poplib} module: -\begin{classdesc}{POP3}{host\optional{, port}} +\begin{classdesc}{POP3}{host\optional{, port\optional{, timeout}}} This class implements the actual POP3 protocol. The connection is created when the instance is initialized. If \var{port} is omitted, the standard POP3 port (110) is used. +The optional \var{timeout} parameter specifies a timeout in seconds for the +connection attempt (if not specified, or passed as None, the global default +timeout setting will be used). \end{classdesc} \begin{classdesc}{POP3_SSL}{host\optional{, port\optional{, keyfile\optional{, certfile}}}} Modified: python/trunk/Lib/poplib.py ============================================================================== --- python/trunk/Lib/poplib.py (original) +++ python/trunk/Lib/poplib.py Tue Mar 27 20:23:21 2007 @@ -76,24 +76,10 @@ """ - def __init__(self, host, port = POP3_PORT): + def __init__(self, host, port=POP3_PORT, timeout=None): self.host = host self.port = port - msg = "getaddrinfo returns an empty list" - self.sock = None - for res in socket.getaddrinfo(self.host, self.port, 0, socket.SOCK_STREAM): - af, socktype, proto, canonname, sa = res - try: - self.sock = socket.socket(af, socktype, proto) - self.sock.connect(sa) - except socket.error, msg: - if self.sock: - self.sock.close() - self.sock = None - continue - break - if not self.sock: - raise socket.error, msg + self.sock = socket.create_connection((host, port), timeout) self.file = self.sock.makefile('rb') self._debugging = 0 self.welcome = self._getresp() From python-checkins at python.org Tue Mar 27 20:50:30 2007 From: python-checkins at python.org (facundo.batista) Date: Tue, 27 Mar 2007 20:50:30 +0200 (CEST) Subject: [Python-checkins] r54586 - python/trunk/Lib/test/test_poplib.py Message-ID: <20070327185030.A259D1E401D@bag.python.org> Author: facundo.batista Date: Tue Mar 27 20:50:29 2007 New Revision: 54586 Added: python/trunk/Lib/test/test_poplib.py Log: The basic test cases of poplib.py. Added: python/trunk/Lib/test/test_poplib.py ============================================================================== --- (empty file) +++ python/trunk/Lib/test/test_poplib.py Tue Mar 27 20:50:29 2007 @@ -0,0 +1,71 @@ +import socket +import threading +import poplib +import time + +from unittest import TestCase +from test import test_support + + +def server(evt): + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.settimeout(3) + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serv.bind(("", 9091)) + serv.listen(5) + try: + conn, addr = serv.accept() + except socket.timeout: + pass + else: + conn.send("+ Hola mundo\n") + conn.close() + finally: + serv.close() + evt.set() + +class GeneralTests(TestCase): + + def setUp(self): + self.evt = threading.Event() + threading.Thread(target=server, args=(self.evt,)).start() + time.sleep(.1) + + def tearDown(self): + self.evt.wait() + + def testBasic(self): + # connects + pop = poplib.POP3("localhost", 9091) + pop.sock.close() + + def testTimeoutDefault(self): + # default + pop = poplib.POP3("localhost", 9091) + self.assertTrue(pop.sock.gettimeout() is None) + pop.sock.close() + + def testTimeoutValue(self): + # a value + pop = poplib.POP3("localhost", 9091, timeout=30) + self.assertEqual(pop.sock.gettimeout(), 30) + pop.sock.close() + + def testTimeoutNone(self): + # None, having other default + previous = socket.getdefaulttimeout() + socket.setdefaulttimeout(30) + try: + pop = poplib.POP3("localhost", 9091, timeout=None) + finally: + socket.setdefaulttimeout(previous) + self.assertEqual(pop.sock.gettimeout(), 30) + pop.sock.close() + + + +def test_main(verbose=None): + test_support.run_unittest(GeneralTests) + +if __name__ == '__main__': + test_main() From buildbot at python.org Tue Mar 27 21:32:39 2007 From: buildbot at python.org (buildbot at python.org) Date: Tue, 27 Mar 2007 19:32:39 +0000 Subject: [Python-checkins] buildbot warnings in x86 W2k trunk Message-ID: <20070327193239.4FFEF1E4002@bag.python.org> The Buildbot has detected a new failure of x86 W2k trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520W2k%2520trunk/builds/161 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: facundo.batista Build had warnings: warnings test Excerpt from the test logfile: 2 tests failed: test_os test_tokenize ====================================================================== ERROR: test_makedir (test.test_os.MakedirTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 376, in setUp os.mkdir(test_support.TESTFN) WindowsError: [Error 183] Cannot create a file when that file already exists: '@test' ====================================================================== ERROR: test_access (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 443, in test_access self.assertRaises(WindowsError, os.utime, test_support.TESTFN, 0) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\unittest.py", line 329, in failUnlessRaises callableObj(*args, **kwargs) TypeError: utime() arg 2 must be a tuple (atime, mtime) ====================================================================== FAIL: test_traversal (test.test_os.WalkTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 313, in test_traversal self.assertEqual(len(all), 4) AssertionError: 5 != 4 ====================================================================== FAIL: test_chdir (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 434, in test_chdir self.assertRaises(WindowsError, os.chdir, test_support.TESTFN) AssertionError: WindowsError not raised sincerely, -The Buildbot From python-checkins at python.org Wed Mar 28 02:28:26 2007 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 28 Mar 2007 02:28:26 +0200 (CEST) Subject: [Python-checkins] r54589 - sandbox/trunk/xreload Message-ID: <20070328002826.C512D1E400C@bag.python.org> Author: guido.van.rossum Date: Wed Mar 28 02:28:23 2007 New Revision: 54589 Added: sandbox/trunk/xreload/ Log: Creating a sandbox directory for xreload. From python-checkins at python.org Wed Mar 28 02:29:03 2007 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 28 Mar 2007 02:29:03 +0200 (CEST) Subject: [Python-checkins] r54590 - sandbox/trunk/xreload/xreload.py Message-ID: <20070328002903.2CBB91E400B@bag.python.org> Author: guido.van.rossum Date: Wed Mar 28 02:29:02 2007 New Revision: 54590 Added: sandbox/trunk/xreload/xreload.py - copied unchanged from r54589, python/branches/p3yk/Lib/xreload.py Log: Moving xreload to the sandbox. It's not ready (and maybe never will). From python-checkins at python.org Wed Mar 28 02:29:37 2007 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 28 Mar 2007 02:29:37 +0200 (CEST) Subject: [Python-checkins] r54591 - sandbox/trunk/xreload/test_xreload.py Message-ID: <20070328002937.B90501E4006@bag.python.org> Author: guido.van.rossum Date: Wed Mar 28 02:29:37 2007 New Revision: 54591 Added: sandbox/trunk/xreload/test_xreload.py - copied unchanged from r54590, python/branches/p3yk/Lib/test/test_xreload.py Log: Move test_xreload.py to the sandbox too. From python-checkins at python.org Wed Mar 28 02:46:06 2007 From: python-checkins at python.org (guido.van.rossum) Date: Wed, 28 Mar 2007 02:46:06 +0200 (CEST) Subject: [Python-checkins] r54593 - sandbox/trunk/abc sandbox/trunk/abc/abc.py Message-ID: <20070328004606.B742B1E4006@bag.python.org> Author: guido.van.rossum Date: Wed Mar 28 02:46:04 2007 New Revision: 54593 Added: sandbox/trunk/abc/ sandbox/trunk/abc/abc.py (contents, props changed) Log: Checkpoint. Added: sandbox/trunk/abc/abc.py ============================================================================== --- (empty file) +++ sandbox/trunk/abc/abc.py Wed Mar 28 02:46:04 2007 @@ -0,0 +1,257 @@ +#!/usr/bin/env python3.0 + +"""Abstract Base Classes experiment. + +XXX How to decide the order in which orthogonal base classes are +listed? For now, I'm putting the smaller API second. + +Note: this depends on the brand new Py3k feature that object.__ne__() +is implemented by calling object.__eq__() and reversing the outcome +(unless NotImplemented). +""" + +__author__ = "Guido van Rossum " + + +class Iterable: + + """An iterable has one method, __iter__().""" + + def __iter__(self): + return Iterator() + + +class Iterator(Iterable): + + """An iterator has two methods, __iter__() and next().""" + + def next(self): + raise StopIteration + + def __iter__(self): + return self + + +class Sizeable: + + def __len__(self): + return 0 + + +class BasicSet: + + # XXX Alternative name: Container? Oracle (as in Delphi's Oracle)? + + """A basic set has __contains__() and that's it.""" + + def __contains__(self, elem): + return False + + +class IterableSet(BasicSet, Iterable): + + """An iterable set is a basic set that is also iterable. + + It may not have a length though; it may be infinite! + + XXX Do we care about potentially infinite sets, or sets of + indeterminate size? + """ + + +class SizeableSet(IterableSet, Sizeable): + + """A sizeable set is an iterable set that has a finite, known size. + + This enables a generic implementation of equality and ordering based + on set inclusion. + + I don't see a use case for a non-iterable set that has a size. + + The idea here is that all you have to do is redefine __le__ and then + the other operations will automatically follow suit. + + XXX However I'm not sure that this always does the right thing, + espectially for __ge__ and __gt__, as these defer to the other + argument's class; that feels fishy. + """ + + def __le__(self, other): + if not isinstance(other, SizeableSet): + return NotImplemented + if len(self) > len(other): + return False + for elem in self: + if elem not in other: + return False + return True + + def __lt__(self, other): + if not isinstance(other, SizeableSet): + return NotImplemented + return len(self) < len(other) and self.__le__(other) + + def __eq__(self, other): + if not isinstance(other, SizeableSet): + return NotImplemented + return len(self) == len(other) and self.__le__(other) + + def __ge__(self, other): + if not isinstance(other, SizeableSet): + return NotImplemented + return other.__le__(self) + + def __gt__(self, other): + if not isinstance(other, SizeableSet): + return NotImplemented + return other.__lt__(self) + + +class BasicMapping: + + # XXX derive from (BasicSet)? + + """A basic mapping has __getitem__(), __contains__() and get(). + + The idea is that you only need to override __getitem__(). + + Other dict methods are not supported. + """ + + def __getitem__(self, key): + raise KeyError + + def get(self, key, default=None): + try: + return self[key] + except KeyError: + return default + + def __contains__(self, key): + try: + self[key] + return True + except KeyError: + return False + + +class IterableMapping(BasicMapping, Iterable): + + def keys(self): + return KeysView(self) + + def items(self): + return ItemsView(self) + + def values(self): + return ValuesView(self) + + +class _MappingView: + + def __init__(self, mapping): + self._mapping = mapping + + +class KeysView(_MappingView, BasicSet): + + def __iter__(self): + for key in self._mapping: + yield key + + def __contains__(self, key): + return key in self._mapping + + +class ItemsView(_MappingView, BasicSet): + + def __iter__(self): + for key in self._mapping: + yield key, self._mapping[key] + + def __contains__(self, (key, value)): + try: + val = self._mapping[key] + except KeyError: + return False + return value == val + + +class ValuesView(_MappingView): + + # Note: does not derive from BasicSet, and does not implement __contains__! + + def __iter__(self): + for key in self._mapping: + yield self._mapping[key] + + +class SizeableMapping(IterableMapping, Sizeable): + + def keys(self): + return SizeableKeysView(self) + + def items(self): + return SizeableItemsView(self) + + def values(self): + return SizeableValuesView(self) + + def __eq__(self, other): + if not isinstance(other, SizeableMapping): + return NotImplemented + if len(other) != len(self): + return False + # XXX Or: for key, value1 in self.items(): ? + for key in self: + value1 = self[key] + try: + value2 = other[key] + except KeyError: + return False + if value1 != value2: + return False + return True + + +class _SizeableMappingView(_MappingView, Sizeable): + + def __len__(self): + return len(self._mapping) + + +class SizeableKeysView(_SizeableMappingView, KeysView, SizeableSet): + pass + + +class SizeableItemsView(_SizeableMappingView, ItemsView, SizeableSet): + pass + + +class SizeableValuesView(_SizeableMappingView, ValuesView): + + def __eq__(self, other): + if not (isinstance(other, Sizeable) and isinstance(other, Iterable)): + return NotImplemented + if len(self) != len(other): + return False + # XXX This is slow. Sometimes this could be optimized, but these + # are the semantics: we can't depend on the values to be hashable + # or comparable. + o_values = list(other) + for value in self: + for i, o_value in enumerate(o_values): + if value == o_value: + del o_values[i] + break + else: + return False + assert not o_values # self must have mutated somehow + return True + + def __contains__(self, value): + # This is slow, but these are the semantics. + for elem in self: + if elem == value: + return True + return False From python-checkins at python.org Wed Mar 28 05:45:28 2007 From: python-checkins at python.org (facundo.batista) Date: Wed, 28 Mar 2007 05:45:28 +0200 (CEST) Subject: [Python-checkins] r54594 - in python/trunk: Lib/test/test_socket.py Modules/socketmodule.c Message-ID: <20070328034528.4A5A41E4013@bag.python.org> Author: facundo.batista Date: Wed Mar 28 05:45:20 2007 New Revision: 54594 Modified: python/trunk/Lib/test/test_socket.py python/trunk/Modules/socketmodule.c Log: Bug 1688393. Adds a control of negative values in socket.recvfrom, which caused an ugly crash. Modified: python/trunk/Lib/test/test_socket.py ============================================================================== --- python/trunk/Lib/test/test_socket.py (original) +++ python/trunk/Lib/test/test_socket.py Wed Mar 28 05:45:20 2007 @@ -597,6 +597,13 @@ def _testRecvFrom(self): self.cli.sendto(MSG, 0, (HOST, PORT)) + def testRecvFromNegative(self): + # Negative lengths passed to recvfrom should give ValueError. + self.assertRaises(ValueError, self.serv.recvfrom, -1) + + def _testRecvFromNegative(self): + self.cli.sendto(MSG, 0, (HOST, PORT)) + class TCPCloserTest(ThreadedTCPSocketTest): def testClose(self): Modified: python/trunk/Modules/socketmodule.c ============================================================================== --- python/trunk/Modules/socketmodule.c (original) +++ python/trunk/Modules/socketmodule.c Wed Mar 28 05:45:20 2007 @@ -2391,7 +2391,7 @@ if (recvlen < 0) { PyErr_SetString(PyExc_ValueError, - "negative buffersize in recv"); + "negative buffersize in recv_into"); return NULL; } if (recvlen == 0) { @@ -2507,6 +2507,12 @@ if (!PyArg_ParseTuple(args, "i|i:recvfrom", &recvlen, &flags)) return NULL; + if (recvlen < 0) { + PyErr_SetString(PyExc_ValueError, + "negative buffersize in recvfrom"); + return NULL; + } + buf = PyString_FromStringAndSize((char *) 0, recvlen); if (buf == NULL) return NULL; @@ -2560,7 +2566,7 @@ if (recvlen < 0) { PyErr_SetString(PyExc_ValueError, - "negative buffersize in recv"); + "negative buffersize in recvfrom_into"); return NULL; } if (recvlen == 0) { From python-checkins at python.org Wed Mar 28 15:18:57 2007 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 28 Mar 2007 15:18:57 +0200 (CEST) Subject: [Python-checkins] r54595 - python/branches/amk-mailbox Message-ID: <20070328131857.300C91E401F@bag.python.org> Author: andrew.kuchling Date: Wed Mar 28 15:18:53 2007 New Revision: 54595 Added: python/branches/amk-mailbox/ - copied from r54594, python/trunk/ Log: Make branch for fixing mailbox bug #1599254 From python-checkins at python.org Wed Mar 28 15:52:43 2007 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 28 Mar 2007 15:52:43 +0200 (CEST) Subject: [Python-checkins] r54596 - python/branches/amk-mailbox/Lib/mailbox.py Message-ID: <20070328135243.197E11E4002@bag.python.org> Author: andrew.kuchling Date: Wed Mar 28 15:52:41 2007 New Revision: 54596 Modified: python/branches/amk-mailbox/Lib/mailbox.py Log: Warn if lock() is called when the mailbox has pending changes Modified: python/branches/amk-mailbox/Lib/mailbox.py ============================================================================== --- python/branches/amk-mailbox/Lib/mailbox.py (original) +++ python/branches/amk-mailbox/Lib/mailbox.py Wed Mar 28 15:52:41 2007 @@ -20,6 +20,7 @@ import email.generator import rfc822 import StringIO +import warnings try: if sys.platform == 'os2emx': # OS/2 EMX fcntl() not adequate @@ -556,6 +557,10 @@ if not self._locked: _lock_file(self._file) self._locked = True + if self._pending: + warnings.warn("lock() method called with pending changes; " + "should have been locked before making changes", + stacklevel=2) def unlock(self): """Unlock the mailbox if it is locked.""" From python-checkins at python.org Wed Mar 28 18:48:59 2007 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 28 Mar 2007 18:48:59 +0200 (CEST) Subject: [Python-checkins] r54597 - python/branches/amk-mailbox/Lib/test/test_mailbox.py Message-ID: <20070328164859.91E7F1E4002@bag.python.org> Author: andrew.kuchling Date: Wed Mar 28 18:48:49 2007 New Revision: 54597 Modified: python/branches/amk-mailbox/Lib/test/test_mailbox.py Log: Add test of concurrent mailbox writes Modified: python/branches/amk-mailbox/Lib/test/test_mailbox.py ============================================================================== --- python/branches/amk-mailbox/Lib/test/test_mailbox.py (original) +++ python/branches/amk-mailbox/Lib/test/test_mailbox.py Wed Mar 28 18:48:49 2007 @@ -417,6 +417,67 @@ self.assertRaises(TypeError, lambda: self._box._dump_message(None, output)) + def test_concurrent_add(self): + # Simple test of concurrent addition to a mailbox. + # This exercises the add() and flush() methods, based on bug #1599254. + # This bug affected only the classes based on _singlefileMailbox + # (mbox, MMDF, Babyl), but this test can apply to any mailbox type. + # If fork isn't available, skip this test. + # XXX Could someone please port this to Windows? + if not hasattr(os, 'fork'): + return + + def random_message (): + # Generate a random message body + import random + body = "" + for i in range(random.randint(1, 10)): + line = "a" * random.randint(0, 75) + '\n' + body += line + + return body + + def add_25_messages (): + "Helper function to add 25 messages to a mailbox." + mbox = self._box + + for i in range(25): + msg = """Subject: %i, pid %i + +From: sender at example.com + + + +Content goes here. + +%s""" % (i, os.getpid(), random_message()) + while True: + try: + mbox.lock() + except mailbox.ExternalClashError: + # In case of conflict, wait a bit and try again. + time.sleep(0.01) + else: + break + mbox.add(msg) + mbox.flush() + mbox.unlock() + + # Fire off a subprocess that will add 25 messages to a mailbox + # file, locking and unlocking it each time. The parent process + # will do the same. The resulting mailbox should contain 50 messages. + pid = os.fork() + if pid == 0: + try: + add_25_messages() + finally: + os._exit(0) + + # Add our 25 messages, and wait for the child to exit. + add_25_messages() + os.wait() + + # We expect the mailbox to contain 50 messages. + self._box.lock() + self.assert_(len(self._box) == 50) + self._box.unlock() + def _get_lock_path(self): # Return the path of the dot lock file. May be overridden. return self._path + '.lock' From python-checkins at python.org Wed Mar 28 19:23:05 2007 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 28 Mar 2007 19:23:05 +0200 (CEST) Subject: [Python-checkins] r54598 - in python/branches/amk-mailbox: Lib/mailbox.py Misc/ACKS Message-ID: <20070328172305.476011E4002@bag.python.org> Author: andrew.kuchling Date: Wed Mar 28 19:23:00 2007 New Revision: 54598 Modified: python/branches/amk-mailbox/Lib/mailbox.py python/branches/amk-mailbox/Misc/ACKS Log: Patch from David Watson (the unified2-module.diff attached to bug #1599254). This patch still has a race condition on platforms where there's no file.truncate(), but it's not clear that any such platforms actually exist at this time. Is it worth keeping that branch of code? Modified: python/branches/amk-mailbox/Lib/mailbox.py ============================================================================== --- python/branches/amk-mailbox/Lib/mailbox.py (original) +++ python/branches/amk-mailbox/Lib/mailbox.py Wed Mar 28 19:23:00 2007 @@ -20,6 +20,7 @@ import email.generator import rfc822 import StringIO +import shutil import warnings try: if sys.platform == 'os2emx': @@ -587,6 +588,15 @@ '(expected %i, found %i)' % (self._file_length, cur_len)) + if fcntl and self._locked and not hasattr(self._file, 'truncate'): + warnings.warn('file.truncate() unavailable, flush() may ' + 'momentarily release the fcntl lock; if you depend ' + 'on fcntl locking, you should regard flush() as ' + 'invalidating the message keys', RuntimeWarning, + stacklevel=2) + + orig_file = self._file + remove_temp_file = True new_file = _create_temporary(self._path) try: new_toc = {} @@ -604,27 +614,45 @@ new_file.write(buffer) new_toc[key] = (new_start, new_file.tell()) self._post_message_hook(new_file) - except: - new_file.close() - os.remove(new_file.name) - raise - _sync_close(new_file) - # self._file is about to get replaced, so no need to sync. - self._file.close() - try: - os.rename(new_file.name, self._path) - except OSError, e: - if e.errno == errno.EEXIST or \ - (os.name == 'os2' and e.errno == errno.EACCES): - os.remove(self._path) - os.rename(new_file.name, self._path) - else: - raise - self._file = open(self._path, 'rb+') - self._toc = new_toc - self._pending = False - if self._locked: - _lock_file(self._file, dotlock=False) + new_len = new_file.tell() + _sync_flush(new_file) + new_file.seek(0) + self._file.seek(0) + if new_len < cur_len and not hasattr(self._file, 'truncate'): + try: + if not os.path.samestat(os.fstat(self._file.fileno()), + os.stat(self._path)): + raise ExternalClashError("Mailbox has been replaced: " + "%s" % self._path) + except OSError, e: + if e.errno == errno.ENOENT: + raise NoSuchMailboxError(self._path) + raise + except AttributeError: + # No stat(), etc. + pass + # *** race condition *** + remove_temp_file = False + self._file = open(self._path, 'wb+') + remove_temp_file = False + shutil.copyfileobj(new_file, self._file) + if hasattr(self._file, 'truncate'): + self._file.truncate(new_len) + self._file_length = new_len + self._toc = new_toc + _sync_flush(self._file) + remove_temp_file = True + self._pending = False + finally: + try: + new_file.close() + if remove_temp_file: + os.remove(new_file.name) + finally: + if self._file is not orig_file: + orig_file.close() + if self._locked: + _lock_file(self._file, dotlock=False) def _pre_mailbox_hook(self, f): """Called before writing the mailbox to file f.""" Modified: python/branches/amk-mailbox/Misc/ACKS ============================================================================== --- python/branches/amk-mailbox/Misc/ACKS (original) +++ python/branches/amk-mailbox/Misc/ACKS Wed Mar 28 19:23:00 2007 @@ -677,6 +677,7 @@ Barry Warsaw Steve Waterbury Bob Watson +David Watson Aaron Watters Henrik Weber Corran Webster From python-checkins at python.org Wed Mar 28 19:31:30 2007 From: python-checkins at python.org (andrew.kuchling) Date: Wed, 28 Mar 2007 19:31:30 +0200 (CEST) Subject: [Python-checkins] r54598 - svn:log Message-ID: <20070328173130.9B58F1E400C@bag.python.org> Author: andrew.kuchling Revision: 54598 Property Name: svn:log New Property Value: Patch from David Watson (the unified2-module.diff attached to bug #1599254). Single-file mailboxes used to write the new mailbox contents into a temporary file which is then renamed over the original. Unfortunately, if another program tries to deliver messages while mailbox.py is working, and uses only fcntl() locking, it will have the old file open and be blocked waiting for the lock to become available. Once mailbox.py has replaced the old file and closed it, making the lock available, the other program will write its messages into the now-deleted "old" file, consigning them to oblivion. The fix is to copy new_file's contents back to the original file instead of renaming a new file. If file.truncate() is available, the mailbox is then truncated to size. Otherwise, if truncation is required, we just re-open the destination file anew (and still have the original locking problem). So this patch still has a race condition on platforms where there's no file.truncate(), but it's not clear that any such platforms actually exist at this time. (AFAIK, the OS/2 VAC++ port lacks it, but Andrew MacIntyre isn't maintaining it; the EMX OS/2 is the actively developed one.) Is it worth keeping that branch of code? From python-checkins at python.org Wed Mar 28 20:25:57 2007 From: python-checkins at python.org (facundo.batista) Date: Wed, 28 Mar 2007 20:25:57 +0200 (CEST) Subject: [Python-checkins] r54599 - in python/trunk: Doc/lib/libsmtplib.tex Lib/smtplib.py Lib/test/test_smtplib.py Message-ID: <20070328182557.8A54B1E4002@bag.python.org> Author: facundo.batista Date: Wed Mar 28 20:25:54 2007 New Revision: 54599 Added: python/trunk/Lib/test/test_smtplib.py Modified: python/trunk/Doc/lib/libsmtplib.tex python/trunk/Lib/smtplib.py Log: Added timeout to smtplib (to SMTP and SMTP_SSL). Also created the test_smtplib.py file, with a basic test and the timeout ones. Docs are updated too. Modified: python/trunk/Doc/lib/libsmtplib.tex ============================================================================== --- python/trunk/Doc/lib/libsmtplib.tex (original) +++ python/trunk/Doc/lib/libsmtplib.tex Wed Mar 28 20:25:54 2007 @@ -15,13 +15,16 @@ (\citetitle{SMTP Service Extensions}). \begin{classdesc}{SMTP}{\optional{host\optional{, port\optional{, - local_hostname}}}} + local_hostname\optional{, timeout}}}}} A \class{SMTP} instance encapsulates an SMTP connection. It has methods that support a full repertoire of SMTP and ESMTP operations. If the optional host and port parameters are given, the SMTP \method{connect()} method is called with those parameters during initialization. An \exception{SMTPConnectError} is raised if the specified host doesn't respond correctly. +The optional \var{timeout} parameter specifies a timeout in seconds for the +connection attempt (if not specified, or passed as None, the global +default timeout setting will be used). For normal use, you should only require the initialization/connect, \method{sendmail()}, and \method{quit()} methods. An example is @@ -31,7 +34,7 @@ \begin{classdesc}{SMTP_SSL}{\optional{host\optional{, port\optional{, local_hostname\optional{, keyfile\optional{, - certfile}}}}}} + certfile\optional{, timeout}}}}}}} A \class{SMTP_SSL} instance behaves exactly the same as instances of \class{SMTP}. \class{SMTP_SSL} should be used for situations where SSL is required from the beginning of the connection and using \method{starttls()} is not appropriate. @@ -39,6 +42,9 @@ omitted, the standard SMTP-over-SSL port (465) is used. \var{keyfile} and \var{certfile} are also optional, and can contain a PEM formatted private key and certificate chain file for the SSL connection. +The optional \var{timeout} parameter specifies a timeout in seconds for the +connection attempt (if not specified, or passed as None, the global +default timeout setting will be used). \end{classdesc} \begin{classdesc}{LMTP}{\optional{host\optional{, port\optional{, Modified: python/trunk/Lib/smtplib.py ============================================================================== --- python/trunk/Lib/smtplib.py (original) +++ python/trunk/Lib/smtplib.py Wed Mar 28 20:25:54 2007 @@ -230,7 +230,7 @@ ehlo_resp = None does_esmtp = 0 - def __init__(self, host = '', port = 0, local_hostname = None): + def __init__(self, host='', port=0, local_hostname=None, timeout=None): """Initialize a new instance. If specified, `host' is the name of the remote host to which to @@ -241,6 +241,7 @@ the local hostname is found using socket.getfqdn(). """ + self.timeout = timeout self.esmtp_features = {} self.default_port = SMTP_PORT if host: @@ -274,12 +275,11 @@ """ self.debuglevel = debuglevel - def _get_socket(self,af, socktype, proto,sa): + def _get_socket(self, port, host, timeout): # This makes it simpler for SMTP_SSL to use the SMTP connect code # and just alter the socket connection bit. - self.sock = socket.socket(af, socktype, proto) if self.debuglevel > 0: print>>stderr, 'connect:', (host, port) - self.sock.connect(sa) + return socket.create_connection((port, host), timeout) def connect(self, host='localhost', port = 0): """Connect to a host on a given port. @@ -301,21 +301,7 @@ raise socket.error, "nonnumeric port" if not port: port = self.default_port if self.debuglevel > 0: print>>stderr, 'connect:', (host, port) - msg = "getaddrinfo returns an empty list" - self.sock = None - for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): - af, socktype, proto, canonname, sa = res - try: - self._get_socket(af,socktype,proto,sa) - except socket.error, msg: - if self.debuglevel > 0: print>>stderr, 'connect fail:', msg - if self.sock: - self.sock.close() - self.sock = None - continue - break - if not self.sock: - raise socket.error, msg + self.sock = self._get_socket(host, port, self.timeout) (code, msg) = self.getreply() if self.debuglevel > 0: print>>stderr, "connect:", msg return (code, msg) @@ -732,17 +718,16 @@ are also optional - they can contain a PEM formatted private key and certificate chain file for the SSL connection. """ - def __init__(self, host = '', port = 0, local_hostname = None, - keyfile = None, certfile = None): + def __init__(self, host='', port=0, local_hostname=None, + keyfile=None, certfile=None, timeout=None): self.keyfile = keyfile self.certfile = certfile - SMTP.__init__(self,host,port,local_hostname) + SMTP.__init__(self, host, port, local_hostname, timeout) self.default_port = SMTP_SSL_PORT - def _get_socket(self,af, socktype, proto,sa): - self.sock = socket.socket(af, socktype, proto) + def _get_socket(self, host, port, timeout): if self.debuglevel > 0: print>>stderr, 'connect:', (host, port) - self.sock.connect(sa) + self.sock = socket.create_connection((host, port), timeout) sslobj = socket.ssl(self.sock, self.keyfile, self.certfile) self.sock = SSLFakeSocket(self.sock, sslobj) self.file = SSLFakeFile(sslobj) Added: python/trunk/Lib/test/test_smtplib.py ============================================================================== --- (empty file) +++ python/trunk/Lib/test/test_smtplib.py Wed Mar 28 20:25:54 2007 @@ -0,0 +1,71 @@ +import socket +import threading +import smtplib +import time + +from unittest import TestCase +from test import test_support + + +def server(evt): + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.settimeout(3) + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serv.bind(("", 9091)) + serv.listen(5) + try: + conn, addr = serv.accept() + except socket.timeout: + pass + else: + conn.send("220 Hola mundo\n") + conn.close() + finally: + serv.close() + evt.set() + +class GeneralTests(TestCase): + + def setUp(self): + self.evt = threading.Event() + threading.Thread(target=server, args=(self.evt,)).start() + time.sleep(.1) + + def tearDown(self): + self.evt.wait() + + def testBasic(self): + # connects + smtp = smtplib.SMTP("localhost", 9091) + smtp.sock.close() + + def testTimeoutDefault(self): + # default + smtp = smtplib.SMTP("localhost", 9091) + self.assertTrue(smtp.sock.gettimeout() is None) + smtp.sock.close() + + def testTimeoutValue(self): + # a value + smtp = smtplib.SMTP("localhost", 9091, timeout=30) + self.assertEqual(smtp.sock.gettimeout(), 30) + smtp.sock.close() + + def testTimeoutNone(self): + # None, having other default + previous = socket.getdefaulttimeout() + socket.setdefaulttimeout(30) + try: + smtp = smtplib.SMTP("localhost", 9091, timeout=None) + finally: + socket.setdefaulttimeout(previous) + self.assertEqual(smtp.sock.gettimeout(), 30) + smtp.sock.close() + + + +def test_main(verbose=None): + test_support.run_unittest(GeneralTests) + +if __name__ == '__main__': + test_main() From python-checkins at python.org Thu Mar 29 01:34:10 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 29 Mar 2007 01:34:10 +0200 (CEST) Subject: [Python-checkins] r54603 - in python/trunk/Lib/test: output/test_pyexpat output/xmltests test_minidom.py test_pyexpat.py test_sax.py Message-ID: <20070328233410.7339F1E4002@bag.python.org> Author: collin.winter Date: Thu Mar 29 01:34:06 2007 New Revision: 54603 Removed: python/trunk/Lib/test/output/test_pyexpat python/trunk/Lib/test/output/xmltests Modified: python/trunk/Lib/test/test_minidom.py python/trunk/Lib/test/test_pyexpat.py python/trunk/Lib/test/test_sax.py Log: Consolidate patches #1690164, 1683397, and 1690169, all of which refactor XML-related test suites. The patches are applied together because they use a common output/xmltests file. Thanks to Jerry Seutter for all three patches. Deleted: /python/trunk/Lib/test/output/test_pyexpat ============================================================================== --- /python/trunk/Lib/test/output/test_pyexpat Thu Mar 29 01:34:06 2007 +++ (empty file) @@ -1,110 +0,0 @@ -test_pyexpat -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -PI: - 'xml-stylesheet' 'href="stylesheet.css"' -Comment: - ' comment data ' -Notation declared: ('notation', None, 'notation.jpeg', None) -Unparsed entity decl: - ('unparsed_entity', None, 'entity.file', None, 'notation') -Start element: - 'root' {'attr1': 'value1', 'attr2': 'value2\xe1\xbd\x80'} -NS decl: - 'myns' 'http://www.python.org/namespace' -Start element: - 'http://www.python.org/namespace!subelement' {} -Character data: - 'Contents of subelements' -End element: - 'http://www.python.org/namespace!subelement' -End of NS decl: - 'myns' -Start element: - 'sub2' {} -Start of CDATA section -Character data: - 'contents of CDATA section' -End of CDATA section -End element: - 'sub2' -External entity ref: (None, 'entity.file', None) -End element: - 'root' -PI: - u'xml-stylesheet' u'href="stylesheet.css"' -Comment: - u' comment data ' -Notation declared: (u'notation', None, u'notation.jpeg', None) -Unparsed entity decl: - (u'unparsed_entity', None, u'entity.file', None, u'notation') -Start element: - u'root' {u'attr1': u'value1', u'attr2': u'value2\u1f40'} -NS decl: - u'myns' u'http://www.python.org/namespace' -Start element: - u'http://www.python.org/namespace!subelement' {} -Character data: - u'Contents of subelements' -End element: - u'http://www.python.org/namespace!subelement' -End of NS decl: - u'myns' -Start element: - u'sub2' {} -Start of CDATA section -Character data: - u'contents of CDATA section' -End of CDATA section -End element: - u'sub2' -External entity ref: (None, u'entity.file', None) -End element: - u'root' -PI: - u'xml-stylesheet' u'href="stylesheet.css"' -Comment: - u' comment data ' -Notation declared: (u'notation', None, u'notation.jpeg', None) -Unparsed entity decl: - (u'unparsed_entity', None, u'entity.file', None, u'notation') -Start element: - u'root' {u'attr1': u'value1', u'attr2': u'value2\u1f40'} -NS decl: - u'myns' u'http://www.python.org/namespace' -Start element: - u'http://www.python.org/namespace!subelement' {} -Character data: - u'Contents of subelements' -End element: - u'http://www.python.org/namespace!subelement' -End of NS decl: - u'myns' -Start element: - u'sub2' {} -Start of CDATA section -Character data: - u'contents of CDATA section' -End of CDATA section -End element: - u'sub2' -External entity ref: (None, u'entity.file', None) -End element: - u'root' - -Testing constructor for proper handling of namespace_separator values: -Legal values tested o.k. -Caught expected TypeError: -ParserCreate() argument 2 must be string or None, not int -Caught expected ValueError: -namespace_separator must be at most one character, omitted, or None Deleted: /python/trunk/Lib/test/output/xmltests ============================================================================== --- /python/trunk/Lib/test/output/xmltests Thu Mar 29 01:34:06 2007 +++ (empty file) @@ -1,364 +0,0 @@ -xmltests -Passed testAAA -Passed setAttribute() sets ownerDocument -Passed setAttribute() sets ownerElement -Test Succeeded testAAA -Passed assertion: len(Node.allnodes) == 0 -Passed testAAB -Test Succeeded testAAB -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Passed Test -Passed Test -Passed Test -Passed Test -Passed Test -Passed Test -Test Succeeded testAddAttr -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Test Succeeded testAppendChild -Passed assertion: len(Node.allnodes) == 0 -Passed appendChild() -Test Succeeded testAppendChildFragment -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testAttrListItem -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testAttrListItemNS -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testAttrListItems -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testAttrListKeys -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testAttrListKeysNS -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testAttrListLength -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testAttrListValues -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testAttrList__getitem__ -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testAttrList__setitem__ -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Test Succeeded testAttributeRepr -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Passed Test -Passed Test -Passed Test -Test Succeeded testChangeAttr -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testChildNodes -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testCloneAttributeDeep -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testCloneAttributeShallow -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testCloneDocumentDeep -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testCloneDocumentShallow -Passed assertion: len(Node.allnodes) == 0 -Passed clone of element has same attribute keys -Passed clone of attribute node has proper attribute values -Passed clone of attribute node correctly owned -Passed testCloneElementDeep -Test Succeeded testCloneElementDeep -Passed assertion: len(Node.allnodes) == 0 -Passed clone of element has same attribute keys -Passed clone of attribute node has proper attribute values -Passed clone of attribute node correctly owned -Passed testCloneElementShallow -Test Succeeded testCloneElementShallow -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testClonePIDeep -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testClonePIShallow -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testComment -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testCreateAttributeNS -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testCreateElementNS -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Passed Test -Test Succeeded testDeleteAttr -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testDocumentElement -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Test Succeeded testElement -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Test Succeeded testElementReprAndStr -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testFirstChild -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testGetAttrLength -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testGetAttrList -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testGetAttrValues -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testGetAttribute -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testGetAttributeNS -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testGetAttributeNode -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Test Succeeded testGetElementsByTagName -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Test Succeeded testGetElementsByTagNameNS -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testGetEmptyNodeListFromElementsByTagNameNS -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testHasChildNodes -Passed assertion: len(Node.allnodes) == 0 -Passed testInsertBefore -- node properly placed in tree -Passed testInsertBefore -- node properly placed in tree -Passed testInsertBefore -- node properly placed in tree -Test Succeeded testInsertBefore -Passed assertion: len(Node.allnodes) == 0 -Passed insertBefore(, None) -Passed insertBefore(, orig) -Test Succeeded testInsertBeforeFragment -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testLegalChildren -Passed assertion: len(Node.allnodes) == 0 -Passed NamedNodeMap.__setitem__() sets ownerDocument -Passed NamedNodeMap.__setitem__() sets ownerElement -Passed NamedNodeMap.__setitem__() sets value -Passed NamedNodeMap.__setitem__() sets nodeValue -Test Succeeded testNamedNodeMapSetItem -Passed assertion: len(Node.allnodes) == 0 -Passed test NodeList.item() -Test Succeeded testNodeListItem -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Test Succeeded testNonZero -Passed assertion: len(Node.allnodes) == 0 -Passed testNormalize -- preparation -Passed testNormalize -- result -Passed testNormalize -- single empty node removed -Test Succeeded testNormalize -Passed assertion: len(Node.allnodes) == 0 -Passed testParents -Test Succeeded testParents -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testParse -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testParseAttributeNamespaces -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testParseAttributes -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testParseElement -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testParseElementNamespaces -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Test Succeeded testParseFromFile -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testParseProcessingInstructions -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testParseString -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testProcessingInstruction -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testProcessingInstructionRepr -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Test Succeeded testRemoveAttr -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Test Succeeded testRemoveAttrNS -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Test Succeeded testRemoveAttributeNode -Passed assertion: len(Node.allnodes) == 0 -Passed replaceChild() -Test Succeeded testReplaceChildFragment -Passed assertion: len(Node.allnodes) == 0 -Passed testSAX2DOM - siblings -Passed testSAX2DOM - parents -Test Succeeded testSAX2DOM -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testSetAttrValueandNodeValue -Passed assertion: len(Node.allnodes) == 0 -Passed testSiblings -Test Succeeded testSiblings -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testTextNodeRepr -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testTextRepr -Passed assertion: len(Node.allnodes) == 0 -Caught expected exception when adding extra document element. -Test Succeeded testTooManyDocumentElements -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testUnlink -Passed assertion: len(Node.allnodes) == 0 -Test Succeeded testWriteText -Passed assertion: len(Node.allnodes) == 0 -Passed Test -Passed Test -Test Succeeded testWriteXML -Passed assertion: len(Node.allnodes) == 0 -All tests succeeded -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -OK. -PI: - 'xml-stylesheet' 'href="stylesheet.css"' -Comment: - ' comment data ' -Notation declared: ('notation', None, 'notation.jpeg', None) -Unparsed entity decl: - ('unparsed_entity', None, 'entity.file', None, 'notation') -Start element: - 'root' {'attr1': 'value1', 'attr2': 'value2\xe1\xbd\x80'} -NS decl: - 'myns' 'http://www.python.org/namespace' -Start element: - 'http://www.python.org/namespace!subelement' {} -Character data: - 'Contents of subelements' -End element: - 'http://www.python.org/namespace!subelement' -End of NS decl: - 'myns' -Start element: - 'sub2' {} -Start of CDATA section -Character data: - 'contents of CDATA section' -End of CDATA section -End element: - 'sub2' -External entity ref: (None, 'entity.file', None) -End element: - 'root' -PI: - u'xml-stylesheet' u'href="stylesheet.css"' -Comment: - u' comment data ' -Notation declared: (u'notation', None, u'notation.jpeg', None) -Unparsed entity decl: - (u'unparsed_entity', None, u'entity.file', None, u'notation') -Start element: - u'root' {u'attr1': u'value1', u'attr2': u'value2\u1f40'} -NS decl: - u'myns' u'http://www.python.org/namespace' -Start element: - u'http://www.python.org/namespace!subelement' {} -Character data: - u'Contents of subelements' -End element: - u'http://www.python.org/namespace!subelement' -End of NS decl: - u'myns' -Start element: - u'sub2' {} -Start of CDATA section -Character data: - u'contents of CDATA section' -End of CDATA section -End element: - u'sub2' -External entity ref: (None, u'entity.file', None) -End element: - u'root' -PI: - u'xml-stylesheet' u'href="stylesheet.css"' -Comment: - u' comment data ' -Notation declared: (u'notation', None, u'notation.jpeg', None) -Unparsed entity decl: - (u'unparsed_entity', None, u'entity.file', None, u'notation') -Start element: - u'root' {u'attr1': u'value1', u'attr2': u'value2\u1f40'} -NS decl: - u'myns' u'http://www.python.org/namespace' -Start element: - u'http://www.python.org/namespace!subelement' {} -Character data: - u'Contents of subelements' -End element: - u'http://www.python.org/namespace!subelement' -End of NS decl: - u'myns' -Start element: - u'sub2' {} -Start of CDATA section -Character data: - u'contents of CDATA section' -End of CDATA section -End element: - u'sub2' -External entity ref: (None, u'entity.file', None) -End element: - u'root' - -Testing constructor for proper handling of namespace_separator values: -Legal values tested o.k. -Caught expected TypeError: -ParserCreate() argument 2 must be string or None, not int -Caught expected ValueError: -namespace_separator must be at most one character, omitted, or None -Passed test_attrs_empty -Passed test_attrs_wattr -Passed test_double_quoteattr -Passed test_escape_all -Passed test_escape_basic -Passed test_escape_extra -Passed test_expat_attrs_empty -Passed test_expat_attrs_wattr -Passed test_expat_dtdhandler -Passed test_expat_entityresolver -Passed test_expat_file -Passed test_expat_incomplete -Passed test_expat_incremental -Passed test_expat_incremental_reset -Passed test_expat_inpsource_filename -Passed test_expat_inpsource_location -Passed test_expat_inpsource_stream -Passed test_expat_inpsource_sysid -Passed test_expat_locator_noinfo -Passed test_expat_locator_withinfo -Passed test_expat_nsattrs_empty -Passed test_expat_nsattrs_wattr -Passed test_filter_basic -Passed test_make_parser -Passed test_make_parser2 -Passed test_nsattrs_empty -Passed test_nsattrs_wattr -Passed test_quoteattr_basic -Passed test_single_double_quoteattr -Passed test_single_quoteattr -Passed test_xmlgen_attr_escape -Passed test_xmlgen_basic -Passed test_xmlgen_content -Passed test_xmlgen_content_escape -Passed test_xmlgen_ignorable -Passed test_xmlgen_ns -Passed test_xmlgen_pi -37 tests, 0 failures Modified: python/trunk/Lib/test/test_minidom.py ============================================================================== --- python/trunk/Lib/test/test_minidom.py (original) +++ python/trunk/Lib/test/test_minidom.py Thu Mar 29 01:34:06 2007 @@ -5,7 +5,8 @@ import pickle import traceback from StringIO import StringIO -from test.test_support import verbose +from test.test_support import verbose, run_unittest, TestSkipped +import unittest import xml.dom import xml.dom.minidom @@ -22,682 +23,9 @@ tstfile = os.path.join(os.path.dirname(base), "test"+os.extsep+"xml") del base -def confirm(test, testname = "Test"): - if not test: - print "Failed " + testname - raise Exception - -def testParseFromFile(): - dom = parse(StringIO(open(tstfile).read())) - dom.unlink() - confirm(isinstance(dom,Document)) - -def testGetElementsByTagName(): - dom = parse(tstfile) - confirm(dom.getElementsByTagName("LI") == \ - dom.documentElement.getElementsByTagName("LI")) - dom.unlink() - -def testInsertBefore(): - dom = parseString("") - root = dom.documentElement - elem = root.childNodes[0] - nelem = dom.createElement("element") - root.insertBefore(nelem, elem) - confirm(len(root.childNodes) == 2 - and root.childNodes.length == 2 - and root.childNodes[0] is nelem - and root.childNodes.item(0) is nelem - and root.childNodes[1] is elem - and root.childNodes.item(1) is elem - and root.firstChild is nelem - and root.lastChild is elem - and root.toxml() == "" - , "testInsertBefore -- node properly placed in tree") - nelem = dom.createElement("element") - root.insertBefore(nelem, None) - confirm(len(root.childNodes) == 3 - and root.childNodes.length == 3 - and root.childNodes[1] is elem - and root.childNodes.item(1) is elem - and root.childNodes[2] is nelem - and root.childNodes.item(2) is nelem - and root.lastChild is nelem - and nelem.previousSibling is elem - and root.toxml() == "" - , "testInsertBefore -- node properly placed in tree") - nelem2 = dom.createElement("bar") - root.insertBefore(nelem2, nelem) - confirm(len(root.childNodes) == 4 - and root.childNodes.length == 4 - and root.childNodes[2] is nelem2 - and root.childNodes.item(2) is nelem2 - and root.childNodes[3] is nelem - and root.childNodes.item(3) is nelem - and nelem2.nextSibling is nelem - and nelem.previousSibling is nelem2 - and root.toxml() == "" - , "testInsertBefore -- node properly placed in tree") - dom.unlink() - -def _create_fragment_test_nodes(): - dom = parseString("") - orig = dom.createTextNode("original") - c1 = dom.createTextNode("foo") - c2 = dom.createTextNode("bar") - c3 = dom.createTextNode("bat") - dom.documentElement.appendChild(orig) - frag = dom.createDocumentFragment() - frag.appendChild(c1) - frag.appendChild(c2) - frag.appendChild(c3) - return dom, orig, c1, c2, c3, frag - -def testInsertBeforeFragment(): - dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes() - dom.documentElement.insertBefore(frag, None) - confirm(tuple(dom.documentElement.childNodes) == (orig, c1, c2, c3), - "insertBefore(, None)") - frag.unlink() - dom.unlink() - # - dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes() - dom.documentElement.insertBefore(frag, orig) - confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3, orig), - "insertBefore(, orig)") - frag.unlink() - dom.unlink() - -def testAppendChild(): - dom = parse(tstfile) - dom.documentElement.appendChild(dom.createComment(u"Hello")) - confirm(dom.documentElement.childNodes[-1].nodeName == "#comment") - confirm(dom.documentElement.childNodes[-1].data == "Hello") - dom.unlink() - -def testAppendChildFragment(): - dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes() - dom.documentElement.appendChild(frag) - confirm(tuple(dom.documentElement.childNodes) == (orig, c1, c2, c3), - "appendChild()") - frag.unlink() - dom.unlink() - -def testReplaceChildFragment(): - dom, orig, c1, c2, c3, frag = _create_fragment_test_nodes() - dom.documentElement.replaceChild(frag, orig) - orig.unlink() - confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3), - "replaceChild()") - frag.unlink() - dom.unlink() - -def testLegalChildren(): - dom = Document() - elem = dom.createElement('element') - text = dom.createTextNode('text') - - try: dom.appendChild(text) - except xml.dom.HierarchyRequestErr: pass - else: - print "dom.appendChild didn't raise HierarchyRequestErr" - - dom.appendChild(elem) - try: dom.insertBefore(text, elem) - except xml.dom.HierarchyRequestErr: pass - else: - print "dom.appendChild didn't raise HierarchyRequestErr" - - try: dom.replaceChild(text, elem) - except xml.dom.HierarchyRequestErr: pass - else: - print "dom.appendChild didn't raise HierarchyRequestErr" - - nodemap = elem.attributes - try: nodemap.setNamedItem(text) - except xml.dom.HierarchyRequestErr: pass - else: - print "NamedNodeMap.setNamedItem didn't raise HierarchyRequestErr" - - try: nodemap.setNamedItemNS(text) - except xml.dom.HierarchyRequestErr: pass - else: - print "NamedNodeMap.setNamedItemNS didn't raise HierarchyRequestErr" - - elem.appendChild(text) - dom.unlink() - -def testNamedNodeMapSetItem(): - dom = Document() - elem = dom.createElement('element') - attrs = elem.attributes - attrs["foo"] = "bar" - a = attrs.item(0) - confirm(a.ownerDocument is dom, - "NamedNodeMap.__setitem__() sets ownerDocument") - confirm(a.ownerElement is elem, - "NamedNodeMap.__setitem__() sets ownerElement") - confirm(a.value == "bar", - "NamedNodeMap.__setitem__() sets value") - confirm(a.nodeValue == "bar", - "NamedNodeMap.__setitem__() sets nodeValue") - elem.unlink() - dom.unlink() - -def testNonZero(): - dom = parse(tstfile) - confirm(dom)# should not be zero - dom.appendChild(dom.createComment("foo")) - confirm(not dom.childNodes[-1].childNodes) - dom.unlink() - -def testUnlink(): - dom = parse(tstfile) - dom.unlink() - -def testElement(): - dom = Document() - dom.appendChild(dom.createElement("abc")) - confirm(dom.documentElement) - dom.unlink() - -def testAAA(): - dom = parseString("") - el = dom.documentElement - el.setAttribute("spam", "jam2") - confirm(el.toxml() == '', "testAAA") - a = el.getAttributeNode("spam") - confirm(a.ownerDocument is dom, - "setAttribute() sets ownerDocument") - confirm(a.ownerElement is dom.documentElement, - "setAttribute() sets ownerElement") - dom.unlink() - -def testAAB(): - dom = parseString("") - el = dom.documentElement - el.setAttribute("spam", "jam") - el.setAttribute("spam", "jam2") - confirm(el.toxml() == '', "testAAB") - dom.unlink() - -def testAddAttr(): - dom = Document() - child = dom.appendChild(dom.createElement("abc")) - - child.setAttribute("def", "ghi") - confirm(child.getAttribute("def") == "ghi") - confirm(child.attributes["def"].value == "ghi") - - child.setAttribute("jkl", "mno") - confirm(child.getAttribute("jkl") == "mno") - confirm(child.attributes["jkl"].value == "mno") - - confirm(len(child.attributes) == 2) - - child.setAttribute("def", "newval") - confirm(child.getAttribute("def") == "newval") - confirm(child.attributes["def"].value == "newval") - - confirm(len(child.attributes) == 2) - dom.unlink() - -def testDeleteAttr(): - dom = Document() - child = dom.appendChild(dom.createElement("abc")) - - confirm(len(child.attributes) == 0) - child.setAttribute("def", "ghi") - confirm(len(child.attributes) == 1) - del child.attributes["def"] - confirm(len(child.attributes) == 0) - dom.unlink() - -def testRemoveAttr(): - dom = Document() - child = dom.appendChild(dom.createElement("abc")) - - child.setAttribute("def", "ghi") - confirm(len(child.attributes) == 1) - child.removeAttribute("def") - confirm(len(child.attributes) == 0) - - dom.unlink() - -def testRemoveAttrNS(): - dom = Document() - child = dom.appendChild( - dom.createElementNS("http://www.python.org", "python:abc")) - child.setAttributeNS("http://www.w3.org", "xmlns:python", - "http://www.python.org") - child.setAttributeNS("http://www.python.org", "python:abcattr", "foo") - confirm(len(child.attributes) == 2) - child.removeAttributeNS("http://www.python.org", "abcattr") - confirm(len(child.attributes) == 1) - - dom.unlink() - -def testRemoveAttributeNode(): - dom = Document() - child = dom.appendChild(dom.createElement("foo")) - child.setAttribute("spam", "jam") - confirm(len(child.attributes) == 1) - node = child.getAttributeNode("spam") - child.removeAttributeNode(node) - confirm(len(child.attributes) == 0 - and child.getAttributeNode("spam") is None) - - dom.unlink() - -def testChangeAttr(): - dom = parseString("") - el = dom.documentElement - el.setAttribute("spam", "jam") - confirm(len(el.attributes) == 1) - el.setAttribute("spam", "bam") - # Set this attribute to be an ID and make sure that doesn't change - # when changing the value: - el.setIdAttribute("spam") - confirm(len(el.attributes) == 1 - and el.attributes["spam"].value == "bam" - and el.attributes["spam"].nodeValue == "bam" - and el.getAttribute("spam") == "bam" - and el.getAttributeNode("spam").isId) - el.attributes["spam"] = "ham" - confirm(len(el.attributes) == 1 - and el.attributes["spam"].value == "ham" - and el.attributes["spam"].nodeValue == "ham" - and el.getAttribute("spam") == "ham" - and el.attributes["spam"].isId) - el.setAttribute("spam2", "bam") - confirm(len(el.attributes) == 2 - and el.attributes["spam"].value == "ham" - and el.attributes["spam"].nodeValue == "ham" - and el.getAttribute("spam") == "ham" - and el.attributes["spam2"].value == "bam" - and el.attributes["spam2"].nodeValue == "bam" - and el.getAttribute("spam2") == "bam") - el.attributes["spam2"] = "bam2" - confirm(len(el.attributes) == 2 - and el.attributes["spam"].value == "ham" - and el.attributes["spam"].nodeValue == "ham" - and el.getAttribute("spam") == "ham" - and el.attributes["spam2"].value == "bam2" - and el.attributes["spam2"].nodeValue == "bam2" - and el.getAttribute("spam2") == "bam2") - dom.unlink() - -def testGetAttrList(): - pass - -def testGetAttrValues(): pass - -def testGetAttrLength(): pass - -def testGetAttribute(): pass - -def testGetAttributeNS(): pass - -def testGetAttributeNode(): pass - -def testGetElementsByTagNameNS(): - d=""" - - """ - dom = parseString(d) - elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom", "myelem") - confirm(len(elems) == 1 - and elems[0].namespaceURI == "http://pyxml.sf.net/minidom" - and elems[0].localName == "myelem" - and elems[0].prefix == "minidom" - and elems[0].tagName == "minidom:myelem" - and elems[0].nodeName == "minidom:myelem") - dom.unlink() - -def get_empty_nodelist_from_elements_by_tagName_ns_helper(doc, nsuri, lname): - nodelist = doc.getElementsByTagNameNS(nsuri, lname) - confirm(len(nodelist) == 0) - -def testGetEmptyNodeListFromElementsByTagNameNS(): - doc = parseString('') - get_empty_nodelist_from_elements_by_tagName_ns_helper( - doc, 'http://xml.python.org/namespaces/a', 'localname') - get_empty_nodelist_from_elements_by_tagName_ns_helper( - doc, '*', 'splat') - get_empty_nodelist_from_elements_by_tagName_ns_helper( - doc, 'http://xml.python.org/namespaces/a', '*') - - doc = parseString('') - get_empty_nodelist_from_elements_by_tagName_ns_helper( - doc, "http://xml.python.org/splat", "not-there") - get_empty_nodelist_from_elements_by_tagName_ns_helper( - doc, "*", "not-there") - get_empty_nodelist_from_elements_by_tagName_ns_helper( - doc, "http://somewhere.else.net/not-there", "e") - -def testElementReprAndStr(): - dom = Document() - el = dom.appendChild(dom.createElement("abc")) - string1 = repr(el) - string2 = str(el) - confirm(string1 == string2) - dom.unlink() - -# commented out until Fredrick's fix is checked in -def _testElementReprAndStrUnicode(): - dom = Document() - el = dom.appendChild(dom.createElement(u"abc")) - string1 = repr(el) - string2 = str(el) - confirm(string1 == string2) - dom.unlink() - -# commented out until Fredrick's fix is checked in -def _testElementReprAndStrUnicodeNS(): - dom = Document() - el = dom.appendChild( - dom.createElementNS(u"http://www.slashdot.org", u"slash:abc")) - string1 = repr(el) - string2 = str(el) - confirm(string1 == string2) - confirm(string1.find("slash:abc") != -1) - dom.unlink() - -def testAttributeRepr(): - dom = Document() - el = dom.appendChild(dom.createElement(u"abc")) - node = el.setAttribute("abc", "def") - confirm(str(node) == repr(node)) - dom.unlink() - -def testTextNodeRepr(): pass - -def testWriteXML(): - 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 - confirm(pi.target == "mypi" - and pi.data == "data \t\n " - and pi.nodeName == "mypi" - and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE - and pi.attributes is None - and not pi.hasChildNodes() - and len(pi.childNodes) == 0 - and pi.firstChild is None - and pi.lastChild is None - and pi.localName is None - and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE) - -def testProcessingInstructionRepr(): pass - -def testTextRepr(): pass - -def testWriteText(): pass - -def testDocumentElement(): pass - -def testTooManyDocumentElements(): - doc = parseString("") - elem = doc.createElement("extra") - try: - doc.appendChild(elem) - except xml.dom.HierarchyRequestErr: - pass - else: - print "Failed to catch expected exception when" \ - " adding extra document element." - elem.unlink() - doc.unlink() - -def testCreateElementNS(): pass - -def testCreateAttributeNS(): pass - -def testParse(): pass - -def testParseString(): pass - -def testComment(): pass - -def testAttrListItem(): pass - -def testAttrListItems(): pass - -def testAttrListItemNS(): pass - -def testAttrListKeys(): pass - -def testAttrListKeysNS(): pass - -def testRemoveNamedItem(): - doc = parseString("") - e = doc.documentElement - attrs = e.attributes - a1 = e.getAttributeNode("a") - a2 = attrs.removeNamedItem("a") - confirm(a1.isSameNode(a2)) - try: - attrs.removeNamedItem("a") - except xml.dom.NotFoundErr: - pass - -def testRemoveNamedItemNS(): - doc = parseString("") - e = doc.documentElement - attrs = e.attributes - a1 = e.getAttributeNodeNS("http://xml.python.org/", "b") - a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b") - confirm(a1.isSameNode(a2)) - try: - attrs.removeNamedItemNS("http://xml.python.org/", "b") - except xml.dom.NotFoundErr: - pass - -def testAttrListValues(): pass - -def testAttrListLength(): pass - -def testAttrList__getitem__(): pass - -def testAttrList__setitem__(): pass - -def testSetAttrValueandNodeValue(): pass - -def testParseElement(): pass - -def testParseAttributes(): pass - -def testParseElementNamespaces(): pass - -def testParseAttributeNamespaces(): pass - -def testParseProcessingInstructions(): pass - -def testChildNodes(): pass - -def testFirstChild(): pass - -def testHasChildNodes(): pass - -def testCloneElementShallow(): - dom, clone = _setupCloneElement(0) - confirm(len(clone.childNodes) == 0 - and clone.childNodes.length == 0 - and clone.parentNode is None - and clone.toxml() == '' - , "testCloneElementShallow") - dom.unlink() - -def testCloneElementDeep(): - dom, clone = _setupCloneElement(1) - confirm(len(clone.childNodes) == 1 - and clone.childNodes.length == 1 - and clone.parentNode is None - and clone.toxml() == '' - , "testCloneElementDeep") - dom.unlink() - -def _setupCloneElement(deep): - dom = parseString("") - root = dom.documentElement - clone = root.cloneNode(deep) - _testCloneElementCopiesAttributes( - root, clone, "testCloneElement" + (deep and "Deep" or "Shallow")) - # mutilate the original so shared data is detected - root.tagName = root.nodeName = "MODIFIED" - root.setAttribute("attr", "NEW VALUE") - root.setAttribute("added", "VALUE") - return dom, clone - -def _testCloneElementCopiesAttributes(e1, e2, test): - attrs1 = e1.attributes - attrs2 = e2.attributes - keys1 = attrs1.keys() - keys2 = attrs2.keys() - keys1.sort() - keys2.sort() - confirm(keys1 == keys2, "clone of element has same attribute keys") - for i in range(len(keys1)): - a1 = attrs1.item(i) - a2 = attrs2.item(i) - confirm(a1 is not a2 - and a1.value == a2.value - and a1.nodeValue == a2.nodeValue - and a1.namespaceURI == a2.namespaceURI - and a1.localName == a2.localName - , "clone of attribute node has proper attribute values") - confirm(a2.ownerElement is e2, - "clone of attribute node correctly owned") - -def testCloneDocumentShallow(): - doc = parseString("\n" - "" - "\n" - "]>\n" - "") - doc2 = doc.cloneNode(0) - confirm(doc2 is None, - "testCloneDocumentShallow:" - " shallow cloning of documents makes no sense!") - -def testCloneDocumentDeep(): - doc = parseString("\n" - "" - "\n" - "]>\n" - "") - doc2 = doc.cloneNode(1) - confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)), - "testCloneDocumentDeep: document objects not distinct") - confirm(len(doc.childNodes) == len(doc2.childNodes), - "testCloneDocumentDeep: wrong number of Document children") - confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE, - "testCloneDocumentDeep: documentElement not an ELEMENT_NODE") - confirm(doc2.documentElement.ownerDocument.isSameNode(doc2), - "testCloneDocumentDeep: documentElement owner is not new document") - confirm(not doc.documentElement.isSameNode(doc2.documentElement), - "testCloneDocumentDeep: documentElement should not be shared") - if doc.doctype is not None: - # check the doctype iff the original DOM maintained it - confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE, - "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE") - confirm(doc2.doctype.ownerDocument.isSameNode(doc2)) - confirm(not doc.doctype.isSameNode(doc2.doctype)) - -def testCloneDocumentTypeDeepOk(): - doctype = create_nonempty_doctype() - clone = doctype.cloneNode(1) - confirm(clone is not None - and clone.nodeName == doctype.nodeName - and clone.name == doctype.name - and clone.publicId == doctype.publicId - and clone.systemId == doctype.systemId - and len(clone.entities) == len(doctype.entities) - and clone.entities.item(len(clone.entities)) is None - and len(clone.notations) == len(doctype.notations) - and clone.notations.item(len(clone.notations)) is None - and len(clone.childNodes) == 0) - for i in range(len(doctype.entities)): - se = doctype.entities.item(i) - ce = clone.entities.item(i) - confirm((not se.isSameNode(ce)) - and (not ce.isSameNode(se)) - and ce.nodeName == se.nodeName - and ce.notationName == se.notationName - and ce.publicId == se.publicId - and ce.systemId == se.systemId - and ce.encoding == se.encoding - and ce.actualEncoding == se.actualEncoding - and ce.version == se.version) - for i in range(len(doctype.notations)): - sn = doctype.notations.item(i) - cn = clone.notations.item(i) - confirm((not sn.isSameNode(cn)) - and (not cn.isSameNode(sn)) - and cn.nodeName == sn.nodeName - and cn.publicId == sn.publicId - and cn.systemId == sn.systemId) - -def testCloneDocumentTypeDeepNotOk(): - doc = create_doc_with_doctype() - clone = doc.doctype.cloneNode(1) - confirm(clone is None, "testCloneDocumentTypeDeepNotOk") - -def testCloneDocumentTypeShallowOk(): - doctype = create_nonempty_doctype() - clone = doctype.cloneNode(0) - confirm(clone is not None - and clone.nodeName == doctype.nodeName - and clone.name == doctype.name - and clone.publicId == doctype.publicId - and clone.systemId == doctype.systemId - and len(clone.entities) == 0 - and clone.entities.item(0) is None - and len(clone.notations) == 0 - and clone.notations.item(0) is None - and len(clone.childNodes) == 0) - -def testCloneDocumentTypeShallowNotOk(): - doc = create_doc_with_doctype() - clone = doc.doctype.cloneNode(0) - confirm(clone is None, "testCloneDocumentTypeShallowNotOk") - -def check_import_document(deep, testName): - doc1 = parseString("") - doc2 = parseString("") - try: - doc1.importNode(doc2, deep) - except xml.dom.NotSupportedErr: - pass - else: - raise Exception(testName + - ": expected NotSupportedErr when importing a document") - -def testImportDocumentShallow(): - check_import_document(0, "testImportDocumentShallow") - -def testImportDocumentDeep(): - check_import_document(1, "testImportDocumentDeep") - # The tests of DocumentType importing use these helpers to construct # the documents to work with, since not all DOM builders actually # create the DocumentType nodes. - def create_doc_without_doctype(doctype=None): return getDOMImplementation().createDocument(None, "doc", doctype) @@ -724,674 +52,1263 @@ doctype.notations.item(0).ownerDocument = doc return doc -def testImportDocumentTypeShallow(): - src = create_doc_with_doctype() - target = create_doc_without_doctype() - try: - imported = target.importNode(src.doctype, 0) - except xml.dom.NotSupportedErr: - pass - else: - raise Exception( - "testImportDocumentTypeShallow: expected NotSupportedErr") - -def testImportDocumentTypeDeep(): - src = create_doc_with_doctype() - target = create_doc_without_doctype() - try: - imported = target.importNode(src.doctype, 1) - except xml.dom.NotSupportedErr: - pass - else: - raise Exception( - "testImportDocumentTypeDeep: expected NotSupportedErr") - -# Testing attribute clones uses a helper, and should always be deep, -# even if the argument to cloneNode is false. -def check_clone_attribute(deep, testName): - doc = parseString("") - attr = doc.documentElement.getAttributeNode("attr") - assert attr is not None - clone = attr.cloneNode(deep) - confirm(not clone.isSameNode(attr)) - confirm(not attr.isSameNode(clone)) - confirm(clone.ownerElement is None, - testName + ": ownerElement should be None") - confirm(clone.ownerDocument.isSameNode(attr.ownerDocument), - testName + ": ownerDocument does not match") - confirm(clone.specified, - testName + ": cloned attribute must have specified == True") - -def testCloneAttributeShallow(): - check_clone_attribute(0, "testCloneAttributeShallow") - -def testCloneAttributeDeep(): - check_clone_attribute(1, "testCloneAttributeDeep") - -def check_clone_pi(deep, testName): - doc = parseString("") - pi = doc.firstChild - assert pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE - clone = pi.cloneNode(deep) - confirm(clone.target == pi.target - and clone.data == pi.data) - -def testClonePIShallow(): - check_clone_pi(0, "testClonePIShallow") - -def testClonePIDeep(): - check_clone_pi(1, "testClonePIDeep") - -def testNormalize(): - doc = parseString("") - root = doc.documentElement - root.appendChild(doc.createTextNode("first")) - root.appendChild(doc.createTextNode("second")) - confirm(len(root.childNodes) == 2 - and root.childNodes.length == 2, "testNormalize -- preparation") - doc.normalize() - confirm(len(root.childNodes) == 1 - and root.childNodes.length == 1 - and root.firstChild is root.lastChild - and root.firstChild.data == "firstsecond" - , "testNormalize -- result") - doc.unlink() - - doc = parseString("") - root = doc.documentElement - root.appendChild(doc.createTextNode("")) - doc.normalize() - confirm(len(root.childNodes) == 0 - and root.childNodes.length == 0, - "testNormalize -- single empty node removed") - doc.unlink() - -def testSiblings(): - doc = parseString("text?") - root = doc.documentElement - (pi, text, elm) = root.childNodes - - confirm(pi.nextSibling is text and - pi.previousSibling is None and - text.nextSibling is elm and - text.previousSibling is pi and - elm.nextSibling is None and - elm.previousSibling is text, "testSiblings") - - doc.unlink() - -def testParents(): - doc = parseString("") - root = doc.documentElement - elm1 = root.childNodes[0] - (elm2a, elm2b) = elm1.childNodes - elm3 = elm2b.childNodes[0] - - confirm(root.parentNode is doc and - elm1.parentNode is root and - elm2a.parentNode is elm1 and - elm2b.parentNode is elm1 and - elm3.parentNode is elm2b, "testParents") - - doc.unlink() - -def testNodeListItem(): - doc = parseString("") - children = doc.childNodes - docelem = children[0] - confirm(children[0] is children.item(0) - and children.item(1) is None - and docelem.childNodes.item(0) is docelem.childNodes[0] - and docelem.childNodes.item(1) is docelem.childNodes[1] - and docelem.childNodes.item(0).childNodes.item(0) is None, - "test NodeList.item()") - doc.unlink() - -def testSAX2DOM(): - from xml.dom import pulldom - - sax2dom = pulldom.SAX2DOM() - sax2dom.startDocument() - sax2dom.startElement("doc", {}) - sax2dom.characters("text") - sax2dom.startElement("subelm", {}) - sax2dom.characters("text") - sax2dom.endElement("subelm") - sax2dom.characters("text") - sax2dom.endElement("doc") - sax2dom.endDocument() - - doc = sax2dom.document - root = doc.documentElement - (text1, elm1, text2) = root.childNodes - text3 = elm1.childNodes[0] - - confirm(text1.previousSibling is None and - text1.nextSibling is elm1 and - elm1.previousSibling is text1 and - elm1.nextSibling is text2 and - text2.previousSibling is elm1 and - text2.nextSibling is None and - text3.previousSibling is None and - text3.nextSibling is None, "testSAX2DOM - siblings") - - confirm(root.parentNode is doc and - text1.parentNode is root and - elm1.parentNode is root and - text2.parentNode is root and - text3.parentNode is elm1, "testSAX2DOM - parents") - - doc.unlink() - -def testEncodings(): - doc = parseString('') - confirm(doc.toxml() == u'\u20ac' - and doc.toxml('utf-8') == '\xe2\x82\xac' - and doc.toxml('iso-8859-15') == '\xa4', - "testEncodings - encoding EURO SIGN") - - # Verify that character decoding errors throw exceptions instead of crashing - try: - doc = parseString('Comment \xe7a va ? Tr\xe8s bien ?') - except UnicodeDecodeError: - pass - else: - print 'parsing with bad encoding should raise a UnicodeDecodeError' - - doc.unlink() - -class UserDataHandler: - called = 0 - def handle(self, operation, key, data, src, dst): - dst.setUserData(key, data + 1, self) - src.setUserData(key, None, None) - self.called = 1 - -def testUserData(): - dom = Document() - n = dom.createElement('e') - confirm(n.getUserData("foo") is None) - n.setUserData("foo", None, None) - confirm(n.getUserData("foo") is None) - n.setUserData("foo", 12, 12) - n.setUserData("bar", 13, 13) - confirm(n.getUserData("foo") == 12) - confirm(n.getUserData("bar") == 13) - n.setUserData("foo", None, None) - confirm(n.getUserData("foo") is None) - confirm(n.getUserData("bar") == 13) - - handler = UserDataHandler() - n.setUserData("bar", 12, handler) - c = n.cloneNode(1) - confirm(handler.called - and n.getUserData("bar") is None - and c.getUserData("bar") == 13) - n.unlink() - c.unlink() - dom.unlink() - -def testRenameAttribute(): - doc = parseString("") - elem = doc.documentElement - attrmap = elem.attributes - attr = elem.attributes['a'] - - # Simple renaming - attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b") - confirm(attr.name == "b" - and attr.nodeName == "b" - and attr.localName is None - and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE - and attr.prefix is None - and attr.value == "v" - and elem.getAttributeNode("a") is None - and elem.getAttributeNode("b").isSameNode(attr) - and attrmap["b"].isSameNode(attr) - and attr.ownerDocument.isSameNode(doc) - and attr.ownerElement.isSameNode(elem)) - - # Rename to have a namespace, no prefix - attr = doc.renameNode(attr, "http://xml.python.org/ns", "c") - confirm(attr.name == "c" - and attr.nodeName == "c" - and attr.localName == "c" - and attr.namespaceURI == "http://xml.python.org/ns" - and attr.prefix is None - and attr.value == "v" - and elem.getAttributeNode("a") is None - and elem.getAttributeNode("b") is None - and elem.getAttributeNode("c").isSameNode(attr) - and elem.getAttributeNodeNS( - "http://xml.python.org/ns", "c").isSameNode(attr) - and attrmap["c"].isSameNode(attr) - and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr)) - - # Rename to have a namespace, with prefix - attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d") - confirm(attr.name == "p:d" - and attr.nodeName == "p:d" - and attr.localName == "d" - and attr.namespaceURI == "http://xml.python.org/ns2" - and attr.prefix == "p" - and attr.value == "v" - and elem.getAttributeNode("a") is None - and elem.getAttributeNode("b") is None - and elem.getAttributeNode("c") is None - and elem.getAttributeNodeNS( - "http://xml.python.org/ns", "c") is None - and elem.getAttributeNode("p:d").isSameNode(attr) - and elem.getAttributeNodeNS( - "http://xml.python.org/ns2", "d").isSameNode(attr) - and attrmap["p:d"].isSameNode(attr) - and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr)) - - # Rename back to a simple non-NS node - attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e") - confirm(attr.name == "e" - and attr.nodeName == "e" - and attr.localName is None - and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE - and attr.prefix is None - and attr.value == "v" - and elem.getAttributeNode("a") is None - and elem.getAttributeNode("b") is None - and elem.getAttributeNode("c") is None - and elem.getAttributeNode("p:d") is None - and elem.getAttributeNodeNS( - "http://xml.python.org/ns", "c") is None - and elem.getAttributeNode("e").isSameNode(attr) - and attrmap["e"].isSameNode(attr)) - - try: - doc.renameNode(attr, "http://xml.python.org/ns", "xmlns") - except xml.dom.NamespaceErr: - pass - else: - print "expected NamespaceErr" - - checkRenameNodeSharedConstraints(doc, attr) - doc.unlink() - -def testRenameElement(): - doc = parseString("") - elem = doc.documentElement - - # Simple renaming - elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a") - confirm(elem.tagName == "a" - and elem.nodeName == "a" - and elem.localName is None - and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE - and elem.prefix is None - and elem.ownerDocument.isSameNode(doc)) - - # Rename to have a namespace, no prefix - elem = doc.renameNode(elem, "http://xml.python.org/ns", "b") - confirm(elem.tagName == "b" - and elem.nodeName == "b" - and elem.localName == "b" - and elem.namespaceURI == "http://xml.python.org/ns" - and elem.prefix is None - and elem.ownerDocument.isSameNode(doc)) - - # Rename to have a namespace, with prefix - elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c") - confirm(elem.tagName == "p:c" - and elem.nodeName == "p:c" - and elem.localName == "c" - and elem.namespaceURI == "http://xml.python.org/ns2" - and elem.prefix == "p" - and elem.ownerDocument.isSameNode(doc)) - - # Rename back to a simple non-NS node - elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d") - confirm(elem.tagName == "d" - and elem.nodeName == "d" - and elem.localName is None - and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE - and elem.prefix is None - and elem.ownerDocument.isSameNode(doc)) - - checkRenameNodeSharedConstraints(doc, elem) - doc.unlink() - -def checkRenameNodeSharedConstraints(doc, node): - # Make sure illegal NS usage is detected: - try: - doc.renameNode(node, "http://xml.python.org/ns", "xmlns:foo") - except xml.dom.NamespaceErr: - pass - else: - print "expected NamespaceErr" - - doc2 = parseString("") - try: - doc2.renameNode(node, xml.dom.EMPTY_NAMESPACE, "foo") - except xml.dom.WrongDocumentErr: - pass - else: - print "expected WrongDocumentErr" - -def testRenameOther(): - # We have to create a comment node explicitly since not all DOM - # builders used with minidom add comments to the DOM. - doc = xml.dom.minidom.getDOMImplementation().createDocument( - xml.dom.EMPTY_NAMESPACE, "e", None) - node = doc.createComment("comment") - try: - doc.renameNode(node, xml.dom.EMPTY_NAMESPACE, "foo") - except xml.dom.NotSupportedErr: +class MinidomTest(unittest.TestCase): + def tearDown(self): + try: + Node.allnodes + except AttributeError: + # We don't actually have the minidom from the standard library, + # but are picking up the PyXML version from site-packages. + pass + else: + self.confirm(len(Node.allnodes) == 0, + "assertion: len(Node.allnodes) == 0") + if len(Node.allnodes): + print "Garbage left over:" + if verbose: + print Node.allnodes.items()[0:10] + else: + # Don't print specific nodes if repeatable results + # are needed + print len(Node.allnodes) + Node.allnodes = {} + + def confirm(self, test, testname = "Test"): + self.assertTrue(test, testname) + + def checkWholeText(self, node, s): + t = node.wholeText + self.confirm(t == s, "looking for %s, found %s" % (repr(s), repr(t))) + + def testParseFromFile(self): + dom = parse(StringIO(open(tstfile).read())) + dom.unlink() + self.confirm(isinstance(dom,Document)) + + def testGetElementsByTagName(self): + dom = parse(tstfile) + self.confirm(dom.getElementsByTagName("LI") == \ + dom.documentElement.getElementsByTagName("LI")) + dom.unlink() + + def testInsertBefore(self): + dom = parseString("") + root = dom.documentElement + elem = root.childNodes[0] + nelem = dom.createElement("element") + root.insertBefore(nelem, elem) + self.confirm(len(root.childNodes) == 2 + and root.childNodes.length == 2 + and root.childNodes[0] is nelem + and root.childNodes.item(0) is nelem + and root.childNodes[1] is elem + and root.childNodes.item(1) is elem + and root.firstChild is nelem + and root.lastChild is elem + and root.toxml() == "" + , "testInsertBefore -- node properly placed in tree") + nelem = dom.createElement("element") + root.insertBefore(nelem, None) + self.confirm(len(root.childNodes) == 3 + and root.childNodes.length == 3 + and root.childNodes[1] is elem + and root.childNodes.item(1) is elem + and root.childNodes[2] is nelem + and root.childNodes.item(2) is nelem + and root.lastChild is nelem + and nelem.previousSibling is elem + and root.toxml() == "" + , "testInsertBefore -- node properly placed in tree") + nelem2 = dom.createElement("bar") + root.insertBefore(nelem2, nelem) + self.confirm(len(root.childNodes) == 4 + and root.childNodes.length == 4 + and root.childNodes[2] is nelem2 + and root.childNodes.item(2) is nelem2 + and root.childNodes[3] is nelem + and root.childNodes.item(3) is nelem + and nelem2.nextSibling is nelem + and nelem.previousSibling is nelem2 + and root.toxml() == + "" + , "testInsertBefore -- node properly placed in tree") + dom.unlink() + + def _create_fragment_test_nodes(self): + dom = parseString("") + orig = dom.createTextNode("original") + c1 = dom.createTextNode("foo") + c2 = dom.createTextNode("bar") + c3 = dom.createTextNode("bat") + dom.documentElement.appendChild(orig) + frag = dom.createDocumentFragment() + frag.appendChild(c1) + frag.appendChild(c2) + frag.appendChild(c3) + return dom, orig, c1, c2, c3, frag + + def testInsertBeforeFragment(self): + dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes() + dom.documentElement.insertBefore(frag, None) + self.confirm(tuple(dom.documentElement.childNodes) == + (orig, c1, c2, c3), + "insertBefore(, None)") + frag.unlink() + dom.unlink() + + dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes() + dom.documentElement.insertBefore(frag, orig) + self.confirm(tuple(dom.documentElement.childNodes) == + (c1, c2, c3, orig), + "insertBefore(, orig)") + frag.unlink() + dom.unlink() + + def testAppendChild(self): + dom = parse(tstfile) + dom.documentElement.appendChild(dom.createComment(u"Hello")) + self.confirm(dom.documentElement.childNodes[-1].nodeName == "#comment") + self.confirm(dom.documentElement.childNodes[-1].data == "Hello") + dom.unlink() + + def testAppendChildFragment(self): + dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes() + dom.documentElement.appendChild(frag) + self.confirm(tuple(dom.documentElement.childNodes) == + (orig, c1, c2, c3), + "appendChild()") + frag.unlink() + dom.unlink() + + def testReplaceChildFragment(self): + dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes() + dom.documentElement.replaceChild(frag, orig) + orig.unlink() + self.confirm(tuple(dom.documentElement.childNodes) == (c1, c2, c3), + "replaceChild()") + frag.unlink() + dom.unlink() + + def testLegalChildren(self): + dom = Document() + elem = dom.createElement('element') + text = dom.createTextNode('text') + self.assertRaises(xml.dom.HierarchyRequestErr, dom.appendChild, text) + + dom.appendChild(elem) + self.assertRaises(xml.dom.HierarchyRequestErr, dom.insertBefore, text, + elem) + self.assertRaises(xml.dom.HierarchyRequestErr, dom.replaceChild, text, + elem) + + nodemap = elem.attributes + self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItem, + text) + self.assertRaises(xml.dom.HierarchyRequestErr, nodemap.setNamedItemNS, + text) + + elem.appendChild(text) + dom.unlink() + + def testNamedNodeMapSetItem(self): + dom = Document() + elem = dom.createElement('element') + attrs = elem.attributes + attrs["foo"] = "bar" + a = attrs.item(0) + self.confirm(a.ownerDocument is dom, + "NamedNodeMap.__setitem__() sets ownerDocument") + self.confirm(a.ownerElement is elem, + "NamedNodeMap.__setitem__() sets ownerElement") + self.confirm(a.value == "bar", + "NamedNodeMap.__setitem__() sets value") + self.confirm(a.nodeValue == "bar", + "NamedNodeMap.__setitem__() sets nodeValue") + elem.unlink() + dom.unlink() + + def testNonZero(self): + dom = parse(tstfile) + self.confirm(dom)# should not be zero + dom.appendChild(dom.createComment("foo")) + self.confirm(not dom.childNodes[-1].childNodes) + dom.unlink() + + def testUnlink(self): + dom = parse(tstfile) + dom.unlink() + + def testElement(self): + dom = Document() + dom.appendChild(dom.createElement("abc")) + self.confirm(dom.documentElement) + dom.unlink() + + def testAAA(self): + dom = parseString("") + el = dom.documentElement + el.setAttribute("spam", "jam2") + self.confirm(el.toxml() == '', "testAAA") + a = el.getAttributeNode("spam") + self.confirm(a.ownerDocument is dom, + "setAttribute() sets ownerDocument") + self.confirm(a.ownerElement is dom.documentElement, + "setAttribute() sets ownerElement") + dom.unlink() + + def testAAB(self): + dom = parseString("") + el = dom.documentElement + el.setAttribute("spam", "jam") + el.setAttribute("spam", "jam2") + self.confirm(el.toxml() == '', "testAAB") + dom.unlink() + + def testAddAttr(self): + dom = Document() + child = dom.appendChild(dom.createElement("abc")) + + child.setAttribute("def", "ghi") + self.confirm(child.getAttribute("def") == "ghi") + self.confirm(child.attributes["def"].value == "ghi") + + child.setAttribute("jkl", "mno") + self.confirm(child.getAttribute("jkl") == "mno") + self.confirm(child.attributes["jkl"].value == "mno") + + self.confirm(len(child.attributes) == 2) + + child.setAttribute("def", "newval") + self.confirm(child.getAttribute("def") == "newval") + self.confirm(child.attributes["def"].value == "newval") + + self.confirm(len(child.attributes) == 2) + dom.unlink() + + def testDeleteAttr(self): + dom = Document() + child = dom.appendChild(dom.createElement("abc")) + + self.confirm(len(child.attributes) == 0) + child.setAttribute("def", "ghi") + self.confirm(len(child.attributes) == 1) + del child.attributes["def"] + self.confirm(len(child.attributes) == 0) + dom.unlink() + + def testRemoveAttr(self): + dom = Document() + child = dom.appendChild(dom.createElement("abc")) + + child.setAttribute("def", "ghi") + self.confirm(len(child.attributes) == 1) + child.removeAttribute("def") + self.confirm(len(child.attributes) == 0) + dom.unlink() + + def testRemoveAttrNS(self): + dom = Document() + child = dom.appendChild( + dom.createElementNS("http://www.python.org", "python:abc")) + child.setAttributeNS("http://www.w3.org", "xmlns:python", + "http://www.python.org") + child.setAttributeNS("http://www.python.org", "python:abcattr", "foo") + self.confirm(len(child.attributes) == 2) + child.removeAttributeNS("http://www.python.org", "abcattr") + self.confirm(len(child.attributes) == 1) + dom.unlink() + + def testRemoveAttributeNode(self): + dom = Document() + child = dom.appendChild(dom.createElement("foo")) + child.setAttribute("spam", "jam") + self.confirm(len(child.attributes) == 1) + node = child.getAttributeNode("spam") + child.removeAttributeNode(node) + self.confirm(len(child.attributes) == 0 + and child.getAttributeNode("spam") is None) + dom.unlink() + + def testChangeAttr(self): + dom = parseString("") + el = dom.documentElement + el.setAttribute("spam", "jam") + self.confirm(len(el.attributes) == 1) + el.setAttribute("spam", "bam") + # Set this attribute to be an ID and make sure that doesn't change + # when changing the value: + el.setIdAttribute("spam") + self.confirm(len(el.attributes) == 1 + and el.attributes["spam"].value == "bam" + and el.attributes["spam"].nodeValue == "bam" + and el.getAttribute("spam") == "bam" + and el.getAttributeNode("spam").isId) + el.attributes["spam"] = "ham" + self.confirm(len(el.attributes) == 1 + and el.attributes["spam"].value == "ham" + and el.attributes["spam"].nodeValue == "ham" + and el.getAttribute("spam") == "ham" + and el.attributes["spam"].isId) + el.setAttribute("spam2", "bam") + self.confirm(len(el.attributes) == 2 + and el.attributes["spam"].value == "ham" + and el.attributes["spam"].nodeValue == "ham" + and el.getAttribute("spam") == "ham" + and el.attributes["spam2"].value == "bam" + and el.attributes["spam2"].nodeValue == "bam" + and el.getAttribute("spam2") == "bam") + el.attributes["spam2"] = "bam2" + self.confirm(len(el.attributes) == 2 + and el.attributes["spam"].value == "ham" + and el.attributes["spam"].nodeValue == "ham" + and el.getAttribute("spam") == "ham" + and el.attributes["spam2"].value == "bam2" + and el.attributes["spam2"].nodeValue == "bam2" + and el.getAttribute("spam2") == "bam2") + dom.unlink() + + def testGetAttrList(self): pass - else: - print "expected NotSupportedErr when renaming comment node" - doc.unlink() - -def checkWholeText(node, s): - t = node.wholeText - confirm(t == s, "looking for %s, found %s" % (repr(s), repr(t))) - -def testWholeText(): - doc = parseString("a") - elem = doc.documentElement - text = elem.childNodes[0] - assert text.nodeType == Node.TEXT_NODE - - checkWholeText(text, "a") - elem.appendChild(doc.createTextNode("b")) - checkWholeText(text, "ab") - elem.insertBefore(doc.createCDATASection("c"), text) - checkWholeText(text, "cab") - - # make sure we don't cross other nodes - splitter = doc.createComment("comment") - elem.appendChild(splitter) - text2 = doc.createTextNode("d") - elem.appendChild(text2) - checkWholeText(text, "cab") - checkWholeText(text2, "d") - - x = doc.createElement("x") - elem.replaceChild(x, splitter) - splitter = x - checkWholeText(text, "cab") - checkWholeText(text2, "d") - - x = doc.createProcessingInstruction("y", "z") - elem.replaceChild(x, splitter) - splitter = x - checkWholeText(text, "cab") - checkWholeText(text2, "d") - - elem.removeChild(splitter) - checkWholeText(text, "cabd") - checkWholeText(text2, "cabd") - -def testPatch1094164 (): - doc = parseString("") - elem = doc.documentElement - e = elem.firstChild - confirm(e.parentNode is elem, "Before replaceChild()") - # Check that replacing a child with itself leaves the tree unchanged - elem.replaceChild(e, e) - confirm(e.parentNode is elem, "After replaceChild()") - - + + def testGetAttrValues(self): pass + + def testGetAttrLength(self): pass + + def testGetAttribute(self): pass + + def testGetAttributeNS(self): pass + + def testGetAttributeNode(self): pass + + def testGetElementsByTagNameNS(self): + d=""" + + """ + dom = parseString(d) + elems = dom.getElementsByTagNameNS("http://pyxml.sf.net/minidom", + "myelem") + self.confirm(len(elems) == 1 + and elems[0].namespaceURI == "http://pyxml.sf.net/minidom" + and elems[0].localName == "myelem" + and elems[0].prefix == "minidom" + and elems[0].tagName == "minidom:myelem" + and elems[0].nodeName == "minidom:myelem") + dom.unlink() + + def get_empty_nodelist_from_elements_by_tagName_ns_helper(self, doc, nsuri, + lname): + nodelist = doc.getElementsByTagNameNS(nsuri, lname) + self.confirm(len(nodelist) == 0) + + def testGetEmptyNodeListFromElementsByTagNameNS(self): + doc = parseString('') + self.get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, 'http://xml.python.org/namespaces/a', 'localname') + self.get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, '*', 'splat') + self.get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, 'http://xml.python.org/namespaces/a', '*') + + doc = parseString('') + self.get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, "http://xml.python.org/splat", "not-there") + self.get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, "*", "not-there") + self.get_empty_nodelist_from_elements_by_tagName_ns_helper( + doc, "http://somewhere.else.net/not-there", "e") + + def testElementReprAndStr(self): + dom = Document() + el = dom.appendChild(dom.createElement("abc")) + string1 = repr(el) + string2 = str(el) + self.confirm(string1 == string2) + dom.unlink() + + def testElementReprAndStrUnicode(self): + dom = Document() + el = dom.appendChild(dom.createElement(u"abc")) + string1 = repr(el) + string2 = str(el) + self.confirm(string1 == string2) + dom.unlink() + + def testElementReprAndStrUnicodeNS(self): + dom = Document() + el = dom.appendChild( + dom.createElementNS(u"http://www.slashdot.org", u"slash:abc")) + string1 = repr(el) + string2 = str(el) + self.confirm(string1 == string2) + self.confirm(string1.find("slash:abc") != -1) + dom.unlink() + + def testAttributeRepr(self): + dom = Document() + el = dom.appendChild(dom.createElement(u"abc")) + node = el.setAttribute("abc", "def") + self.confirm(str(node) == repr(node)) + dom.unlink() + + def testTextNodeRepr(self): pass + + def testWriteXML(self): + str = '' + dom = parseString(str) + domstr = dom.toxml() + dom.unlink() + self.confirm(str == domstr) + + def testAltNewline(self): + str = '\n\n' + dom = parseString(str) + domstr = dom.toprettyxml(newl="\r\n") + dom.unlink() + self.confirm(domstr == str.replace("\n", "\r\n")) + + def testProcessingInstruction(self): + dom = parseString('') + pi = dom.documentElement.firstChild + self.confirm(pi.target == "mypi" + and pi.data == "data \t\n " + and pi.nodeName == "mypi" + and pi.nodeType == Node.PROCESSING_INSTRUCTION_NODE + and pi.attributes is None + and not pi.hasChildNodes() + and len(pi.childNodes) == 0 + and pi.firstChild is None + and pi.lastChild is None + and pi.localName is None + and pi.namespaceURI == xml.dom.EMPTY_NAMESPACE) + + def testProcessingInstructionRepr(self): pass + + def testTextRepr(self): pass + + def testWriteText(self): pass + + def testDocumentElement(self): pass + + def testTooManyDocumentElements(self): + doc = parseString("") + elem = doc.createElement("extra") + # Should raise an exception when adding an extra document element. + self.assertRaises(xml.dom.HierarchyRequestErr, doc.appendChild, elem) + elem.unlink() + doc.unlink() + + def testCreateElementNS(self): pass + + def testCreateAttributeNS(self): pass + + def testParse(self): pass + + def testParseString(self): pass + + def testComment(self): pass + + def testAttrListItem(self): pass + + def testAttrListItems(self): pass + + def testAttrListItemNS(self): pass + + def testAttrListKeys(self): pass + + def testAttrListKeysNS(self): pass + + def testRemoveNamedItem(self): + doc = parseString("") + e = doc.documentElement + attrs = e.attributes + a1 = e.getAttributeNode("a") + a2 = attrs.removeNamedItem("a") + self.confirm(a1.isSameNode(a2)) + self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItem, "a") + + def testRemoveNamedItemNS(self): + doc = parseString("") + e = doc.documentElement + attrs = e.attributes + a1 = e.getAttributeNodeNS("http://xml.python.org/", "b") + a2 = attrs.removeNamedItemNS("http://xml.python.org/", "b") + self.confirm(a1.isSameNode(a2)) + self.assertRaises(xml.dom.NotFoundErr, attrs.removeNamedItemNS, + "http://xml.python.org/", "b") + + def testAttrListValues(self): pass + + def testAttrListLength(self): pass + + def testAttrList__getitem__(self): pass + + def testAttrList__setitem__(self): pass + + def testSetAttrValueandNodeValue(self): pass + + def testParseElement(self): pass + + def testParseAttributes(self): pass + + def testParseElementNamespaces(self): pass + + def testParseAttributeNamespaces(self): pass + + def testParseProcessingInstructions(self): pass + + def testChildNodes(self): pass + + def testFirstChild(self): pass + + def testHasChildNodes(self): pass + + def _testCloneElementCopiesAttributes(self, e1, e2, test): + attrs1 = e1.attributes + attrs2 = e2.attributes + keys1 = attrs1.keys() + keys2 = attrs2.keys() + keys1.sort() + keys2.sort() + self.confirm(keys1 == keys2, "clone of element has same attribute keys") + for i in range(len(keys1)): + a1 = attrs1.item(i) + a2 = attrs2.item(i) + self.confirm(a1 is not a2 + and a1.value == a2.value + and a1.nodeValue == a2.nodeValue + and a1.namespaceURI == a2.namespaceURI + and a1.localName == a2.localName + , "clone of attribute node has proper attribute values") + self.confirm(a2.ownerElement is e2, + "clone of attribute node correctly owned") + + def _setupCloneElement(self, deep): + dom = parseString("") + root = dom.documentElement + clone = root.cloneNode(deep) + self._testCloneElementCopiesAttributes( + root, clone, "testCloneElement" + (deep and "Deep" or "Shallow")) + # mutilate the original so shared data is detected + root.tagName = root.nodeName = "MODIFIED" + root.setAttribute("attr", "NEW VALUE") + root.setAttribute("added", "VALUE") + return dom, clone + + def testCloneElementShallow(self): + dom, clone = self._setupCloneElement(0) + self.confirm(len(clone.childNodes) == 0 + and clone.childNodes.length == 0 + and clone.parentNode is None + and clone.toxml() == '' + , "testCloneElementShallow") + dom.unlink() + + def testCloneElementDeep(self): + dom, clone = self._setupCloneElement(1) + self.confirm(len(clone.childNodes) == 1 + and clone.childNodes.length == 1 + and clone.parentNode is None + and clone.toxml() == '' + , "testCloneElementDeep") + dom.unlink() + + def testCloneDocumentShallow(self): + doc = parseString("\n" + "" + "\n" + "]>\n" + "") + doc2 = doc.cloneNode(0) + self.confirm(doc2 is None, + "testCloneDocumentShallow:" + " shallow cloning of documents makes no sense!") + + def testCloneDocumentDeep(self): + doc = parseString("\n" + "" + "\n" + "]>\n" + "") + doc2 = doc.cloneNode(1) + self.confirm(not (doc.isSameNode(doc2) or doc2.isSameNode(doc)), + "testCloneDocumentDeep: document objects not distinct") + self.confirm(len(doc.childNodes) == len(doc2.childNodes), + "testCloneDocumentDeep: wrong number of Document children") + self.confirm(doc2.documentElement.nodeType == Node.ELEMENT_NODE, + "testCloneDocumentDeep: documentElement not an ELEMENT_NODE") + self.confirm(doc2.documentElement.ownerDocument.isSameNode(doc2), + "testCloneDocumentDeep: documentElement owner is not new document") + self.confirm(not doc.documentElement.isSameNode(doc2.documentElement), + "testCloneDocumentDeep: documentElement should not be shared") + if doc.doctype is not None: + # check the doctype iff the original DOM maintained it + self.confirm(doc2.doctype.nodeType == Node.DOCUMENT_TYPE_NODE, + "testCloneDocumentDeep: doctype not a DOCUMENT_TYPE_NODE") + self.confirm(doc2.doctype.ownerDocument.isSameNode(doc2)) + self.confirm(not doc.doctype.isSameNode(doc2.doctype)) + + def testCloneDocumentTypeDeepOk(self): + doctype = create_nonempty_doctype() + clone = doctype.cloneNode(1) + self.confirm(clone is not None + and clone.nodeName == doctype.nodeName + and clone.name == doctype.name + and clone.publicId == doctype.publicId + and clone.systemId == doctype.systemId + and len(clone.entities) == len(doctype.entities) + and clone.entities.item(len(clone.entities)) is None + and len(clone.notations) == len(doctype.notations) + and clone.notations.item(len(clone.notations)) is None + and len(clone.childNodes) == 0) + for i in range(len(doctype.entities)): + se = doctype.entities.item(i) + ce = clone.entities.item(i) + self.confirm((not se.isSameNode(ce)) + and (not ce.isSameNode(se)) + and ce.nodeName == se.nodeName + and ce.notationName == se.notationName + and ce.publicId == se.publicId + and ce.systemId == se.systemId + and ce.encoding == se.encoding + and ce.actualEncoding == se.actualEncoding + and ce.version == se.version) + for i in range(len(doctype.notations)): + sn = doctype.notations.item(i) + cn = clone.notations.item(i) + self.confirm((not sn.isSameNode(cn)) + and (not cn.isSameNode(sn)) + and cn.nodeName == sn.nodeName + and cn.publicId == sn.publicId + and cn.systemId == sn.systemId) + + def testCloneDocumentTypeDeepNotOk(self): + doc = create_doc_with_doctype() + clone = doc.doctype.cloneNode(1) + self.confirm(clone is None, "testCloneDocumentTypeDeepNotOk") + + def testCloneDocumentTypeShallowOk(self): + doctype = create_nonempty_doctype() + clone = doctype.cloneNode(0) + self.confirm(clone is not None + and clone.nodeName == doctype.nodeName + and clone.name == doctype.name + and clone.publicId == doctype.publicId + and clone.systemId == doctype.systemId + and len(clone.entities) == 0 + and clone.entities.item(0) is None + and len(clone.notations) == 0 + and clone.notations.item(0) is None + and len(clone.childNodes) == 0) + + def testCloneDocumentTypeShallowNotOk(self): + doc = create_doc_with_doctype() + clone = doc.doctype.cloneNode(0) + self.confirm(clone is None, "testCloneDocumentTypeShallowNotOk") + + def check_import_document(self, deep, testName): + doc1 = parseString("") + doc2 = parseString("") + self.assertRaises(xml.dom.NotSupportedErr, doc1.importNode, doc2, deep) + + def testImportDocumentShallow(self): + self.check_import_document(0, "testImportDocumentShallow") + + def testImportDocumentDeep(self): + self.check_import_document(1, "testImportDocumentDeep") + + def testImportDocumentTypeShallow(self): + src = create_doc_with_doctype() + target = create_doc_without_doctype() + self.assertRaises(xml.dom.NotSupportedErr, target.importNode, + src.doctype, 0) + + def testImportDocumentTypeDeep(self): + src = create_doc_with_doctype() + target = create_doc_without_doctype() + self.assertRaises(xml.dom.NotSupportedErr, target.importNode, + src.doctype, 1) + + # Testing attribute clones uses a helper, and should always be deep, + # even if the argument to cloneNode is false. + def check_clone_attribute(self, deep, testName): + doc = parseString("") + attr = doc.documentElement.getAttributeNode("attr") + self.failIfEqual(attr, None) + clone = attr.cloneNode(deep) + self.confirm(not clone.isSameNode(attr)) + self.confirm(not attr.isSameNode(clone)) + self.confirm(clone.ownerElement is None, + testName + ": ownerElement should be None") + self.confirm(clone.ownerDocument.isSameNode(attr.ownerDocument), + testName + ": ownerDocument does not match") + self.confirm(clone.specified, + testName + ": cloned attribute must have specified == True") + + def testCloneAttributeShallow(self): + self.check_clone_attribute(0, "testCloneAttributeShallow") + + def testCloneAttributeDeep(self): + self.check_clone_attribute(1, "testCloneAttributeDeep") + + def check_clone_pi(self, deep, testName): + doc = parseString("") + pi = doc.firstChild + self.assertEquals(pi.nodeType, Node.PROCESSING_INSTRUCTION_NODE) + clone = pi.cloneNode(deep) + self.confirm(clone.target == pi.target + and clone.data == pi.data) + + def testClonePIShallow(self): + self.check_clone_pi(0, "testClonePIShallow") + + def testClonePIDeep(self): + self.check_clone_pi(1, "testClonePIDeep") + + def testNormalize(self): + doc = parseString("") + root = doc.documentElement + root.appendChild(doc.createTextNode("first")) + root.appendChild(doc.createTextNode("second")) + self.confirm(len(root.childNodes) == 2 + and root.childNodes.length == 2, + "testNormalize -- preparation") + doc.normalize() + self.confirm(len(root.childNodes) == 1 + and root.childNodes.length == 1 + and root.firstChild is root.lastChild + and root.firstChild.data == "firstsecond" + , "testNormalize -- result") + doc.unlink() + + doc = parseString("") + root = doc.documentElement + root.appendChild(doc.createTextNode("")) + doc.normalize() + self.confirm(len(root.childNodes) == 0 + and root.childNodes.length == 0, + "testNormalize -- single empty node removed") + doc.unlink() + + def testSiblings(self): + doc = parseString("text?") + root = doc.documentElement + (pi, text, elm) = root.childNodes + + self.confirm(pi.nextSibling is text and + pi.previousSibling is None and + text.nextSibling is elm and + text.previousSibling is pi and + elm.nextSibling is None and + elm.previousSibling is text, "testSiblings") + + doc.unlink() + + def testParents(self): + doc = parseString( + "") + root = doc.documentElement + elm1 = root.childNodes[0] + (elm2a, elm2b) = elm1.childNodes + elm3 = elm2b.childNodes[0] + + self.confirm(root.parentNode is doc and + elm1.parentNode is root and + elm2a.parentNode is elm1 and + elm2b.parentNode is elm1 and + elm3.parentNode is elm2b, "testParents") + doc.unlink() + + def testNodeListItem(self): + doc = parseString("") + children = doc.childNodes + docelem = children[0] + self.confirm(children[0] is children.item(0) + and children.item(1) is None + and docelem.childNodes.item(0) is docelem.childNodes[0] + and docelem.childNodes.item(1) is docelem.childNodes[1] + and docelem.childNodes.item(0).childNodes.item(0) is None, + "test NodeList.item()") + doc.unlink() + + def testSAX2DOM(self): + from xml.dom import pulldom + + sax2dom = pulldom.SAX2DOM() + sax2dom.startDocument() + sax2dom.startElement("doc", {}) + sax2dom.characters("text") + sax2dom.startElement("subelm", {}) + sax2dom.characters("text") + sax2dom.endElement("subelm") + sax2dom.characters("text") + sax2dom.endElement("doc") + sax2dom.endDocument() + + doc = sax2dom.document + root = doc.documentElement + (text1, elm1, text2) = root.childNodes + text3 = elm1.childNodes[0] + + self.confirm(text1.previousSibling is None and + text1.nextSibling is elm1 and + elm1.previousSibling is text1 and + elm1.nextSibling is text2 and + text2.previousSibling is elm1 and + text2.nextSibling is None and + text3.previousSibling is None and + text3.nextSibling is None, "testSAX2DOM - siblings") + + self.confirm(root.parentNode is doc and + text1.parentNode is root and + elm1.parentNode is root and + text2.parentNode is root and + text3.parentNode is elm1, "testSAX2DOM - parents") + doc.unlink() + + def testEncodings(self): + doc = parseString('') + self.confirm(doc.toxml() == u'\u20ac' + and doc.toxml('utf-8') == + '\xe2\x82\xac' + and doc.toxml('iso-8859-15') == + '\xa4', + "testEncodings - encoding EURO SIGN") + + # Verify that character decoding errors throw exceptions instead + # of crashing + self.assertRaises(UnicodeDecodeError, parseString, + 'Comment \xe7a va ? Tr\xe8s bien ?') + + doc.unlink() + + class UserDataHandler: + called = 0 + def handle(self, operation, key, data, src, dst): + dst.setUserData(key, data + 1, self) + src.setUserData(key, None, None) + self.called = 1 + + def testUserData(self): + dom = Document() + n = dom.createElement('e') + self.confirm(n.getUserData("foo") is None) + n.setUserData("foo", None, None) + self.confirm(n.getUserData("foo") is None) + n.setUserData("foo", 12, 12) + n.setUserData("bar", 13, 13) + self.confirm(n.getUserData("foo") == 12) + self.confirm(n.getUserData("bar") == 13) + n.setUserData("foo", None, None) + self.confirm(n.getUserData("foo") is None) + self.confirm(n.getUserData("bar") == 13) + + handler = self.UserDataHandler() + n.setUserData("bar", 12, handler) + c = n.cloneNode(1) + self.confirm(handler.called + and n.getUserData("bar") is None + and c.getUserData("bar") == 13) + n.unlink() + c.unlink() + dom.unlink() + + def checkRenameNodeSharedConstraints(self, doc, node): + # Make sure illegal NS usage is detected: + self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, node, + "http://xml.python.org/ns", "xmlns:foo") + doc2 = parseString("") + self.assertRaises(xml.dom.WrongDocumentErr, doc2.renameNode, node, + xml.dom.EMPTY_NAMESPACE, "foo") + + def testRenameAttribute(self): + doc = parseString("") + elem = doc.documentElement + attrmap = elem.attributes + attr = elem.attributes['a'] + + # Simple renaming + attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "b") + self.confirm(attr.name == "b" + and attr.nodeName == "b" + and attr.localName is None + and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE + and attr.prefix is None + and attr.value == "v" + and elem.getAttributeNode("a") is None + and elem.getAttributeNode("b").isSameNode(attr) + and attrmap["b"].isSameNode(attr) + and attr.ownerDocument.isSameNode(doc) + and attr.ownerElement.isSameNode(elem)) + + # Rename to have a namespace, no prefix + attr = doc.renameNode(attr, "http://xml.python.org/ns", "c") + self.confirm(attr.name == "c" + and attr.nodeName == "c" + and attr.localName == "c" + and attr.namespaceURI == "http://xml.python.org/ns" + and attr.prefix is None + and attr.value == "v" + and elem.getAttributeNode("a") is None + and elem.getAttributeNode("b") is None + and elem.getAttributeNode("c").isSameNode(attr) + and elem.getAttributeNodeNS( + "http://xml.python.org/ns", "c").isSameNode(attr) + and attrmap["c"].isSameNode(attr) + and attrmap[("http://xml.python.org/ns", "c")].isSameNode(attr)) + + # Rename to have a namespace, with prefix + attr = doc.renameNode(attr, "http://xml.python.org/ns2", "p:d") + self.confirm(attr.name == "p:d" + and attr.nodeName == "p:d" + and attr.localName == "d" + and attr.namespaceURI == "http://xml.python.org/ns2" + and attr.prefix == "p" + and attr.value == "v" + and elem.getAttributeNode("a") is None + and elem.getAttributeNode("b") is None + and elem.getAttributeNode("c") is None + and elem.getAttributeNodeNS( + "http://xml.python.org/ns", "c") is None + and elem.getAttributeNode("p:d").isSameNode(attr) + and elem.getAttributeNodeNS( + "http://xml.python.org/ns2", "d").isSameNode(attr) + and attrmap["p:d"].isSameNode(attr) + and attrmap[("http://xml.python.org/ns2", "d")].isSameNode(attr)) + + # Rename back to a simple non-NS node + attr = doc.renameNode(attr, xml.dom.EMPTY_NAMESPACE, "e") + self.confirm(attr.name == "e" + and attr.nodeName == "e" + and attr.localName is None + and attr.namespaceURI == xml.dom.EMPTY_NAMESPACE + and attr.prefix is None + and attr.value == "v" + and elem.getAttributeNode("a") is None + and elem.getAttributeNode("b") is None + and elem.getAttributeNode("c") is None + and elem.getAttributeNode("p:d") is None + and elem.getAttributeNodeNS( + "http://xml.python.org/ns", "c") is None + and elem.getAttributeNode("e").isSameNode(attr) + and attrmap["e"].isSameNode(attr)) + + self.assertRaises(xml.dom.NamespaceErr, doc.renameNode, attr, + "http://xml.python.org/ns", "xmlns") + self.checkRenameNodeSharedConstraints(doc, attr) + doc.unlink() + + def testRenameElement(self): + doc = parseString("") + elem = doc.documentElement + + # Simple renaming + elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "a") + self.confirm(elem.tagName == "a" + and elem.nodeName == "a" + and elem.localName is None + and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE + and elem.prefix is None + and elem.ownerDocument.isSameNode(doc)) + + # Rename to have a namespace, no prefix + elem = doc.renameNode(elem, "http://xml.python.org/ns", "b") + self.confirm(elem.tagName == "b" + and elem.nodeName == "b" + and elem.localName == "b" + and elem.namespaceURI == "http://xml.python.org/ns" + and elem.prefix is None + and elem.ownerDocument.isSameNode(doc)) + + # Rename to have a namespace, with prefix + elem = doc.renameNode(elem, "http://xml.python.org/ns2", "p:c") + self.confirm(elem.tagName == "p:c" + and elem.nodeName == "p:c" + and elem.localName == "c" + and elem.namespaceURI == "http://xml.python.org/ns2" + and elem.prefix == "p" + and elem.ownerDocument.isSameNode(doc)) + + # Rename back to a simple non-NS node + elem = doc.renameNode(elem, xml.dom.EMPTY_NAMESPACE, "d") + self.confirm(elem.tagName == "d" + and elem.nodeName == "d" + and elem.localName is None + and elem.namespaceURI == xml.dom.EMPTY_NAMESPACE + and elem.prefix is None + and elem.ownerDocument.isSameNode(doc)) + + self.checkRenameNodeSharedConstraints(doc, elem) + doc.unlink() + + def testRenameOther(self): + # We have to create a comment node explicitly since not all DOM + # builders used with minidom add comments to the DOM. + doc = xml.dom.minidom.getDOMImplementation().createDocument( + xml.dom.EMPTY_NAMESPACE, "e", None) + node = doc.createComment("comment") + self.assertRaises(xml.dom.NotSupportedErr, doc.renameNode, node, + xml.dom.EMPTY_NAMESPACE, "foo") + doc.unlink() -def testReplaceWholeText(): - def setup(): - doc = parseString("ad") + def testWholeText(self): + doc = parseString("a") + elem = doc.documentElement + text = elem.childNodes[0] + self.assertEquals(text.nodeType, Node.TEXT_NODE) + + self.checkWholeText(text, "a") + elem.appendChild(doc.createTextNode("b")) + self.checkWholeText(text, "ab") + elem.insertBefore(doc.createCDATASection("c"), text) + self.checkWholeText(text, "cab") + + # make sure we don't cross other nodes + splitter = doc.createComment("comment") + elem.appendChild(splitter) + text2 = doc.createTextNode("d") + elem.appendChild(text2) + self.checkWholeText(text, "cab") + self.checkWholeText(text2, "d") + + x = doc.createElement("x") + elem.replaceChild(x, splitter) + splitter = x + self.checkWholeText(text, "cab") + self.checkWholeText(text2, "d") + + x = doc.createProcessingInstruction("y", "z") + elem.replaceChild(x, splitter) + splitter = x + self.checkWholeText(text, "cab") + self.checkWholeText(text2, "d") + + elem.removeChild(splitter) + self.checkWholeText(text, "cabd") + self.checkWholeText(text2, "cabd") + + def testPatch1094164(self): + doc = parseString("") + elem = doc.documentElement + e = elem.firstChild + self.confirm(e.parentNode is elem, "Before replaceChild()") + # Check that replacing a child with itself leaves the tree unchanged + elem.replaceChild(e, e) + self.confirm(e.parentNode is elem, "After replaceChild()") + + def testReplaceWholeText(self): + def setup(): + doc = parseString("ad") + elem = doc.documentElement + text1 = elem.firstChild + text2 = elem.lastChild + splitter = text1.nextSibling + elem.insertBefore(doc.createTextNode("b"), splitter) + elem.insertBefore(doc.createCDATASection("c"), text1) + return doc, elem, text1, splitter, text2 + + doc, elem, text1, splitter, text2 = setup() + text = text1.replaceWholeText("new content") + self.checkWholeText(text, "new content") + self.checkWholeText(text2, "d") + self.confirm(len(elem.childNodes) == 3) + + doc, elem, text1, splitter, text2 = setup() + text = text2.replaceWholeText("new content") + self.checkWholeText(text, "new content") + self.checkWholeText(text1, "cab") + self.confirm(len(elem.childNodes) == 5) + + doc, elem, text1, splitter, text2 = setup() + text = text1.replaceWholeText("") + self.checkWholeText(text2, "d") + self.confirm(text is None + and len(elem.childNodes) == 2) + + def testSchemaType(self): + doc = parseString( + "\n" + " \n" + " \n" + "]>") elem = doc.documentElement - text1 = elem.firstChild - text2 = elem.lastChild - splitter = text1.nextSibling - elem.insertBefore(doc.createTextNode("b"), splitter) - elem.insertBefore(doc.createCDATASection("c"), text1) - return doc, elem, text1, splitter, text2 - - doc, elem, text1, splitter, text2 = setup() - text = text1.replaceWholeText("new content") - checkWholeText(text, "new content") - checkWholeText(text2, "d") - confirm(len(elem.childNodes) == 3) - - doc, elem, text1, splitter, text2 = setup() - text = text2.replaceWholeText("new content") - checkWholeText(text, "new content") - checkWholeText(text1, "cab") - confirm(len(elem.childNodes) == 5) - - doc, elem, text1, splitter, text2 = setup() - text = text1.replaceWholeText("") - checkWholeText(text2, "d") - confirm(text is None - and len(elem.childNodes) == 2) - -def testSchemaType(): - doc = parseString( - "\n" - " \n" - " \n" - "]>") - elem = doc.documentElement - # We don't want to rely on any specific loader at this point, so - # just make sure we can get to all the names, and that the - # DTD-based namespace is right. The names can vary by loader - # since each supports a different level of DTD information. - t = elem.schemaType - confirm(t.name is None - and t.namespace == xml.dom.EMPTY_NAMESPACE) - names = "id notid text enum ref refs ent ents nm nms".split() - for name in names: - a = elem.getAttributeNode(name) - t = a.schemaType - confirm(hasattr(t, "name") + # We don't want to rely on any specific loader at this point, so + # just make sure we can get to all the names, and that the + # DTD-based namespace is right. The names can vary by loader + # since each supports a different level of DTD information. + t = elem.schemaType + self.confirm(t.name is None and t.namespace == xml.dom.EMPTY_NAMESPACE) - -def testSetIdAttribute(): - doc = parseString("") - e = doc.documentElement - a1 = e.getAttributeNode("a1") - a2 = e.getAttributeNode("a2") - confirm(doc.getElementById("v") is None - and not a1.isId - and not a2.isId) - e.setIdAttribute("a1") - confirm(e.isSameNode(doc.getElementById("v")) - and a1.isId - and not a2.isId) - e.setIdAttribute("a2") - confirm(e.isSameNode(doc.getElementById("v")) - and e.isSameNode(doc.getElementById("w")) - and a1.isId - and a2.isId) - # replace the a1 node; the new node should *not* be an ID - a3 = doc.createAttribute("a1") - a3.value = "v" - e.setAttributeNode(a3) - confirm(doc.getElementById("v") is None - and e.isSameNode(doc.getElementById("w")) - and not a1.isId - and a2.isId - and not a3.isId) - # renaming an attribute should not affect its ID-ness: - doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an") - confirm(e.isSameNode(doc.getElementById("w")) - and a2.isId) - -def testSetIdAttributeNS(): - NS1 = "http://xml.python.org/ns1" - NS2 = "http://xml.python.org/ns2" - doc = parseString("") - e = doc.documentElement - a1 = e.getAttributeNodeNS(NS1, "a1") - a2 = e.getAttributeNodeNS(NS2, "a2") - confirm(doc.getElementById("v") is None - and not a1.isId - and not a2.isId) - e.setIdAttributeNS(NS1, "a1") - confirm(e.isSameNode(doc.getElementById("v")) - and a1.isId - and not a2.isId) - e.setIdAttributeNS(NS2, "a2") - confirm(e.isSameNode(doc.getElementById("v")) - and e.isSameNode(doc.getElementById("w")) - and a1.isId - and a2.isId) - # replace the a1 node; the new node should *not* be an ID - a3 = doc.createAttributeNS(NS1, "a1") - a3.value = "v" - e.setAttributeNode(a3) - confirm(e.isSameNode(doc.getElementById("w"))) - confirm(not a1.isId) - confirm(a2.isId) - confirm(not a3.isId) - confirm(doc.getElementById("v") is None) - # renaming an attribute should not affect its ID-ness: - doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an") - confirm(e.isSameNode(doc.getElementById("w")) - and a2.isId) - -def testSetIdAttributeNode(): - NS1 = "http://xml.python.org/ns1" - NS2 = "http://xml.python.org/ns2" - doc = parseString("") - e = doc.documentElement - a1 = e.getAttributeNodeNS(NS1, "a1") - a2 = e.getAttributeNodeNS(NS2, "a2") - confirm(doc.getElementById("v") is None - and not a1.isId - and not a2.isId) - e.setIdAttributeNode(a1) - confirm(e.isSameNode(doc.getElementById("v")) - and a1.isId - and not a2.isId) - e.setIdAttributeNode(a2) - confirm(e.isSameNode(doc.getElementById("v")) - and e.isSameNode(doc.getElementById("w")) - and a1.isId - and a2.isId) - # replace the a1 node; the new node should *not* be an ID - a3 = doc.createAttributeNS(NS1, "a1") - a3.value = "v" - e.setAttributeNode(a3) - confirm(e.isSameNode(doc.getElementById("w"))) - confirm(not a1.isId) - confirm(a2.isId) - confirm(not a3.isId) - confirm(doc.getElementById("v") is None) - # renaming an attribute should not affect its ID-ness: - doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an") - confirm(e.isSameNode(doc.getElementById("w")) - and a2.isId) - -def testPickledDocument(): - doc = parseString("\n" - "\n" - " \n" - "]> text\n" - " ") - s = pickle.dumps(doc) - doc2 = pickle.loads(s) - stack = [(doc, doc2)] - while stack: - n1, n2 = stack.pop() - confirm(n1.nodeType == n2.nodeType - and len(n1.childNodes) == len(n2.childNodes) - and n1.nodeName == n2.nodeName - and not n1.isSameNode(n2) - and not n2.isSameNode(n1)) - if n1.nodeType == Node.DOCUMENT_TYPE_NODE: - len(n1.entities) - len(n2.entities) - len(n1.notations) - len(n2.notations) - confirm(len(n1.entities) == len(n2.entities) - and len(n1.notations) == len(n2.notations)) - for i in range(len(n1.notations)): - no1 = n1.notations.item(i) - no2 = n1.notations.item(i) - confirm(no1.name == no2.name - and no1.publicId == no2.publicId - and no1.systemId == no2.systemId) - statck.append((no1, no2)) - for i in range(len(n1.entities)): - e1 = n1.entities.item(i) - e2 = n2.entities.item(i) - confirm(e1.notationName == e2.notationName - and e1.publicId == e2.publicId - and e1.systemId == e2.systemId) - stack.append((e1, e2)) - if n1.nodeType != Node.DOCUMENT_NODE: - confirm(n1.ownerDocument.isSameNode(doc) - and n2.ownerDocument.isSameNode(doc2)) - for i in range(len(n1.childNodes)): - stack.append((n1.childNodes[i], n2.childNodes[i])) - - -# --- MAIN PROGRAM - -names = globals().keys() -names.sort() - -failed = [] - -try: - Node.allnodes -except AttributeError: - # We don't actually have the minidom from the standard library, - # but are picking up the PyXML version from site-packages. - def check_allnodes(): - pass -else: - def check_allnodes(): - confirm(len(Node.allnodes) == 0, - "assertion: len(Node.allnodes) == 0") - if len(Node.allnodes): - print "Garbage left over:" - if verbose: - print Node.allnodes.items()[0:10] - else: - # Don't print specific nodes if repeatable results - # are needed - print len(Node.allnodes) - Node.allnodes = {} - -for name in names: - if name.startswith("test"): - func = globals()[name] - try: - func() - check_allnodes() - except: - failed.append(name) - print "Test Failed: ", name - sys.stdout.flush() - traceback.print_exception(*sys.exc_info()) - print repr(sys.exc_info()[1]) - Node.allnodes = {} - -if failed: - print "\n\n\n**** Check for failures in these tests:" - for name in failed: - print " " + name + names = "id notid text enum ref refs ent ents nm nms".split() + for name in names: + a = elem.getAttributeNode(name) + t = a.schemaType + self.confirm(hasattr(t, "name") + and t.namespace == xml.dom.EMPTY_NAMESPACE) + + def testSetIdAttribute(self): + doc = parseString("") + e = doc.documentElement + a1 = e.getAttributeNode("a1") + a2 = e.getAttributeNode("a2") + self.confirm(doc.getElementById("v") is None + and not a1.isId + and not a2.isId) + e.setIdAttribute("a1") + self.confirm(e.isSameNode(doc.getElementById("v")) + and a1.isId + and not a2.isId) + e.setIdAttribute("a2") + self.confirm(e.isSameNode(doc.getElementById("v")) + and e.isSameNode(doc.getElementById("w")) + and a1.isId + and a2.isId) + # replace the a1 node; the new node should *not* be an ID + a3 = doc.createAttribute("a1") + a3.value = "v" + e.setAttributeNode(a3) + self.confirm(doc.getElementById("v") is None + and e.isSameNode(doc.getElementById("w")) + and not a1.isId + and a2.isId + and not a3.isId) + # renaming an attribute should not affect its ID-ness: + doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an") + self.confirm(e.isSameNode(doc.getElementById("w")) + and a2.isId) + + def testSetIdAttributeNS(self): + NS1 = "http://xml.python.org/ns1" + NS2 = "http://xml.python.org/ns2" + doc = parseString("") + e = doc.documentElement + a1 = e.getAttributeNodeNS(NS1, "a1") + a2 = e.getAttributeNodeNS(NS2, "a2") + self.confirm(doc.getElementById("v") is None + and not a1.isId + and not a2.isId) + e.setIdAttributeNS(NS1, "a1") + self.confirm(e.isSameNode(doc.getElementById("v")) + and a1.isId + and not a2.isId) + e.setIdAttributeNS(NS2, "a2") + self.confirm(e.isSameNode(doc.getElementById("v")) + and e.isSameNode(doc.getElementById("w")) + and a1.isId + and a2.isId) + # replace the a1 node; the new node should *not* be an ID + a3 = doc.createAttributeNS(NS1, "a1") + a3.value = "v" + e.setAttributeNode(a3) + self.confirm(e.isSameNode(doc.getElementById("w"))) + self.confirm(not a1.isId) + self.confirm(a2.isId) + self.confirm(not a3.isId) + self.confirm(doc.getElementById("v") is None) + # renaming an attribute should not affect its ID-ness: + doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an") + self.confirm(e.isSameNode(doc.getElementById("w")) + and a2.isId) + + def testSetIdAttributeNode(self): + NS1 = "http://xml.python.org/ns1" + NS2 = "http://xml.python.org/ns2" + doc = parseString("") + e = doc.documentElement + a1 = e.getAttributeNodeNS(NS1, "a1") + a2 = e.getAttributeNodeNS(NS2, "a2") + self.confirm(doc.getElementById("v") is None + and not a1.isId + and not a2.isId) + e.setIdAttributeNode(a1) + self.confirm(e.isSameNode(doc.getElementById("v")) + and a1.isId + and not a2.isId) + e.setIdAttributeNode(a2) + self.confirm(e.isSameNode(doc.getElementById("v")) + and e.isSameNode(doc.getElementById("w")) + and a1.isId + and a2.isId) + # replace the a1 node; the new node should *not* be an ID + a3 = doc.createAttributeNS(NS1, "a1") + a3.value = "v" + e.setAttributeNode(a3) + self.confirm(e.isSameNode(doc.getElementById("w"))) + self.confirm(not a1.isId) + self.confirm(a2.isId) + self.confirm(not a3.isId) + self.confirm(doc.getElementById("v") is None) + # renaming an attribute should not affect its ID-ness: + doc.renameNode(a2, xml.dom.EMPTY_NAMESPACE, "an") + self.confirm(e.isSameNode(doc.getElementById("w")) + and a2.isId) + + def testPickledDocument(self): + doc = parseString("\n" + "\n" + " \n" + "]> text\n" + " ") + s = pickle.dumps(doc) + doc2 = pickle.loads(s) + stack = [(doc, doc2)] + while stack: + n1, n2 = stack.pop() + self.confirm(n1.nodeType == n2.nodeType + and len(n1.childNodes) == len(n2.childNodes) + and n1.nodeName == n2.nodeName + and not n1.isSameNode(n2) + and not n2.isSameNode(n1)) + if n1.nodeType == Node.DOCUMENT_TYPE_NODE: + len(n1.entities) + len(n2.entities) + len(n1.notations) + len(n2.notations) + self.confirm(len(n1.entities) == len(n2.entities) + and len(n1.notations) == len(n2.notations)) + for i in range(len(n1.notations)): + no1 = n1.notations.item(i) + no2 = n1.notations.item(i) + self.confirm(no1.name == no2.name + and no1.publicId == no2.publicId + and no1.systemId == no2.systemId) + statck.append((no1, no2)) + for i in range(len(n1.entities)): + e1 = n1.entities.item(i) + e2 = n2.entities.item(i) + self.confirm(e1.notationName == e2.notationName + and e1.publicId == e2.publicId + and e1.systemId == e2.systemId) + stack.append((e1, e2)) + if n1.nodeType != Node.DOCUMENT_NODE: + self.confirm(n1.ownerDocument.isSameNode(doc) + and n2.ownerDocument.isSameNode(doc2)) + for i in range(len(n1.childNodes)): + stack.append((n1.childNodes[i], n2.childNodes[i])) + +def test_main(): + run_unittest(MinidomTest) + +if __name__ == "__main__": + test_main() Modified: python/trunk/Lib/test/test_pyexpat.py ============================================================================== --- python/trunk/Lib/test/test_pyexpat.py (original) +++ python/trunk/Lib/test/test_pyexpat.py Thu Mar 29 01:34:06 2007 @@ -1,108 +1,40 @@ -# Very simple test - Parse a file and print what happens - # XXX TypeErrors on calling handlers, or on bad return values from a # handler, are obscure and unhelpful. +import StringIO +import unittest + import pyexpat from xml.parsers import expat -from test.test_support import sortdict, TestFailed +from test.test_support import sortdict, run_unittest -class Outputter: - def StartElementHandler(self, name, attrs): - print 'Start element:\n\t', repr(name), sortdict(attrs) - def EndElementHandler(self, name): - print 'End element:\n\t', repr(name) +class SetAttributeTest(unittest.TestCase): + def setUp(self): + self.parser = expat.ParserCreate(namespace_separator='!') + self.set_get_pairs = [ + [0, 0], + [1, 1], + [2, 1], + [0, 0], + ] + + def test_returns_unicode(self): + for x, y in self.set_get_pairs: + self.parser.returns_unicode = x + self.assertEquals(self.parser.returns_unicode, y) + + def test_ordered_attributes(self): + for x, y in self.set_get_pairs: + self.parser.ordered_attributes = x + self.assertEquals(self.parser.ordered_attributes, y) + + def test_specified_attributes(self): + for x, y in self.set_get_pairs: + self.parser.specified_attributes = x + self.assertEquals(self.parser.specified_attributes, y) - def CharacterDataHandler(self, data): - data = data.strip() - if data: - print 'Character data:' - print '\t', repr(data) - - def ProcessingInstructionHandler(self, target, data): - print 'PI:\n\t', repr(target), repr(data) - - def StartNamespaceDeclHandler(self, prefix, uri): - print 'NS decl:\n\t', repr(prefix), repr(uri) - - def EndNamespaceDeclHandler(self, prefix): - print 'End of NS decl:\n\t', repr(prefix) - - def StartCdataSectionHandler(self): - print 'Start of CDATA section' - - def EndCdataSectionHandler(self): - print 'End of CDATA section' - - def CommentHandler(self, text): - print 'Comment:\n\t', repr(text) - - def NotationDeclHandler(self, *args): - name, base, sysid, pubid = args - print 'Notation declared:', args - - def UnparsedEntityDeclHandler(self, *args): - entityName, base, systemId, publicId, notationName = args - print 'Unparsed entity decl:\n\t', args - - def NotStandaloneHandler(self, userData): - print 'Not standalone' - return 1 - - def ExternalEntityRefHandler(self, *args): - context, base, sysId, pubId = args - print 'External entity ref:', args[1:] - return 1 - - def DefaultHandler(self, userData): - pass - - def DefaultHandlerExpand(self, userData): - pass - - -def confirm(ok): - if ok: - print "OK." - else: - print "Not OK." - -out = Outputter() -parser = expat.ParserCreate(namespace_separator='!') - -# Test getting/setting returns_unicode -parser.returns_unicode = 0; confirm(parser.returns_unicode == 0) -parser.returns_unicode = 1; confirm(parser.returns_unicode == 1) -parser.returns_unicode = 2; confirm(parser.returns_unicode == 1) -parser.returns_unicode = 0; confirm(parser.returns_unicode == 0) - -# Test getting/setting ordered_attributes -parser.ordered_attributes = 0; confirm(parser.ordered_attributes == 0) -parser.ordered_attributes = 1; confirm(parser.ordered_attributes == 1) -parser.ordered_attributes = 2; confirm(parser.ordered_attributes == 1) -parser.ordered_attributes = 0; confirm(parser.ordered_attributes == 0) - -# Test getting/setting specified_attributes -parser.specified_attributes = 0; confirm(parser.specified_attributes == 0) -parser.specified_attributes = 1; confirm(parser.specified_attributes == 1) -parser.specified_attributes = 2; confirm(parser.specified_attributes == 1) -parser.specified_attributes = 0; confirm(parser.specified_attributes == 0) - -HANDLER_NAMES = [ - 'StartElementHandler', 'EndElementHandler', - 'CharacterDataHandler', 'ProcessingInstructionHandler', - 'UnparsedEntityDeclHandler', 'NotationDeclHandler', - 'StartNamespaceDeclHandler', 'EndNamespaceDeclHandler', - 'CommentHandler', 'StartCdataSectionHandler', - 'EndCdataSectionHandler', - 'DefaultHandler', 'DefaultHandlerExpand', - #'NotStandaloneHandler', - 'ExternalEntityRefHandler' - ] -for name in HANDLER_NAMES: - setattr(parser, name, getattr(out, name)) data = '''\ @@ -126,108 +58,228 @@ ''' -# Produce UTF-8 output -parser.returns_unicode = 0 -try: - parser.Parse(data, 1) -except expat.error: - print '** Error', parser.ErrorCode, expat.ErrorString(parser.ErrorCode) - print '** Line', parser.ErrorLineNumber - print '** Column', parser.ErrorColumnNumber - print '** Byte', parser.ErrorByteIndex - -# Try the parse again, this time producing Unicode output -parser = expat.ParserCreate(namespace_separator='!') -parser.returns_unicode = 1 - -for name in HANDLER_NAMES: - setattr(parser, name, getattr(out, name)) -try: - parser.Parse(data, 1) -except expat.error: - print '** Error', parser.ErrorCode, expat.ErrorString(parser.ErrorCode) - print '** Line', parser.ErrorLineNumber - print '** Column', parser.ErrorColumnNumber - print '** Byte', parser.ErrorByteIndex - -# Try parsing a file -parser = expat.ParserCreate(namespace_separator='!') -parser.returns_unicode = 1 -for name in HANDLER_NAMES: - setattr(parser, name, getattr(out, name)) -import StringIO -file = StringIO.StringIO(data) -try: - parser.ParseFile(file) -except expat.error: - print '** Error', parser.ErrorCode, expat.ErrorString(parser.ErrorCode) - print '** Line', parser.ErrorLineNumber - print '** Column', parser.ErrorColumnNumber - print '** Byte', parser.ErrorByteIndex - - -# Tests that make sure we get errors when the namespace_separator value -# is illegal, and that we don't for good values: -print -print "Testing constructor for proper handling of namespace_separator values:" -expat.ParserCreate() -expat.ParserCreate(namespace_separator=None) -expat.ParserCreate(namespace_separator=' ') -print "Legal values tested o.k." -try: - expat.ParserCreate(namespace_separator=42) -except TypeError, e: - print "Caught expected TypeError:" - print e -else: - print "Failed to catch expected TypeError." - -try: - expat.ParserCreate(namespace_separator='too long') -except ValueError, e: - print "Caught expected ValueError:" - print e -else: - print "Failed to catch expected ValueError." - -# ParserCreate() needs to accept a namespace_separator of zero length -# to satisfy the requirements of RDF applications that are required -# to simply glue together the namespace URI and the localname. Though -# considered a wart of the RDF specifications, it needs to be supported. -# -# See XML-SIG mailing list thread starting with -# http://mail.python.org/pipermail/xml-sig/2001-April/005202.html -# -expat.ParserCreate(namespace_separator='') # too short - -# Test the interning machinery. -p = expat.ParserCreate() -L = [] -def collector(name, *args): - L.append(name) -p.StartElementHandler = collector -p.EndElementHandler = collector -p.Parse(" ", 1) -tag = L[0] -if len(L) != 6: - print "L should only contain 6 entries; found", len(L) -for entry in L: - if tag is not entry: - print "expected L to contain many references to the same string", - print "(it didn't)" - print "L =", repr(L) - break +# Produce UTF-8 output +class ParseTest(unittest.TestCase): + class Outputter: + def __init__(self): + self.out = [] + + def StartElementHandler(self, name, attrs): + self.out.append('Start element: ' + repr(name) + ' ' + + sortdict(attrs)) + + def EndElementHandler(self, name): + self.out.append('End element: ' + repr(name)) + + def CharacterDataHandler(self, data): + data = data.strip() + if data: + self.out.append('Character data: ' + repr(data)) + + def ProcessingInstructionHandler(self, target, data): + self.out.append('PI: ' + repr(target) + ' ' + repr(data)) + + def StartNamespaceDeclHandler(self, prefix, uri): + self.out.append('NS decl: ' + repr(prefix) + ' ' + repr(uri)) + + def EndNamespaceDeclHandler(self, prefix): + self.out.append('End of NS decl: ' + repr(prefix)) + + def StartCdataSectionHandler(self): + self.out.append('Start of CDATA section') + + def EndCdataSectionHandler(self): + self.out.append('End of CDATA section') + + def CommentHandler(self, text): + self.out.append('Comment: ' + repr(text)) + + def NotationDeclHandler(self, *args): + name, base, sysid, pubid = args + self.out.append('Notation declared: %s' %(args,)) + + def UnparsedEntityDeclHandler(self, *args): + entityName, base, systemId, publicId, notationName = args + self.out.append('Unparsed entity decl: %s' %(args,)) + + def NotStandaloneHandler(self, userData): + self.out.append('Not standalone') + return 1 + + def ExternalEntityRefHandler(self, *args): + context, base, sysId, pubId = args + self.out.append('External entity ref: %s' %(args[1:],)) + return 1 + + def DefaultHandler(self, userData): + pass + + def DefaultHandlerExpand(self, userData): + pass + + handler_names = [ + 'StartElementHandler', 'EndElementHandler', + 'CharacterDataHandler', 'ProcessingInstructionHandler', + 'UnparsedEntityDeclHandler', 'NotationDeclHandler', + 'StartNamespaceDeclHandler', 'EndNamespaceDeclHandler', + 'CommentHandler', 'StartCdataSectionHandler', + 'EndCdataSectionHandler', + 'DefaultHandler', 'DefaultHandlerExpand', + #'NotStandaloneHandler', + 'ExternalEntityRefHandler' + ] + + def test_utf8(self): + + out = self.Outputter() + parser = expat.ParserCreate(namespace_separator='!') + for name in self.handler_names: + setattr(parser, name, getattr(out, name)) + parser.returns_unicode = 0 + parser.Parse(data, 1) + + # Verify output + op = out.out + self.assertEquals(op[0], 'PI: \'xml-stylesheet\' \'href="stylesheet.css"\'') + self.assertEquals(op[1], "Comment: ' comment data '") + self.assertEquals(op[2], "Notation declared: ('notation', None, 'notation.jpeg', None)") + self.assertEquals(op[3], "Unparsed entity decl: ('unparsed_entity', None, 'entity.file', None, 'notation')") + self.assertEquals(op[4], "Start element: 'root' {'attr1': 'value1', 'attr2': 'value2\\xe1\\xbd\\x80'}") + self.assertEquals(op[5], "NS decl: 'myns' 'http://www.python.org/namespace'") + self.assertEquals(op[6], "Start element: 'http://www.python.org/namespace!subelement' {}") + self.assertEquals(op[7], "Character data: 'Contents of subelements'") + self.assertEquals(op[8], "End element: 'http://www.python.org/namespace!subelement'") + self.assertEquals(op[9], "End of NS decl: 'myns'") + self.assertEquals(op[10], "Start element: 'sub2' {}") + self.assertEquals(op[11], 'Start of CDATA section') + self.assertEquals(op[12], "Character data: 'contents of CDATA section'") + self.assertEquals(op[13], 'End of CDATA section') + self.assertEquals(op[14], "End element: 'sub2'") + self.assertEquals(op[15], "External entity ref: (None, 'entity.file', None)") + self.assertEquals(op[16], "End element: 'root'") + + def test_unicode(self): + # Try the parse again, this time producing Unicode output + out = self.Outputter() + parser = expat.ParserCreate(namespace_separator='!') + parser.returns_unicode = 1 + for name in self.handler_names: + setattr(parser, name, getattr(out, name)) + + parser.Parse(data, 1) + + op = out.out + self.assertEquals(op[0], 'PI: u\'xml-stylesheet\' u\'href="stylesheet.css"\'') + self.assertEquals(op[1], "Comment: u' comment data '") + self.assertEquals(op[2], "Notation declared: (u'notation', None, u'notation.jpeg', None)") + self.assertEquals(op[3], "Unparsed entity decl: (u'unparsed_entity', None, u'entity.file', None, u'notation')") + self.assertEquals(op[4], "Start element: u'root' {u'attr1': u'value1', u'attr2': u'value2\\u1f40'}") + self.assertEquals(op[5], "NS decl: u'myns' u'http://www.python.org/namespace'") + self.assertEquals(op[6], "Start element: u'http://www.python.org/namespace!subelement' {}") + self.assertEquals(op[7], "Character data: u'Contents of subelements'") + self.assertEquals(op[8], "End element: u'http://www.python.org/namespace!subelement'") + self.assertEquals(op[9], "End of NS decl: u'myns'") + self.assertEquals(op[10], "Start element: u'sub2' {}") + self.assertEquals(op[11], 'Start of CDATA section') + self.assertEquals(op[12], "Character data: u'contents of CDATA section'") + self.assertEquals(op[13], 'End of CDATA section') + self.assertEquals(op[14], "End element: u'sub2'") + self.assertEquals(op[15], "External entity ref: (None, u'entity.file', None)") + self.assertEquals(op[16], "End element: u'root'") + + def test_parse_file(self): + # Try parsing a file + out = self.Outputter() + parser = expat.ParserCreate(namespace_separator='!') + parser.returns_unicode = 1 + for name in self.handler_names: + setattr(parser, name, getattr(out, name)) + file = StringIO.StringIO(data) + + parser.ParseFile(file) + + op = out.out + self.assertEquals(op[0], 'PI: u\'xml-stylesheet\' u\'href="stylesheet.css"\'') + self.assertEquals(op[1], "Comment: u' comment data '") + self.assertEquals(op[2], "Notation declared: (u'notation', None, u'notation.jpeg', None)") + self.assertEquals(op[3], "Unparsed entity decl: (u'unparsed_entity', None, u'entity.file', None, u'notation')") + self.assertEquals(op[4], "Start element: u'root' {u'attr1': u'value1', u'attr2': u'value2\\u1f40'}") + self.assertEquals(op[5], "NS decl: u'myns' u'http://www.python.org/namespace'") + self.assertEquals(op[6], "Start element: u'http://www.python.org/namespace!subelement' {}") + self.assertEquals(op[7], "Character data: u'Contents of subelements'") + self.assertEquals(op[8], "End element: u'http://www.python.org/namespace!subelement'") + self.assertEquals(op[9], "End of NS decl: u'myns'") + self.assertEquals(op[10], "Start element: u'sub2' {}") + self.assertEquals(op[11], 'Start of CDATA section') + self.assertEquals(op[12], "Character data: u'contents of CDATA section'") + self.assertEquals(op[13], 'End of CDATA section') + self.assertEquals(op[14], "End element: u'sub2'") + self.assertEquals(op[15], "External entity ref: (None, u'entity.file', None)") + self.assertEquals(op[16], "End element: u'root'") + + +class NamespaceSeparatorTest(unittest.TestCase): + def test_legal(self): + # Tests that make sure we get errors when the namespace_separator value + # is illegal, and that we don't for good values: + expat.ParserCreate() + expat.ParserCreate(namespace_separator=None) + expat.ParserCreate(namespace_separator=' ') + + def test_illegal(self): + try: + expat.ParserCreate(namespace_separator=42) + self.fail() + except TypeError, e: + self.assertEquals(str(e), + 'ParserCreate() argument 2 must be string or None, not int') + + try: + expat.ParserCreate(namespace_separator='too long') + self.fail() + except ValueError, e: + self.assertEquals(str(e), + 'namespace_separator must be at most one character, omitted, or None') + + def test_zero_length(self): + # ParserCreate() needs to accept a namespace_separator of zero length + # to satisfy the requirements of RDF applications that are required + # to simply glue together the namespace URI and the localname. Though + # considered a wart of the RDF specifications, it needs to be supported. + # + # See XML-SIG mailing list thread starting with + # http://mail.python.org/pipermail/xml-sig/2001-April/005202.html + # + expat.ParserCreate(namespace_separator='') # too short + + +class InterningTest(unittest.TestCase): + def test(self): + # Test the interning machinery. + p = expat.ParserCreate() + L = [] + def collector(name, *args): + L.append(name) + p.StartElementHandler = collector + p.EndElementHandler = collector + p.Parse(" ", 1) + tag = L[0] + self.assertEquals(len(L), 6) + for entry in L: + # L should have the same string repeated over and over. + self.assertTrue(tag is entry) -# Tests of the buffer_text attribute. -import sys -class TextCollector: - def __init__(self, parser): +class BufferTextTest(unittest.TestCase): + def setUp(self): self.stuff = [] - + self.parser = expat.ParserCreate() + self.parser.buffer_text = 1 + self.parser.CharacterDataHandler = self.CharacterDataHandler + def check(self, expected, label): - require(self.stuff == expected, + self.assertEquals(self.stuff, expected, "%s\nstuff = %r\nexpected = %r" % (label, self.stuff, map(unicode, expected))) @@ -238,9 +290,9 @@ self.stuff.append("<%s>" % name) bt = attrs.get("buffer-text") if bt == "yes": - parser.buffer_text = 1 + self.parser.buffer_text = 1 elif bt == "no": - parser.buffer_text = 0 + self.parser.buffer_text = 0 def EndElementHandler(self, name): self.stuff.append("" % name) @@ -248,95 +300,91 @@ def CommentHandler(self, data): self.stuff.append("" % data) -def require(cond, label): - # similar to confirm(), but no extraneous output - if not cond: - raise TestFailed(label) - -def setup(handlers=[]): - parser = expat.ParserCreate() - require(not parser.buffer_text, - "buffer_text not disabled by default") - parser.buffer_text = 1 - handler = TextCollector(parser) - parser.CharacterDataHandler = handler.CharacterDataHandler - for name in handlers: - setattr(parser, name, getattr(handler, name)) - return parser, handler - -parser, handler = setup() -require(parser.buffer_text, - "text buffering either not acknowledged or not enabled") -parser.Parse("123", 1) -handler.check(["123"], - "buffered text not properly collapsed") - -# XXX This test exposes more detail of Expat's text chunking than we -# XXX like, but it tests what we need to concisely. -parser, handler = setup(["StartElementHandler"]) -parser.Parse("12\n34\n5", 1) -handler.check(["", "1", "", "2", "\n", "3", "", "4\n5"], - "buffering control not reacting as expected") - -parser, handler = setup() -parser.Parse("1<2> \n 3", 1) -handler.check(["1<2> \n 3"], - "buffered text not properly collapsed") - -parser, handler = setup(["StartElementHandler"]) -parser.Parse("123", 1) -handler.check(["", "1", "", "2", "", "3"], - "buffered text not properly split") - -parser, handler = setup(["StartElementHandler", "EndElementHandler"]) -parser.CharacterDataHandler = None -parser.Parse("123", 1) -handler.check(["", "", "", "", "", ""], - "huh?") - -parser, handler = setup(["StartElementHandler", "EndElementHandler"]) -parser.Parse("123", 1) -handler.check(["", "1", "", "", "2", "", "", "3", ""], - "huh?") - -parser, handler = setup(["CommentHandler", "EndElementHandler", - "StartElementHandler"]) -parser.Parse("12345 ", 1) -handler.check(["", "1", "", "", "2", "", "", "345", ""], - "buffered text not properly split") - -parser, handler = setup(["CommentHandler", "EndElementHandler", - "StartElementHandler"]) -parser.Parse("12345 ", 1) -handler.check(["", "1", "", "", "2", "", "", "3", - "", "4", "", "5", ""], - "buffered text not properly split") + def setHandlers(self, handlers=[]): + for name in handlers: + setattr(self.parser, name, getattr(self, name)) + + def test_default_to_disabled(self): + parser = expat.ParserCreate() + self.assertFalse(parser.buffer_text) + + def test_buffering_enabled(self): + # Make sure buffering is turned on + self.assertTrue(self.parser.buffer_text) + self.parser.Parse("123", 1) + self.assertEquals(self.stuff, ['123'], + "buffered text not properly collapsed") + + def test1(self): + # XXX This test exposes more detail of Expat's text chunking than we + # XXX like, but it tests what we need to concisely. + self.setHandlers(["StartElementHandler"]) + self.parser.Parse("12\n34\n5", 1) + self.assertEquals(self.stuff, + ["", "1", "", "2", "\n", "3", "", "4\n5"], + "buffering control not reacting as expected") + + def test2(self): + self.parser.Parse("1<2> \n 3", 1) + self.assertEquals(self.stuff, ["1<2> \n 3"], + "buffered text not properly collapsed") + + def test3(self): + self.setHandlers(["StartElementHandler"]) + self.parser.Parse("123", 1) + self.assertEquals(self.stuff, ["", "1", "", "2", "", "3"], + "buffered text not properly split") + + def test4(self): + self.setHandlers(["StartElementHandler", "EndElementHandler"]) + self.parser.CharacterDataHandler = None + self.parser.Parse("123", 1) + self.assertEquals(self.stuff, + ["", "", "", "", "", ""]) + + def test5(self): + self.setHandlers(["StartElementHandler", "EndElementHandler"]) + self.parser.Parse("123", 1) + self.assertEquals(self.stuff, + ["", "1", "", "", "2", "", "", "3", ""]) + + def test6(self): + self.setHandlers(["CommentHandler", "EndElementHandler", + "StartElementHandler"]) + self.parser.Parse("12345 ", 1) + self.assertEquals(self.stuff, + ["", "1", "", "", "2", "", "", "345", ""], + "buffered text not properly split") + + def test7(self): + self.setHandlers(["CommentHandler", "EndElementHandler", + "StartElementHandler"]) + self.parser.Parse("12345 ", 1) + self.assertEquals(self.stuff, + ["", "1", "", "", "2", "", "", "3", + "", "4", "", "5", ""], + "buffered text not properly split") + # Test handling of exception from callback: -def StartElementHandler(name, attrs): - raise RuntimeError(name) +class HandlerExceptionTest(unittest.TestCase): + def StartElementHandler(self, name, attrs): + raise RuntimeError(name) -parser = expat.ParserCreate() -parser.StartElementHandler = StartElementHandler + def test(self): + parser = expat.ParserCreate() + parser.StartElementHandler = self.StartElementHandler + try: + parser.Parse("", 1) + self.fail() + except RuntimeError, e: + self.assertEquals(e.args[0], 'a', + "Expected RuntimeError for element 'a', but" + \ + " found %r" % e.args[0]) -try: - parser.Parse("", 1) -except RuntimeError, e: - if e.args[0] != "a": - print "Expected RuntimeError for element 'a'; found %r" % e.args[0] -else: - print "Expected RuntimeError for 'a'" # Test Current* members: -class PositionTest: - - def __init__(self, expected_list, parser): - self.parser = parser - self.parser.StartElementHandler = self.StartElementHandler - self.parser.EndElementHandler = self.EndElementHandler - self.expected_list = expected_list - self.upto = 0 - +class PositionTest(unittest.TestCase): def StartElementHandler(self, name, attrs): self.check_pos('s') @@ -348,41 +396,54 @@ self.parser.CurrentByteIndex, self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber) - require(self.upto < len(self.expected_list), - 'too many parser events') + self.assertTrue(self.upto < len(self.expected_list), + 'too many parser events') expected = self.expected_list[self.upto] - require(pos == expected, - 'expected position %s, got %s' % (expected, pos)) + self.assertEquals(pos, expected, + 'Expected position %s, got position %s' %(pos, expected)) self.upto += 1 + def test(self): + self.parser = expat.ParserCreate() + self.parser.StartElementHandler = self.StartElementHandler + self.parser.EndElementHandler = self.EndElementHandler + self.upto = 0 + self.expected_list = [('s', 0, 1, 0), ('s', 5, 2, 1), ('s', 11, 3, 2), + ('e', 15, 3, 6), ('e', 17, 4, 1), ('e', 22, 5, 0)] + + xml = '\n \n \n \n' + self.parser.Parse(xml, 1) + -parser = expat.ParserCreate() -handler = PositionTest([('s', 0, 1, 0), ('s', 5, 2, 1), ('s', 11, 3, 2), - ('e', 15, 3, 6), ('e', 17, 4, 1), ('e', 22, 5, 0)], - parser) -parser.Parse(''' - - - -''', 1) - - -def test_parse_only_xml_data(): - # http://python.org/sf/1296433 - # - xml = "%s" % ('a' * 1025) - # this one doesn't crash - #xml = "%s" % ('a' * 10000) - - def handler(text): - raise Exception - - parser = expat.ParserCreate() - parser.CharacterDataHandler = handler - - try: - parser.Parse(xml) - except: - pass +class sf1296433Test(unittest.TestCase): + def test_parse_only_xml_data(self): + # http://python.org/sf/1296433 + # + xml = "%s" % ('a' * 1025) + # this one doesn't crash + #xml = "%s" % ('a' * 10000) + + class SpecificException(Exception): + pass + + def handler(text): + raise SpecificException + + parser = expat.ParserCreate() + parser.CharacterDataHandler = handler + + self.assertRaises(Exception, parser.Parse, xml) + + +def test_main(): + run_unittest(SetAttributeTest, + ParseTest, + NamespaceSeparatorTest, + InterningTest, + BufferTextTest, + HandlerExceptionTest, + PositionTest, + sf1296433Test) -test_parse_only_xml_data() +if __name__ == "__main__": + test_main() Modified: python/trunk/Lib/test/test_sax.py ============================================================================== --- python/trunk/Lib/test/test_sax.py (original) +++ python/trunk/Lib/test/test_sax.py Thu Mar 29 01:34:06 2007 @@ -13,26 +13,66 @@ from xml.sax.expatreader import create_parser from xml.sax.xmlreader import InputSource, AttributesImpl, AttributesNSImpl from cStringIO import StringIO -from test.test_support import verify, verbose, TestFailed, findfile +from test.test_support import findfile, run_unittest +import unittest import os -# ===== Utilities - -tests = 0 -failures = [] - -def confirm(outcome, name): - global tests - - tests = tests + 1 - if outcome: - if verbose: - print "Passed", name - else: - failures.append(name) +ns_uri = "http://www.python.org/xml-ns/saxtest/" -def test_make_parser2(): - try: +class XmlTestBase(unittest.TestCase): + def verify_empty_attrs(self, attrs): + self.assertRaises(KeyError, attrs.getValue, "attr") + self.assertRaises(KeyError, attrs.getValueByQName, "attr") + self.assertRaises(KeyError, attrs.getNameByQName, "attr") + self.assertRaises(KeyError, attrs.getQNameByName, "attr") + self.assertRaises(KeyError, attrs.__getitem__, "attr") + self.assertEquals(attrs.getLength(), 0) + self.assertEquals(attrs.getNames(), []) + self.assertEquals(attrs.getQNames(), []) + self.assertEquals(len(attrs), 0) + self.assertFalse(attrs.has_key("attr")) + self.assertEquals(attrs.keys(), []) + self.assertEquals(attrs.get("attrs"), None) + self.assertEquals(attrs.get("attrs", 25), 25) + self.assertEquals(attrs.items(), []) + self.assertEquals(attrs.values(), []) + + def verify_empty_nsattrs(self, attrs): + self.assertRaises(KeyError, attrs.getValue, (ns_uri, "attr")) + self.assertRaises(KeyError, attrs.getValueByQName, "ns:attr") + self.assertRaises(KeyError, attrs.getNameByQName, "ns:attr") + self.assertRaises(KeyError, attrs.getQNameByName, (ns_uri, "attr")) + self.assertRaises(KeyError, attrs.__getitem__, (ns_uri, "attr")) + self.assertEquals(attrs.getLength(), 0) + self.assertEquals(attrs.getNames(), []) + self.assertEquals(attrs.getQNames(), []) + self.assertEquals(len(attrs), 0) + self.assertFalse(attrs.has_key((ns_uri, "attr"))) + self.assertEquals(attrs.keys(), []) + self.assertEquals(attrs.get((ns_uri, "attr")), None) + self.assertEquals(attrs.get((ns_uri, "attr"), 25), 25) + self.assertEquals(attrs.items(), []) + self.assertEquals(attrs.values(), []) + + def verify_attrs_wattr(self, attrs): + self.assertEquals(attrs.getLength(), 1) + self.assertEquals(attrs.getNames(), ["attr"]) + self.assertEquals(attrs.getQNames(), ["attr"]) + self.assertEquals(len(attrs), 1) + self.assertTrue(attrs.has_key("attr")) + self.assertEquals(attrs.keys(), ["attr"]) + self.assertEquals(attrs.get("attr"), "val") + self.assertEquals(attrs.get("attr", 25), "val") + self.assertEquals(attrs.items(), [("attr", "val")]) + self.assertEquals(attrs.values(), ["val"]) + self.assertEquals(attrs.getValue("attr"), "val") + self.assertEquals(attrs.getValueByQName("attr"), "val") + self.assertEquals(attrs.getNameByQName("attr"), "attr") + self.assertEquals(attrs["attr"], "val") + self.assertEquals(attrs.getQNameByName("attr"), "attr") + +class MakeParserTest(unittest.TestCase): + def test_make_parser2(self): # Creating parsers several times in a row should succeed. # Testing this because there have been failures of this kind # before. @@ -48,10 +88,6 @@ p = make_parser() from xml.sax import make_parser p = make_parser() - except: - return 0 - else: - return p # =========================================================================== @@ -60,215 +96,214 @@ # # =========================================================================== -# ===== escape - -def test_escape_basic(): - return escape("Donald Duck & Co") == "Donald Duck & Co" - -def test_escape_all(): - return escape("") == "<Donald Duck & Co>" - -def test_escape_extra(): - return escape("Hei p? deg", {"?" : "å"}) == "Hei på deg" - -# ===== unescape - -def test_unescape_basic(): - return unescape("Donald Duck & Co") == "Donald Duck & Co" - -def test_unescape_all(): - return unescape("<Donald Duck & Co>") == "" - -def test_unescape_extra(): - return unescape("Hei p? deg", {"?" : "å"}) == "Hei på deg" - -def test_unescape_amp_extra(): - return unescape("&foo;", {"&foo;": "splat"}) == "&foo;" - -# ===== quoteattr - -def test_quoteattr_basic(): - return quoteattr("Donald Duck & Co") == '"Donald Duck & Co"' - -def test_single_quoteattr(): - return (quoteattr('Includes "double" quotes') - == '\'Includes "double" quotes\'') - -def test_double_quoteattr(): - return (quoteattr("Includes 'single' quotes") - == "\"Includes 'single' quotes\"") - -def test_single_double_quoteattr(): - return (quoteattr("Includes 'single' and \"double\" quotes") - == "\"Includes 'single' and "double" quotes\"") - -# ===== make_parser - -def test_make_parser(): - try: +class SaxutilsTest(unittest.TestCase): + # ===== escape + def test_escape_basic(self): + self.assertEquals(escape("Donald Duck & Co"), "Donald Duck & Co") + + def test_escape_all(self): + self.assertEquals(escape(""), + "<Donald Duck & Co>") + + def test_escape_extra(self): + self.assertEquals(escape("Hei p? deg", {"?" : "å"}), + "Hei på deg") + + # ===== unescape + def test_unescape_basic(self): + self.assertEquals(unescape("Donald Duck & Co"), "Donald Duck & Co") + + def test_unescape_all(self): + self.assertEquals(unescape("<Donald Duck & Co>"), + "") + + def test_unescape_extra(self): + self.assertEquals(unescape("Hei p? deg", {"?" : "å"}), + "Hei på deg") + + def test_unescape_amp_extra(self): + self.assertEquals(unescape("&foo;", {"&foo;": "splat"}), "&foo;") + + # ===== quoteattr + def test_quoteattr_basic(self): + self.assertEquals(quoteattr("Donald Duck & Co"), + '"Donald Duck & Co"') + + def test_single_quoteattr(self): + self.assertEquals(quoteattr('Includes "double" quotes'), + '\'Includes "double" quotes\'') + + def test_double_quoteattr(self): + self.assertEquals(quoteattr("Includes 'single' quotes"), + "\"Includes 'single' quotes\"") + + def test_single_double_quoteattr(self): + self.assertEquals(quoteattr("Includes 'single' and \"double\" quotes"), + "\"Includes 'single' and "double" quotes\"") + + # ===== make_parser + def test_make_parser(self): # Creating a parser should succeed - it should fall back # to the expatreader p = make_parser(['xml.parsers.no_such_parser']) - except: - return 0 - else: - return p # ===== XMLGenerator start = '\n' -def test_xmlgen_basic(): - result = StringIO() - gen = XMLGenerator(result) - gen.startDocument() - gen.startElement("doc", {}) - gen.endElement("doc") - gen.endDocument() - - return result.getvalue() == start + "" - -def test_xmlgen_content(): - result = StringIO() - gen = XMLGenerator(result) - - gen.startDocument() - gen.startElement("doc", {}) - gen.characters("huhei") - gen.endElement("doc") - gen.endDocument() - - return result.getvalue() == start + "huhei" - -def test_xmlgen_pi(): - result = StringIO() - gen = XMLGenerator(result) - - gen.startDocument() - gen.processingInstruction("test", "data") - gen.startElement("doc", {}) - gen.endElement("doc") - gen.endDocument() - - return result.getvalue() == start + "" - -def test_xmlgen_content_escape(): - result = StringIO() - gen = XMLGenerator(result) - - gen.startDocument() - gen.startElement("doc", {}) - gen.characters("<huhei&" - -def test_xmlgen_attr_escape(): - result = StringIO() - gen = XMLGenerator(result) - - gen.startDocument() - gen.startElement("doc", {"a": '"'}) - gen.startElement("e", {"a": "'"}) - gen.endElement("e") - gen.startElement("e", {"a": "'\""}) - gen.endElement("e") - gen.startElement("e", {"a": "\n\r\t"}) - gen.endElement("e") - gen.endElement("doc") - gen.endDocument() - - return result.getvalue() == start + ("" - "" - "") - -def test_xmlgen_ignorable(): - result = StringIO() - gen = XMLGenerator(result) - - gen.startDocument() - gen.startElement("doc", {}) - gen.ignorableWhitespace(" ") - gen.endElement("doc") - gen.endDocument() +class XmlgenTest(unittest.TestCase): + def test_xmlgen_basic(self): + result = StringIO() + gen = XMLGenerator(result) + gen.startDocument() + gen.startElement("doc", {}) + gen.endElement("doc") + gen.endDocument() + + self.assertEquals(result.getvalue(), start + "") + + def test_xmlgen_content(self): + result = StringIO() + gen = XMLGenerator(result) + + gen.startDocument() + gen.startElement("doc", {}) + gen.characters("huhei") + gen.endElement("doc") + gen.endDocument() + + self.assertEquals(result.getvalue(), start + "huhei") + + def test_xmlgen_pi(self): + result = StringIO() + gen = XMLGenerator(result) + + gen.startDocument() + gen.processingInstruction("test", "data") + gen.startElement("doc", {}) + gen.endElement("doc") + gen.endDocument() + + self.assertEquals(result.getvalue(), start + "") + + def test_xmlgen_content_escape(self): + result = StringIO() + gen = XMLGenerator(result) + + gen.startDocument() + gen.startElement("doc", {}) + gen.characters("<huhei&") + + def test_xmlgen_attr_escape(self): + result = StringIO() + gen = XMLGenerator(result) + + gen.startDocument() + gen.startElement("doc", {"a": '"'}) + gen.startElement("e", {"a": "'"}) + gen.endElement("e") + gen.startElement("e", {"a": "'\""}) + gen.endElement("e") + gen.startElement("e", {"a": "\n\r\t"}) + gen.endElement("e") + gen.endElement("doc") + gen.endDocument() + + self.assertEquals(result.getvalue(), start + + ("" + "" + "")) + + def test_xmlgen_ignorable(self): + result = StringIO() + gen = XMLGenerator(result) + + gen.startDocument() + gen.startElement("doc", {}) + gen.ignorableWhitespace(" ") + gen.endElement("doc") + gen.endDocument() + + self.assertEquals(result.getvalue(), start + " ") + + def test_xmlgen_ns(self): + result = StringIO() + gen = XMLGenerator(result) + + gen.startDocument() + gen.startPrefixMapping("ns1", ns_uri) + gen.startElementNS((ns_uri, "doc"), "ns1:doc", {}) + # add an unqualified name + gen.startElementNS((None, "udoc"), None, {}) + gen.endElementNS((None, "udoc"), None) + gen.endElementNS((ns_uri, "doc"), "ns1:doc") + gen.endPrefixMapping("ns1") + gen.endDocument() - return result.getvalue() == start + " " - -ns_uri = "http://www.python.org/xml-ns/saxtest/" - -def test_xmlgen_ns(): - result = StringIO() - gen = XMLGenerator(result) - - gen.startDocument() - gen.startPrefixMapping("ns1", ns_uri) - gen.startElementNS((ns_uri, "doc"), "ns1:doc", {}) - # add an unqualified name - gen.startElementNS((None, "udoc"), None, {}) - gen.endElementNS((None, "udoc"), None) - gen.endElementNS((ns_uri, "doc"), "ns1:doc") - gen.endPrefixMapping("ns1") - gen.endDocument() - - return result.getvalue() == start + \ + self.assertEquals(result.getvalue(), start + \ ('' % - ns_uri) + ns_uri)) -def test_1463026_1(): - result = StringIO() - gen = XMLGenerator(result) - - gen.startDocument() - gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'}) - gen.endElementNS((None, 'a'), 'a') - gen.endDocument() - - return result.getvalue() == start+'' - -def test_1463026_2(): - result = StringIO() - gen = XMLGenerator(result) - - gen.startDocument() - gen.startPrefixMapping(None, 'qux') - gen.startElementNS(('qux', 'a'), 'a', {}) - gen.endElementNS(('qux', 'a'), 'a') - gen.endPrefixMapping(None) - gen.endDocument() - - return result.getvalue() == start+'' - -def test_1463026_3(): - result = StringIO() - gen = XMLGenerator(result) - - gen.startDocument() - gen.startPrefixMapping('my', 'qux') - gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'}) - gen.endElementNS(('qux', 'a'), 'a') - gen.endPrefixMapping('my') - gen.endDocument() - - return result.getvalue() == start+'' - -# ===== Xmlfilterbase - -def test_filter_basic(): - result = StringIO() - gen = XMLGenerator(result) - filter = XMLFilterBase() - filter.setContentHandler(gen) - - filter.startDocument() - filter.startElement("doc", {}) - filter.characters("content") - filter.ignorableWhitespace(" ") - filter.endElement("doc") - filter.endDocument() + def test_1463026_1(self): + result = StringIO() + gen = XMLGenerator(result) + + gen.startDocument() + gen.startElementNS((None, 'a'), 'a', {(None, 'b'):'c'}) + gen.endElementNS((None, 'a'), 'a') + gen.endDocument() + + self.assertEquals(result.getvalue(), start+'') + + def test_1463026_2(self): + result = StringIO() + gen = XMLGenerator(result) + + gen.startDocument() + gen.startPrefixMapping(None, 'qux') + gen.startElementNS(('qux', 'a'), 'a', {}) + gen.endElementNS(('qux', 'a'), 'a') + gen.endPrefixMapping(None) + gen.endDocument() + + self.assertEquals(result.getvalue(), start+'') + + def test_1463026_3(self): + result = StringIO() + gen = XMLGenerator(result) + + gen.startDocument() + gen.startPrefixMapping('my', 'qux') + gen.startElementNS(('qux', 'a'), 'a', {(None, 'b'):'c'}) + gen.endElementNS(('qux', 'a'), 'a') + gen.endPrefixMapping('my') + gen.endDocument() + + self.assertEquals(result.getvalue(), + start+'') + + +class XMLFilterBaseTest(unittest.TestCase): + def test_filter_basic(self): + result = StringIO() + gen = XMLGenerator(result) + filter = XMLFilterBase() + filter.setContentHandler(gen) + + filter.startDocument() + filter.startElement("doc", {}) + filter.characters("content") + filter.ignorableWhitespace(" ") + filter.endElement("doc") + filter.endDocument() - return result.getvalue() == start + "content " + self.assertEquals(result.getvalue(), start + "content ") # =========================================================================== # @@ -276,294 +311,294 @@ # # =========================================================================== -# ===== XMLReader support - -def test_expat_file(): - parser = create_parser() - result = StringIO() - xmlgen = XMLGenerator(result) - - parser.setContentHandler(xmlgen) - parser.parse(open(findfile("test"+os.extsep+"xml"))) - - return result.getvalue() == xml_test_out - -# ===== DTDHandler support - -class TestDTDHandler: - - def __init__(self): - self._notations = [] - self._entities = [] - - def notationDecl(self, name, publicId, systemId): - self._notations.append((name, publicId, systemId)) - - def unparsedEntityDecl(self, name, publicId, systemId, ndata): - self._entities.append((name, publicId, systemId, ndata)) - -def test_expat_dtdhandler(): - parser = create_parser() - handler = TestDTDHandler() - parser.setDTDHandler(handler) - - parser.feed('\n') - parser.feed(' \n') - parser.feed(']>\n') - parser.feed('') - parser.close() - - return handler._notations == [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)] and \ - handler._entities == [("img", None, "expat.gif", "GIF")] - -# ===== EntityResolver support - -class TestEntityResolver: - - def resolveEntity(self, publicId, systemId): - inpsrc = InputSource() - inpsrc.setByteStream(StringIO("")) - return inpsrc - -def test_expat_entityresolver(): - parser = create_parser() - parser.setEntityResolver(TestEntityResolver()) - result = StringIO() - parser.setContentHandler(XMLGenerator(result)) - - parser.feed('\n') - parser.feed(']>\n') - parser.feed('&test;') - parser.close() - - return result.getvalue() == start + "" - -# ===== Attributes support - -class AttrGatherer(ContentHandler): - - def startElement(self, name, attrs): - self._attrs = attrs - - def startElementNS(self, name, qname, attrs): - self._attrs = attrs - -def test_expat_attrs_empty(): - parser = create_parser() - gather = AttrGatherer() - parser.setContentHandler(gather) - - parser.feed("") - parser.close() - - return verify_empty_attrs(gather._attrs) - -def test_expat_attrs_wattr(): - parser = create_parser() - gather = AttrGatherer() - parser.setContentHandler(gather) - - parser.feed("") - parser.close() - - return verify_attrs_wattr(gather._attrs) - -def test_expat_nsattrs_empty(): - parser = create_parser(1) - gather = AttrGatherer() - parser.setContentHandler(gather) - - parser.feed("") - parser.close() - - return verify_empty_nsattrs(gather._attrs) - -def test_expat_nsattrs_wattr(): - parser = create_parser(1) - gather = AttrGatherer() - parser.setContentHandler(gather) - - parser.feed("" % ns_uri) - parser.close() - - attrs = gather._attrs - - return attrs.getLength() == 1 and \ - attrs.getNames() == [(ns_uri, "attr")] and \ - (attrs.getQNames() == [] or attrs.getQNames() == ["ns:attr"]) and \ - len(attrs) == 1 and \ - attrs.has_key((ns_uri, "attr")) and \ - attrs.keys() == [(ns_uri, "attr")] and \ - attrs.get((ns_uri, "attr")) == "val" and \ - attrs.get((ns_uri, "attr"), 25) == "val" and \ - attrs.items() == [((ns_uri, "attr"), "val")] and \ - attrs.values() == ["val"] and \ - attrs.getValue((ns_uri, "attr")) == "val" and \ - attrs[(ns_uri, "attr")] == "val" - -# ===== InputSource support - xml_test_out = open(findfile("test"+os.extsep+"xml"+os.extsep+"out")).read() -def test_expat_inpsource_filename(): - parser = create_parser() - result = StringIO() - xmlgen = XMLGenerator(result) - - parser.setContentHandler(xmlgen) - parser.parse(findfile("test"+os.extsep+"xml")) - - return result.getvalue() == xml_test_out - -def test_expat_inpsource_sysid(): - parser = create_parser() - result = StringIO() - xmlgen = XMLGenerator(result) - - parser.setContentHandler(xmlgen) - parser.parse(InputSource(findfile("test"+os.extsep+"xml"))) - - return result.getvalue() == xml_test_out - -def test_expat_inpsource_stream(): - parser = create_parser() - result = StringIO() - xmlgen = XMLGenerator(result) - - parser.setContentHandler(xmlgen) - inpsrc = InputSource() - inpsrc.setByteStream(open(findfile("test"+os.extsep+"xml"))) - parser.parse(inpsrc) - - return result.getvalue() == xml_test_out - -# ===== IncrementalParser support - -def test_expat_incremental(): - result = StringIO() - xmlgen = XMLGenerator(result) - parser = create_parser() - parser.setContentHandler(xmlgen) - - parser.feed("") - parser.feed("") - parser.close() - - return result.getvalue() == start + "" - -def test_expat_incremental_reset(): - result = StringIO() - xmlgen = XMLGenerator(result) - parser = create_parser() - parser.setContentHandler(xmlgen) - - parser.feed("") - parser.feed("text") - - result = StringIO() - xmlgen = XMLGenerator(result) - parser.setContentHandler(xmlgen) - parser.reset() - - parser.feed("") - parser.feed("text") - parser.feed("") - parser.close() - - return result.getvalue() == start + "text" - -# ===== Locator support - -def test_expat_locator_noinfo(): - result = StringIO() - xmlgen = XMLGenerator(result) - parser = create_parser() - parser.setContentHandler(xmlgen) - - parser.feed("") - parser.feed("") - parser.close() - - return parser.getSystemId() is None and \ - parser.getPublicId() is None and \ - parser.getLineNumber() == 1 - -def test_expat_locator_withinfo(): - result = StringIO() - xmlgen = XMLGenerator(result) - parser = create_parser() - parser.setContentHandler(xmlgen) - parser.parse(findfile("test.xml")) - - return parser.getSystemId() == findfile("test.xml") and \ - parser.getPublicId() is None - - +class ExpatReaderTest(XmlTestBase): + + # ===== XMLReader support + + def test_expat_file(self): + parser = create_parser() + result = StringIO() + xmlgen = XMLGenerator(result) + + parser.setContentHandler(xmlgen) + parser.parse(open(findfile("test"+os.extsep+"xml"))) + + self.assertEquals(result.getvalue(), xml_test_out) + + # ===== DTDHandler support + + class TestDTDHandler: + + def __init__(self): + self._notations = [] + self._entities = [] + + def notationDecl(self, name, publicId, systemId): + self._notations.append((name, publicId, systemId)) + + def unparsedEntityDecl(self, name, publicId, systemId, ndata): + self._entities.append((name, publicId, systemId, ndata)) + + def test_expat_dtdhandler(self): + parser = create_parser() + handler = self.TestDTDHandler() + parser.setDTDHandler(handler) + + parser.feed('\n') + parser.feed(' \n') + parser.feed(']>\n') + parser.feed('') + parser.close() + + self.assertEquals(handler._notations, + [("GIF", "-//CompuServe//NOTATION Graphics Interchange Format 89a//EN", None)]) + self.assertEquals(handler._entities, [("img", None, "expat.gif", "GIF")]) + + # ===== EntityResolver support + + class TestEntityResolver: + + def resolveEntity(self, publicId, systemId): + inpsrc = InputSource() + inpsrc.setByteStream(StringIO("")) + return inpsrc + + def test_expat_entityresolver(self): + parser = create_parser() + parser.setEntityResolver(self.TestEntityResolver()) + result = StringIO() + parser.setContentHandler(XMLGenerator(result)) + + parser.feed('\n') + parser.feed(']>\n') + parser.feed('&test;') + parser.close() + + self.assertEquals(result.getvalue(), start + + "") + + # ===== Attributes support + + class AttrGatherer(ContentHandler): + + def startElement(self, name, attrs): + self._attrs = attrs + + def startElementNS(self, name, qname, attrs): + self._attrs = attrs + + def test_expat_attrs_empty(self): + parser = create_parser() + gather = self.AttrGatherer() + parser.setContentHandler(gather) + + parser.feed("") + parser.close() + + self.verify_empty_attrs(gather._attrs) + + def test_expat_attrs_wattr(self): + parser = create_parser() + gather = self.AttrGatherer() + parser.setContentHandler(gather) + + parser.feed("") + parser.close() + + self.verify_attrs_wattr(gather._attrs) + + def test_expat_nsattrs_empty(self): + parser = create_parser(1) + gather = self.AttrGatherer() + parser.setContentHandler(gather) + + parser.feed("") + parser.close() + + self.verify_empty_nsattrs(gather._attrs) + + def test_expat_nsattrs_wattr(self): + parser = create_parser(1) + gather = self.AttrGatherer() + parser.setContentHandler(gather) + + parser.feed("" % ns_uri) + parser.close() + + attrs = gather._attrs + + self.assertEquals(attrs.getLength(), 1) + self.assertEquals(attrs.getNames(), [(ns_uri, "attr")]) + self.assertTrue((attrs.getQNames() == [] or + attrs.getQNames() == ["ns:attr"])) + self.assertEquals(len(attrs), 1) + self.assertTrue(attrs.has_key((ns_uri, "attr"))) + self.assertEquals(attrs.get((ns_uri, "attr")), "val") + self.assertEquals(attrs.get((ns_uri, "attr"), 25), "val") + self.assertEquals(attrs.items(), [((ns_uri, "attr"), "val")]) + self.assertEquals(attrs.values(), ["val"]) + self.assertEquals(attrs.getValue((ns_uri, "attr")), "val") + self.assertEquals(attrs[(ns_uri, "attr")], "val") + + # ===== InputSource support + + def test_expat_inpsource_filename(self): + parser = create_parser() + result = StringIO() + xmlgen = XMLGenerator(result) + + parser.setContentHandler(xmlgen) + parser.parse(findfile("test"+os.extsep+"xml")) + + self.assertEquals(result.getvalue(), xml_test_out) + + def test_expat_inpsource_sysid(self): + parser = create_parser() + result = StringIO() + xmlgen = XMLGenerator(result) + + parser.setContentHandler(xmlgen) + parser.parse(InputSource(findfile("test"+os.extsep+"xml"))) + + self.assertEquals(result.getvalue(), xml_test_out) + + def test_expat_inpsource_stream(self): + parser = create_parser() + result = StringIO() + xmlgen = XMLGenerator(result) + + parser.setContentHandler(xmlgen) + inpsrc = InputSource() + inpsrc.setByteStream(open(findfile("test"+os.extsep+"xml"))) + parser.parse(inpsrc) + + self.assertEquals(result.getvalue(), xml_test_out) + + # ===== IncrementalParser support + + def test_expat_incremental(self): + result = StringIO() + xmlgen = XMLGenerator(result) + parser = create_parser() + parser.setContentHandler(xmlgen) + + parser.feed("") + parser.feed("") + parser.close() + + self.assertEquals(result.getvalue(), start + "") + + def test_expat_incremental_reset(self): + result = StringIO() + xmlgen = XMLGenerator(result) + parser = create_parser() + parser.setContentHandler(xmlgen) + + parser.feed("") + parser.feed("text") + + result = StringIO() + xmlgen = XMLGenerator(result) + parser.setContentHandler(xmlgen) + parser.reset() + + parser.feed("") + parser.feed("text") + parser.feed("") + parser.close() + + self.assertEquals(result.getvalue(), start + "text") + + # ===== Locator support + + def test_expat_locator_noinfo(self): + result = StringIO() + xmlgen = XMLGenerator(result) + parser = create_parser() + parser.setContentHandler(xmlgen) + + parser.feed("") + parser.feed("") + parser.close() + + self.assertEquals(parser.getSystemId(), None) + self.assertEquals(parser.getPublicId(), None) + self.assertEquals(parser.getLineNumber(), 1) + + def test_expat_locator_withinfo(self): + result = StringIO() + xmlgen = XMLGenerator(result) + parser = create_parser() + parser.setContentHandler(xmlgen) + parser.parse(findfile("test.xml")) + + self.assertEquals(parser.getSystemId(), findfile("test.xml")) + self.assertEquals(parser.getPublicId(), None) + + # =========================================================================== # # error reporting # # =========================================================================== -def test_expat_inpsource_location(): - parser = create_parser() - parser.setContentHandler(ContentHandler()) # do nothing - source = InputSource() - source.setByteStream(StringIO("")) #ill-formed - name = "a file name" - source.setSystemId(name) - try: - parser.parse(source) - except SAXException, e: - return e.getSystemId() == name - -def test_expat_incomplete(): - parser = create_parser() - parser.setContentHandler(ContentHandler()) # do nothing - try: - parser.parse(StringIO("")) - except SAXParseException: - return 1 # ok, error found - else: - return 0 - -def test_sax_parse_exception_str(): - # pass various values from a locator to the SAXParseException to - # make sure that the __str__() doesn't fall apart when None is - # passed instead of an integer line and column number - # - # use "normal" values for the locator: - str(SAXParseException("message", None, - DummyLocator(1, 1))) - # use None for the line number: - str(SAXParseException("message", None, - DummyLocator(None, 1))) - # use None for the column number: - str(SAXParseException("message", None, - DummyLocator(1, None))) - # use None for both: - str(SAXParseException("message", None, - DummyLocator(None, None))) - return 1 - -class DummyLocator: - def __init__(self, lineno, colno): - self._lineno = lineno - self._colno = colno - - def getPublicId(self): - return "pubid" - - def getSystemId(self): - return "sysid" - - def getLineNumber(self): - return self._lineno - - def getColumnNumber(self): - return self._colno +class ErrorReportingTest(unittest.TestCase): + def test_expat_inpsource_location(self): + parser = create_parser() + parser.setContentHandler(ContentHandler()) # do nothing + source = InputSource() + source.setByteStream(StringIO("")) #ill-formed + name = "a file name" + source.setSystemId(name) + try: + parser.parse(source) + self.fail() + except SAXException, e: + self.assertEquals(e.getSystemId(), name) + + def test_expat_incomplete(self): + parser = create_parser() + parser.setContentHandler(ContentHandler()) # do nothing + self.assertRaises(SAXParseException, parser.parse, StringIO("")) + + def test_sax_parse_exception_str(self): + # pass various values from a locator to the SAXParseException to + # make sure that the __str__() doesn't fall apart when None is + # passed instead of an integer line and column number + # + # use "normal" values for the locator: + str(SAXParseException("message", None, + self.DummyLocator(1, 1))) + # use None for the line number: + str(SAXParseException("message", None, + self.DummyLocator(None, 1))) + # use None for the column number: + str(SAXParseException("message", None, + self.DummyLocator(1, None))) + # use None for both: + str(SAXParseException("message", None, + self.DummyLocator(None, None))) + + class DummyLocator: + def __init__(self, lineno, colno): + self._lineno = lineno + self._colno = colno + + def getPublicId(self): + return "pubid" + + def getSystemId(self): + return "sysid" + + def getLineNumber(self): + return self._lineno + + def getColumnNumber(self): + return self._colno # =========================================================================== # @@ -571,218 +606,91 @@ # # =========================================================================== -# ===== AttributesImpl +class XmlReaderTest(XmlTestBase): + + # ===== AttributesImpl + def test_attrs_empty(self): + self.verify_empty_attrs(AttributesImpl({})) + + def test_attrs_wattr(self): + self.verify_attrs_wattr(AttributesImpl({"attr" : "val"})) + + def test_nsattrs_empty(self): + self.verify_empty_nsattrs(AttributesNSImpl({}, {})) + + def test_nsattrs_wattr(self): + attrs = AttributesNSImpl({(ns_uri, "attr") : "val"}, + {(ns_uri, "attr") : "ns:attr"}) + + self.assertEquals(attrs.getLength(), 1) + self.assertEquals(attrs.getNames(), [(ns_uri, "attr")]) + self.assertEquals(attrs.getQNames(), ["ns:attr"]) + self.assertEquals(len(attrs), 1) + self.assertTrue(attrs.has_key((ns_uri, "attr"))) + self.assertEquals(attrs.keys(), [(ns_uri, "attr")]) + self.assertEquals(attrs.get((ns_uri, "attr")), "val") + self.assertEquals(attrs.get((ns_uri, "attr"), 25), "val") + self.assertEquals(attrs.items(), [((ns_uri, "attr"), "val")]) + self.assertEquals(attrs.values(), ["val"]) + self.assertEquals(attrs.getValue((ns_uri, "attr")), "val") + self.assertEquals(attrs.getValueByQName("ns:attr"), "val") + self.assertEquals(attrs.getNameByQName("ns:attr"), (ns_uri, "attr")) + self.assertEquals(attrs[(ns_uri, "attr")], "val") + self.assertEquals(attrs.getQNameByName((ns_uri, "attr")), "ns:attr") + + + # During the development of Python 2.5, an attempt to move the "xml" + # package implementation to a new package ("xmlcore") proved painful. + # The goal of this change was to allow applications to be able to + # obtain and rely on behavior in the standard library implementation + # of the XML support without needing to be concerned about the + # availability of the PyXML implementation. + # + # While the existing import hackery in Lib/xml/__init__.py can cause + # PyXML's _xmlpus package to supplant the "xml" package, that only + # works because either implementation uses the "xml" package name for + # imports. + # + # The move resulted in a number of problems related to the fact that + # the import machinery's "package context" is based on the name that's + # being imported rather than the __name__ of the actual package + # containment; it wasn't possible for the "xml" package to be replaced + # by a simple module that indirected imports to the "xmlcore" package. + # + # The following two tests exercised bugs that were introduced in that + # attempt. Keeping these tests around will help detect problems with + # other attempts to provide reliable access to the standard library's + # implementation of the XML support. + + def test_sf_1511497(self): + # Bug report: http://www.python.org/sf/1511497 + import sys + old_modules = sys.modules.copy() + for modname in sys.modules.keys(): + if modname.startswith("xml."): + del sys.modules[modname] + try: + import xml.sax.expatreader + module = xml.sax.expatreader + self.assertEquals(module.__name__, "xml.sax.expatreader") + finally: + sys.modules.update(old_modules) + + def test_sf_1513611(self): + # Bug report: http://www.python.org/sf/1513611 + sio = StringIO("invalid") + parser = make_parser() + from xml.sax import SAXParseException + self.assertRaises(SAXParseException, parser.parse, sio) + + +def unittest_main(): + run_unittest(MakeParserTest, + SaxutilsTest, + XmlgenTest, + ExpatReaderTest, + ErrorReportingTest, + XmlReaderTest) -def verify_empty_attrs(attrs): - try: - attrs.getValue("attr") - gvk = 0 - except KeyError: - gvk = 1 - - try: - attrs.getValueByQName("attr") - gvqk = 0 - except KeyError: - gvqk = 1 - - try: - attrs.getNameByQName("attr") - gnqk = 0 - except KeyError: - gnqk = 1 - - try: - attrs.getQNameByName("attr") - gqnk = 0 - except KeyError: - gqnk = 1 - - try: - attrs["attr"] - gik = 0 - except KeyError: - gik = 1 - - return attrs.getLength() == 0 and \ - attrs.getNames() == [] and \ - attrs.getQNames() == [] and \ - len(attrs) == 0 and \ - not attrs.has_key("attr") and \ - attrs.keys() == [] and \ - attrs.get("attrs") is None and \ - attrs.get("attrs", 25) == 25 and \ - attrs.items() == [] and \ - attrs.values() == [] and \ - gvk and gvqk and gnqk and gik and gqnk - -def verify_attrs_wattr(attrs): - return attrs.getLength() == 1 and \ - attrs.getNames() == ["attr"] and \ - attrs.getQNames() == ["attr"] and \ - len(attrs) == 1 and \ - attrs.has_key("attr") and \ - attrs.keys() == ["attr"] and \ - attrs.get("attr") == "val" and \ - attrs.get("attr", 25) == "val" and \ - attrs.items() == [("attr", "val")] and \ - attrs.values() == ["val"] and \ - attrs.getValue("attr") == "val" and \ - attrs.getValueByQName("attr") == "val" and \ - attrs.getNameByQName("attr") == "attr" and \ - attrs["attr"] == "val" and \ - attrs.getQNameByName("attr") == "attr" - -def test_attrs_empty(): - return verify_empty_attrs(AttributesImpl({})) - -def test_attrs_wattr(): - return verify_attrs_wattr(AttributesImpl({"attr" : "val"})) - -# ===== AttributesImpl - -def verify_empty_nsattrs(attrs): - try: - attrs.getValue((ns_uri, "attr")) - gvk = 0 - except KeyError: - gvk = 1 - - try: - attrs.getValueByQName("ns:attr") - gvqk = 0 - except KeyError: - gvqk = 1 - - try: - attrs.getNameByQName("ns:attr") - gnqk = 0 - except KeyError: - gnqk = 1 - - try: - attrs.getQNameByName((ns_uri, "attr")) - gqnk = 0 - except KeyError: - gqnk = 1 - - try: - attrs[(ns_uri, "attr")] - gik = 0 - except KeyError: - gik = 1 - - return attrs.getLength() == 0 and \ - attrs.getNames() == [] and \ - attrs.getQNames() == [] and \ - len(attrs) == 0 and \ - not attrs.has_key((ns_uri, "attr")) and \ - attrs.keys() == [] and \ - attrs.get((ns_uri, "attr")) is None and \ - attrs.get((ns_uri, "attr"), 25) == 25 and \ - attrs.items() == [] and \ - attrs.values() == [] and \ - gvk and gvqk and gnqk and gik and gqnk - -def test_nsattrs_empty(): - return verify_empty_nsattrs(AttributesNSImpl({}, {})) - -def test_nsattrs_wattr(): - attrs = AttributesNSImpl({(ns_uri, "attr") : "val"}, - {(ns_uri, "attr") : "ns:attr"}) - - return attrs.getLength() == 1 and \ - attrs.getNames() == [(ns_uri, "attr")] and \ - attrs.getQNames() == ["ns:attr"] and \ - len(attrs) == 1 and \ - attrs.has_key((ns_uri, "attr")) and \ - attrs.keys() == [(ns_uri, "attr")] and \ - attrs.get((ns_uri, "attr")) == "val" and \ - attrs.get((ns_uri, "attr"), 25) == "val" and \ - attrs.items() == [((ns_uri, "attr"), "val")] and \ - attrs.values() == ["val"] and \ - attrs.getValue((ns_uri, "attr")) == "val" and \ - attrs.getValueByQName("ns:attr") == "val" and \ - attrs.getNameByQName("ns:attr") == (ns_uri, "attr") and \ - attrs[(ns_uri, "attr")] == "val" and \ - attrs.getQNameByName((ns_uri, "attr")) == "ns:attr" - - -# During the development of Python 2.5, an attempt to move the "xml" -# package implementation to a new package ("xmlcore") proved painful. -# The goal of this change was to allow applications to be able to -# obtain and rely on behavior in the standard library implementation -# of the XML support without needing to be concerned about the -# availability of the PyXML implementation. -# -# While the existing import hackery in Lib/xml/__init__.py can cause -# PyXML's _xmlpus package to supplant the "xml" package, that only -# works because either implementation uses the "xml" package name for -# imports. -# -# The move resulted in a number of problems related to the fact that -# the import machinery's "package context" is based on the name that's -# being imported rather than the __name__ of the actual package -# containment; it wasn't possible for the "xml" package to be replaced -# by a simple module that indirected imports to the "xmlcore" package. -# -# The following two tests exercised bugs that were introduced in that -# attempt. Keeping these tests around will help detect problems with -# other attempts to provide reliable access to the standard library's -# implementation of the XML support. - -def test_sf_1511497(): - # Bug report: http://www.python.org/sf/1511497 - import sys - old_modules = sys.modules.copy() - for modname in sys.modules.keys(): - if modname.startswith("xml."): - del sys.modules[modname] - try: - import xml.sax.expatreader - module = xml.sax.expatreader - return module.__name__ == "xml.sax.expatreader" - finally: - sys.modules.update(old_modules) - -def test_sf_1513611(): - # Bug report: http://www.python.org/sf/1513611 - sio = StringIO("invalid") - parser = make_parser() - from xml.sax import SAXParseException - try: - parser.parse(sio) - except SAXParseException: - return True - else: - return False - -# ===== Main program - -def make_test_output(): - parser = create_parser() - result = StringIO() - xmlgen = XMLGenerator(result) - - parser.setContentHandler(xmlgen) - parser.parse(findfile("test"+os.extsep+"xml")) - - outf = open(findfile("test"+os.extsep+"xml"+os.extsep+"out"), "w") - outf.write(result.getvalue()) - outf.close() - -items = locals().items() -items.sort() -for (name, value) in items: - if name[ : 5] == "test_": - confirm(value(), name) -# We delete the items variable so that the assignment to items above -# doesn't pick up the old value of items (which messes with attempts -# to find reference leaks). -del items - -if verbose: - print "%d tests, %d failures" % (tests, len(failures)) -if failures: - raise TestFailed("%d of %d tests failed: %s" - % (len(failures), tests, ", ".join(failures))) +if __name__ == "__main__": + unittest_main() From buildbot at python.org Thu Mar 29 02:13:27 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 29 Mar 2007 00:13:27 +0000 Subject: [Python-checkins] buildbot warnings in x86 Ubuntu edgy (icc) trunk Message-ID: <20070329001327.258CF1E4004@bag.python.org> The Buildbot has detected a new failure of x86 Ubuntu edgy (icc) trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520Ubuntu%2520edgy%2520%2528icc%2529%2520trunk/builds/1207 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings failed slave lost sincerely, -The Buildbot From python-checkins at python.org Thu Mar 29 04:28:20 2007 From: python-checkins at python.org (collin.winter) Date: Thu, 29 Mar 2007 04:28:20 +0200 (CEST) Subject: [Python-checkins] r54604 - python/trunk/Lib/test/test_zipfile.py Message-ID: <20070329022820.7D8A61E4002@bag.python.org> Author: collin.winter Date: Thu Mar 29 04:28:16 2007 New Revision: 54604 Modified: python/trunk/Lib/test/test_zipfile.py Log: Make test_zipfile clean up its temporary files properly. Modified: python/trunk/Lib/test/test_zipfile.py ============================================================================== --- python/trunk/Lib/test/test_zipfile.py (original) +++ python/trunk/Lib/test/test_zipfile.py Thu Mar 29 04:28:16 2007 @@ -10,6 +10,7 @@ from tempfile import TemporaryFile from random import randint, random +import test.test_support as support from test.test_support import TESTFN, run_unittest TESTFN2 = TESTFN + "2" @@ -454,8 +455,6 @@ self.assertEqual(zf.read(filename), content) zf.close() - os.unlink(TESTFN) - def testCloseErroneousFile(self): # This test checks that the ZipFile constructor closes the file object # it opens if there's an error in the file. If it doesn't, the traceback @@ -469,7 +468,7 @@ try: zf = zipfile.ZipFile(TESTFN) except zipfile.BadZipfile: - os.unlink(TESTFN) + pass def testIsZipErroneousFile(self): # This test checks that the is_zipfile function correctly identifies @@ -478,7 +477,6 @@ fp.write("this is not a legal zip file\n") fp.close() chk = zipfile.is_zipfile(TESTFN) - os.unlink(TESTFN) self.assert_(chk is False) def testIsZipValidFile(self): @@ -488,7 +486,6 @@ zipf.writestr("foo.txt", "O, for a Muse of Fire!") zipf.close() chk = zipfile.is_zipfile(TESTFN) - os.unlink(TESTFN) self.assert_(chk is True) def testNonExistentFileRaisesIOError(self): @@ -517,6 +514,10 @@ # version of .testzip would swallow this exception (and any other) # and report that the first file in the archive was corrupt. self.assertRaises(RuntimeError, zipf.testzip) + + def tearDown(self): + support.unlink(TESTFN) + support.unlink(TESTFN2) class DecryptionTests(unittest.TestCase): # This test checks that ZIP decryption works. Since the library does not @@ -567,6 +568,10 @@ fp = open(TESTFN, "wb") fp.write(self.data) fp.close() + + def tearDown(self): + support.unlink(TESTFN) + support.unlink(TESTFN2) def makeTestArchive(self, f, compression): # Create the ZIP archive @@ -799,6 +804,8 @@ def tearDown(self): for sep, fn in self.arcfiles.items(): os.remove(fn) + support.unlink(TESTFN) + support.unlink(TESTFN2) def test_main(): @@ -806,7 +813,5 @@ PyZipFileTests, DecryptionTests, TestsWithMultipleOpens, UniversalNewlineTests, TestsWithRandomBinaryFiles) - #run_unittest(TestZip64InSmallFiles) - if __name__ == "__main__": test_main() From buildbot at python.org Thu Mar 29 04:56:14 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 29 Mar 2007 02:56:14 +0000 Subject: [Python-checkins] buildbot warnings in x86 W2k trunk Message-ID: <20070329025614.7AD5F1E4002@bag.python.org> The Buildbot has detected a new failure of x86 W2k trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520W2k%2520trunk/builds/165 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings test Excerpt from the test logfile: 7 tests failed: test_cProfile test_class test_extcall test_os test_profile test_tokenize test_urllib ====================================================================== ERROR: test_makedir (test.test_os.MakedirTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 376, in setUp os.mkdir(test_support.TESTFN) WindowsError: [Error 183] Cannot create a file when that file already exists: '@test' ====================================================================== ERROR: test_access (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 443, in test_access self.assertRaises(WindowsError, os.utime, test_support.TESTFN, 0) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\unittest.py", line 329, in failUnlessRaises callableObj(*args, **kwargs) TypeError: utime() arg 2 must be a tuple (atime, mtime) ====================================================================== FAIL: test_traversal (test.test_os.WalkTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 313, in test_traversal self.assertEqual(len(all), 4) AssertionError: 5 != 4 ====================================================================== FAIL: test_chdir (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 434, in test_chdir self.assertRaises(WindowsError, os.chdir, test_support.TESTFN) AssertionError: WindowsError not raised Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\threading.py", line 460, in __bootstrap self.run() File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\bsddb\test\test_thread.py", line 245, in writerThread self.assertEqual(data, self.makeData(key)) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\unittest.py", line 343, in failUnlessEqual (msg or '%r != %r' % (first, second)) AssertionError: None != '2123-2123-2123-2123-2123' Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\threading.py", line 460, in __bootstrap self.run() File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\bsddb\test\test_thread.py", line 260, in writerThread self.assertEqual(data, self.makeData(key)) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\unittest.py", line 343, in failUnlessEqual (msg or '%r != %r' % (first, second)) AssertionError: None != '0002-0002-0002-0002-0002' Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\threading.py", line 460, in __bootstrap self.run() File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\threading.py", line 440, in run self.__target(*self.__args, **self.__kwargs) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\bsddb\test\test_thread.py", line 260, in writerThread self.assertEqual(data, self.makeData(key)) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\unittest.py", line 343, in failUnlessEqual (msg or '%r != %r' % (first, second)) AssertionError: None != '1001-1001-1001-1001-1001' sincerely, -The Buildbot From python-checkins at python.org Thu Mar 29 09:41:34 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 29 Mar 2007 09:41:34 +0200 (CEST) Subject: [Python-checkins] r54605 - python/trunk/Doc/lib/libwebbrowser.tex Message-ID: <20070329074134.388C21E4002@bag.python.org> Author: georg.brandl Date: Thu Mar 29 09:41:32 2007 New Revision: 54605 Modified: python/trunk/Doc/lib/libwebbrowser.tex Log: These are actually methods. Modified: python/trunk/Doc/lib/libwebbrowser.tex ============================================================================== --- python/trunk/Doc/lib/libwebbrowser.tex (original) +++ python/trunk/Doc/lib/libwebbrowser.tex Thu Mar 29 09:41:32 2007 @@ -154,20 +154,20 @@ Browser controllers provide two methods which parallel two of the module-level convenience functions: -\begin{funcdesc}{open}{url\optional{, new\optional{, autoraise=1}}} +\begin{methoddesc}{open}{url\optional{, new\optional{, autoraise=1}}} Display \var{url} using the browser handled by this controller. If \var{new} is 1, a new browser window is opened if possible. If \var{new} is 2, a new browser page ("tab") is opened if possible. -\end{funcdesc} +\end{methoddesc} -\begin{funcdesc}{open_new}{url} +\begin{methoddesc}{open_new}{url} Open \var{url} in a new window of the browser handled by this controller, if possible, otherwise, open \var{url} in the only browser window. Alias \function{open_new}. -\end{funcdesc} +\end{methoddesc} -\begin{funcdesc}{open_new_tab}{url} +\begin{methoddesc}{open_new_tab}{url} Open \var{url} in a new page ("tab") of the browser handled by this controller, if possible, otherwise equivalent to \function{open_new}. \versionadded{2.5} -\end{funcdesc} +\end{methoddesc} From python-checkins at python.org Thu Mar 29 14:42:10 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 29 Mar 2007 14:42:10 +0200 (CEST) Subject: [Python-checkins] r54606 - python/trunk/Modules/timemodule.c Message-ID: <20070329124210.967FB1E4002@bag.python.org> Author: georg.brandl Date: Thu Mar 29 14:42:07 2007 New Revision: 54606 Modified: python/trunk/Modules/timemodule.c Log: In Windows' time.clock(), when QueryPerformanceFrequency() fails, the C lib's clock() is used, but it must be divided by CLOCKS_PER_SEC as for the POSIX implementation (thanks to #pypy). Modified: python/trunk/Modules/timemodule.c ============================================================================== --- python/trunk/Modules/timemodule.c (original) +++ python/trunk/Modules/timemodule.c Thu Mar 29 14:42:07 2007 @@ -175,7 +175,8 @@ if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) { /* Unlikely to happen - this works on all intel machines at least! Revert to clock() */ - return PyFloat_FromDouble(clock()); + return PyFloat_FromDouble(((double)clock()) / + CLOCKS_PER_SEC); } divisor = (double)freq.QuadPart; } From python-checkins at python.org Thu Mar 29 14:42:17 2007 From: python-checkins at python.org (georg.brandl) Date: Thu, 29 Mar 2007 14:42:17 +0200 (CEST) Subject: [Python-checkins] r54607 - python/branches/release25-maint/Modules/timemodule.c Message-ID: <20070329124217.53F951E4004@bag.python.org> Author: georg.brandl Date: Thu Mar 29 14:42:16 2007 New Revision: 54607 Modified: python/branches/release25-maint/Modules/timemodule.c Log: In Windows' time.clock(), when QueryPerformanceFrequency() fails, the C lib's clock() is used, but it must be divided by CLOCKS_PER_SEC as for the POSIX implementation (thanks to #pypy). (backport from rev. 54606) Modified: python/branches/release25-maint/Modules/timemodule.c ============================================================================== --- python/branches/release25-maint/Modules/timemodule.c (original) +++ python/branches/release25-maint/Modules/timemodule.c Thu Mar 29 14:42:16 2007 @@ -175,7 +175,8 @@ if (!QueryPerformanceFrequency(&freq) || freq.QuadPart == 0) { /* Unlikely to happen - this works on all intel machines at least! Revert to clock() */ - return PyFloat_FromDouble(clock()); + return PyFloat_FromDouble(((double)clock()) / + CLOCKS_PER_SEC); } divisor = (double)freq.QuadPart; } From buildbot at python.org Thu Mar 29 14:47:20 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 29 Mar 2007 12:47:20 +0000 Subject: [Python-checkins] buildbot failure in x86 OpenBSD 2.5 Message-ID: <20070329124720.DAAEF1E4007@bag.python.org> The Buildbot has detected a new failure of x86 OpenBSD 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520OpenBSD%25202.5/builds/236 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl,ziga.seilnacht BUILD FAILED: failed svn sincerely, -The Buildbot From buildbot at python.org Thu Mar 29 18:36:27 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 29 Mar 2007 16:36:27 +0000 Subject: [Python-checkins] buildbot warnings in ia64 Ubuntu trunk 2.5 Message-ID: <20070329163628.13EF11E4040@bag.python.org> The Buildbot has detected a new failure of ia64 Ubuntu trunk 2.5. Full details are available at: http://www.python.org/dev/buildbot/all/ia64%2520Ubuntu%2520trunk%25202.5/builds/250 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch branches/release25-maint] HEAD Blamelist: georg.brandl,ziga.seilnacht Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_timeout ====================================================================== FAIL: testConnectTimeout (test.test_timeout.TimeoutTestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/pybot/buildarea/2.5.klose-debian-ia64/build/Lib/test/test_timeout.py", line 122, in testConnectTimeout self.addr_remote) AssertionError: error not raised make: *** [buildbottest] Error 1 sincerely, -The Buildbot From python-checkins at python.org Thu Mar 29 20:22:40 2007 From: python-checkins at python.org (facundo.batista) Date: Thu, 29 Mar 2007 20:22:40 +0200 (CEST) Subject: [Python-checkins] r54608 - in python/trunk: Doc/lib/libtelnetlib.tex Lib/telnetlib.py Lib/test/test_telnetlib.py Misc/NEWS Message-ID: <20070329182240.2BD161E4002@bag.python.org> Author: facundo.batista Date: Thu Mar 29 20:22:35 2007 New Revision: 54608 Added: python/trunk/Lib/test/test_telnetlib.py Modified: python/trunk/Doc/lib/libtelnetlib.tex python/trunk/Lib/telnetlib.py python/trunk/Misc/NEWS Log: Added timout parameter to telnetlib.Telnet. Also created test_telnetlib.py with a basic test and timeout ones. Docs are also updated. Modified: python/trunk/Doc/lib/libtelnetlib.tex ============================================================================== --- python/trunk/Doc/lib/libtelnetlib.tex (original) +++ python/trunk/Doc/lib/libtelnetlib.tex Thu Mar 29 20:22:35 2007 @@ -23,13 +23,16 @@ SB (Subnegotiation Begin). -\begin{classdesc}{Telnet}{\optional{host\optional{, port}}} +\begin{classdesc}{Telnet}{\optional{host\optional{, port\optional{, timeout}}}} \class{Telnet} represents a connection to a Telnet server. The instance is initially not connected by default; the \method{open()} method must be used to establish a connection. Alternatively, the host name and optional port number can be passed to the constructor, to, in which case the connection to the server will be established before the constructor returns. +The optional \var{timeout} parameter specifies a timeout in seconds for the +connection attempt (if not specified, or passed as None, the global default +timeout setting will be used). Do not reopen an already connected instance. @@ -111,10 +114,13 @@ \versionadded{2.3} \end{methoddesc} -\begin{methoddesc}{open}{host\optional{, port}} +\begin{methoddesc}{open}{host\optional{, port\optional{, timeout}}} Connect to a host. The optional second argument is the port number, which defaults to the standard Telnet port (23). +The optional \var{timeout} parameter specifies a timeout in seconds for the +connection attempt (if not specified, or passed as None, the global default +timeout setting will be used). Do not try to reopen an already connected instance. \end{methoddesc} Modified: python/trunk/Lib/telnetlib.py ============================================================================== --- python/trunk/Lib/telnetlib.py (original) +++ python/trunk/Lib/telnetlib.py Thu Mar 29 20:22:35 2007 @@ -184,7 +184,7 @@ """ - def __init__(self, host=None, port=0): + def __init__(self, host=None, port=0, timeout=None): """Constructor. When called without arguments, create an unconnected instance. @@ -195,6 +195,7 @@ self.debuglevel = DEBUGLEVEL self.host = host self.port = port + self.timeout = timeout self.sock = None self.rawq = '' self.irawq = 0 @@ -205,9 +206,9 @@ self.sbdataq = '' self.option_callback = None if host is not None: - self.open(host, port) + self.open(host, port, timeout) - def open(self, host, port=0): + def open(self, host, port=0, timeout=None): """Connect to a host. The optional second argument is the port number, which @@ -221,20 +222,9 @@ port = TELNET_PORT self.host = host self.port = port - msg = "getaddrinfo returns an empty list" - for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): - af, socktype, proto, canonname, sa = res - try: - self.sock = socket.socket(af, socktype, proto) - self.sock.connect(sa) - except socket.error, msg: - if self.sock: - self.sock.close() - self.sock = None - continue - break - if not self.sock: - raise socket.error, msg + if timeout is not None: + self.timeout = timeout + self.sock = socket.create_connection((host, port), self.timeout) def __del__(self): """Destructor -- close the connection.""" @@ -661,7 +651,7 @@ port = socket.getservbyname(portstr, 'tcp') tn = Telnet() tn.set_debuglevel(debuglevel) - tn.open(host, port) + tn.open(host, port, timeout=0.5) tn.interact() tn.close() Added: python/trunk/Lib/test/test_telnetlib.py ============================================================================== --- (empty file) +++ python/trunk/Lib/test/test_telnetlib.py Thu Mar 29 20:22:35 2007 @@ -0,0 +1,74 @@ +import socket +import threading +import telnetlib +import time + +from unittest import TestCase +from test import test_support + + +def server(evt): + serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.settimeout(3) + serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + serv.bind(("", 9091)) + serv.listen(5) + try: + conn, addr = serv.accept() + except socket.timeout: + pass + finally: + serv.close() + evt.set() + +class GeneralTests(TestCase): + + def setUp(self): + self.evt = threading.Event() + threading.Thread(target=server, args=(self.evt,)).start() + time.sleep(.1) + + def tearDown(self): + self.evt.wait() + + def testBasic(self): + # connects + telnet = telnetlib.Telnet("localhost", 9091) + telnet.sock.close() + + def testTimeoutDefault(self): + # default + telnet = telnetlib.Telnet("localhost", 9091) + self.assertTrue(telnet.sock.gettimeout() is None) + telnet.sock.close() + + def testTimeoutValue(self): + # a value + telnet = telnetlib.Telnet("localhost", 9091, timeout=30) + self.assertEqual(telnet.sock.gettimeout(), 30) + telnet.sock.close() + + def testTimeoutDifferentOrder(self): + telnet = telnetlib.Telnet(timeout=30) + telnet.open("localhost", 9091) + self.assertEqual(telnet.sock.gettimeout(), 30) + telnet.sock.close() + + def testTimeoutNone(self): + # None, having other default + previous = socket.getdefaulttimeout() + socket.setdefaulttimeout(30) + try: + telnet = telnetlib.Telnet("localhost", 9091, timeout=None) + finally: + socket.setdefaulttimeout(previous) + self.assertEqual(telnet.sock.gettimeout(), 30) + telnet.sock.close() + + + +def test_main(verbose=None): + test_support.run_unittest(GeneralTests) + +if __name__ == '__main__': + test_main() Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Thu Mar 29 20:22:35 2007 @@ -200,6 +200,11 @@ Library ------- +- Added a timeout parameter to the constructor of other protocols + (telnetlib, ftplib, smtplib and poplib). This is second part of the + work started with create_connection() and timeout in httplib, and + closes patch #723312. + - Patch #1676823: Added create_connection() to socket.py, which may be called with a timeout, and use it from httplib (whose HTTPConnection now accepts an optional timeout). From buildbot at python.org Thu Mar 29 20:30:46 2007 From: buildbot at python.org (buildbot at python.org) Date: Thu, 29 Mar 2007 18:30:46 +0000 Subject: [Python-checkins] buildbot warnings in alpha Tru64 5.1 trunk Message-ID: <20070329183047.1F7BA1E4023@bag.python.org> The Buildbot has detected a new failure of alpha Tru64 5.1 trunk. Full details are available at: http://www.python.org/dev/buildbot/all/alpha%2520Tru64%25205.1%2520trunk/builds/1581 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: facundo.batista Build had warnings: warnings test Excerpt from the test logfile: sincerely, -The Buildbot From python-checkins at python.org Fri Mar 30 01:15:41 2007 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 30 Mar 2007 01:15:41 +0200 (CEST) Subject: [Python-checkins] r54611 - sandbox/trunk/abc/abc.py Message-ID: <20070329231541.8E1611E400A@bag.python.org> Author: guido.van.rossum Date: Fri Mar 30 01:15:37 2007 New Revision: 54611 Modified: sandbox/trunk/abc/abc.py Log: Another checkpoint. Modified: sandbox/trunk/abc/abc.py ============================================================================== --- sandbox/trunk/abc/abc.py (original) +++ sandbox/trunk/abc/abc.py Fri Mar 30 01:15:37 2007 @@ -2,16 +2,31 @@ """Abstract Base Classes experiment. -XXX How to decide the order in which orthogonal base classes are -listed? For now, I'm putting the smaller API second. - Note: this depends on the brand new Py3k feature that object.__ne__() is implemented by calling object.__eq__() and reversing the outcome (unless NotImplemented). + +XXX Should we use argument annotations here? + +XXX How to decide the order in which orthogonal base classes are +listed? For now, I'm putting the smaller API second. """ __author__ = "Guido van Rossum " +import sys + + +### BASICS ### + + +class Hashable: + + """A hashable has one method, __hash__().""" + + def __hash__(self): + return 0 + class Iterable: @@ -38,6 +53,9 @@ return 0 +### SETS ### + + class BasicSet: # XXX Alternative name: Container? Oracle (as in Delphi's Oracle)? @@ -70,10 +88,6 @@ The idea here is that all you have to do is redefine __le__ and then the other operations will automatically follow suit. - - XXX However I'm not sure that this always does the right thing, - espectially for __ge__ and __gt__, as these defer to the other - argument's class; that feels fishy. """ def __le__(self, other): @@ -96,15 +110,58 @@ return NotImplemented return len(self) == len(other) and self.__le__(other) - def __ge__(self, other): - if not isinstance(other, SizeableSet): - return NotImplemented - return other.__le__(self) + # XXX Should we define __ge__ and __gt__ too? + + # XXX The following implementations of &, |, ^, - return frozen sets + # because we have to pick a concrete type. They are allowed to + # return any subclass of SizeableSet (but SizeableSet is not a + # concrete implementation). + + def __and__(self, other): + new = set(self) + new.intersection_update(other) + return frozenset(new) + + def __or__(self, other): + new = set(self) + new.update(other) + return frozenset(new) + + def __xor__(self, other): + new = set(self) + new.symmetric_difference_update(other) + return frozenset(new) + + def __sub__(self, other): + new = set(self) + new.difference_update(other) + return frozenset(new) + + +class HashableSet(SizeableSet, HashableSet): + + def __hash__(self): + """The hash value must match __eq__. + + All sets ought to compare equal if they contain the same elements, + regardless of how they are implemented; so there's not much freedom + for __eq__ or __hash__. + """ + # This particular algorithm is similar to tuple.__hash__(). + # Implementations are free to use a different algorithm. + mult = 1000003 + h = 0x345678 + for i, elem in enumerate(self): + h = ((h ^ hash(elem)) * mult) & sys.maxint + mult = (mult + (82520 + 2*i)) & sys.maxint + return h + + +# class set(SizeableSet) +# class frozenset(HashableSet) - def __gt__(self, other): - if not isinstance(other, SizeableSet): - return NotImplemented - return other.__lt__(self) + +### MAPPINGS ### class BasicMapping: @@ -169,7 +226,12 @@ for key in self._mapping: yield key, self._mapping[key] - def __contains__(self, (key, value)): + def __contains__(self, item): + if not isinstance(item, Iterable): + try: + key, value = item + except: + return False try: val = self._mapping[key] except KeyError: @@ -255,3 +317,92 @@ if elem == value: return True return False + + +### SEQUENCES ### + + +class Sequence(Iterable): + + """A minimal sequence. + + I'm not bothering with an unsized version; I don't see a use case. + + Concrete subclasses must override __new__ or __init__, __getitem__, + and __len__; they might want to override __add__ and __mul__. The + constructor signature is expected to support a single argument + giving an iterable providing the elements. + """ + + def __index(self, i): + # Internal helper to raise TypeError for non-integer(-castable) values + if not isinstance(i, int): + if not hasattr(i, "__index__"): + raise TypeError + i = i.__index__() + if not isinstance(i, int): + raise TypeError + return i + + def __getitem__(self, index): + if isinstance(index, slice): + return self.__getslice(index) + index = self.__index(index) + raise IndexError + + def __getslice(self, slc): + # XXX Would be nice to make this generally available? + start, stop, step = slc.start, slc.stop, slc.step + for index in start, stop, step: + if index is not None: + self.__index(index) + if step is None: + step = 1 + if step == 0: + raise ValueError + if step < 0: + if start is None: + start = len(self) - 1 + if stop is None: + stop = -1 + else: + if start is None: + start = 0 + if stop is None: + stop = len(self) + return self.__class__(self[i] for i in range(start, stop, step)) + + def __len__(self): + return 0 + + def __iter__(self): + i = 0 + while i < len(self): + yield self[i] + i += 1 + + def __reversed__(self): + i = len(self) + while i > 0: + i -= 1 + yield self[i] + + def index(self, value): + for i, elem in enumerate(self): + if elem == value: + return i + raise ValueError + + def count(self, value): + return sum(1 for elem in self if elem == value) + + def __add__(self, other): + if not isinstance(other, Sequence): + return NotImplemented + return self.__class__(elem for seq in (self, other) for elem in seq) + + def __mul__(self, repeat): + if not isinstance(repeat, int) and not hasattr(repeat, "__index__"): + return NotImplemented + repeat = self.__index(repeat) + return self.__class__(elem for i in range(repeat) for elem in self) From python-checkins at python.org Fri Mar 30 02:49:46 2007 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 30 Mar 2007 02:49:46 +0200 (CEST) Subject: [Python-checkins] r54612 - sandbox/trunk/abc/abc.py Message-ID: <20070330004946.BC0C01E4004@bag.python.org> Author: guido.van.rossum Date: Fri Mar 30 02:49:45 2007 New Revision: 54612 Modified: sandbox/trunk/abc/abc.py Log: Add Sizeable base class and comparisons to Sequence. (Do we need ABCs to indicate comparability?) Modified: sandbox/trunk/abc/abc.py ============================================================================== --- sandbox/trunk/abc/abc.py (original) +++ sandbox/trunk/abc/abc.py Fri Mar 30 02:49:45 2007 @@ -322,7 +322,7 @@ ### SEQUENCES ### -class Sequence(Iterable): +class Sequence(Sizeable, Iterable): """A minimal sequence. @@ -406,3 +406,32 @@ return NotImplemented repeat = self.__index(repeat) return self.__class__(elem for i in range(repeat) for elem in self) + + def __eq__(self, other): + if not isinstance(other, Sequence): + return NotImplemented + if len(self) != len(other): + return False + for a, b in zip(self, other): + if a == b: + continue + return False + return len(self) == len(other) + + def __lt__(self, other): + if not isinstance(other, Sequence): + return NotImplemented + for a, b in zip(self, other): + if a == b: + continue + return a < b + return len(self) < len(other) + + def __le__(self, other): + if not isinstance(other, Sequence): + return NotImplemented + for a, b in zip(self, other): + if a == b: + continue + return a < b + return len(self) <= len(other) From python-checkins at python.org Fri Mar 30 15:00:36 2007 From: python-checkins at python.org (facundo.batista) Date: Fri, 30 Mar 2007 15:00:36 +0200 (CEST) Subject: [Python-checkins] r54613 - in python/trunk: Doc/lib/libftplib.tex Lib/ftplib.py Lib/test/test_ftplib.py Message-ID: <20070330130036.919BB1E401C@bag.python.org> Author: facundo.batista Date: Fri Mar 30 15:00:35 2007 New Revision: 54613 Modified: python/trunk/Doc/lib/libftplib.tex python/trunk/Lib/ftplib.py python/trunk/Lib/test/test_ftplib.py Log: Added the posibility to pass the timeout to FTP.connect, not only when instantiating the class. Docs and tests are updated. Modified: python/trunk/Doc/lib/libftplib.tex ============================================================================== --- python/trunk/Doc/lib/libftplib.tex (original) +++ python/trunk/Doc/lib/libftplib.tex Fri Mar 30 15:00:35 2007 @@ -104,13 +104,19 @@ logging each line sent and received on the control connection. \end{methoddesc} -\begin{methoddesc}{connect}{host\optional{, port}} +\begin{methoddesc}{connect}{host\optional{, port\optional{, timeout}}} Connect to the given host and port. The default port number is \code{21}, as specified by the FTP protocol specification. It is rarely needed to specify a different port number. This function should be called only once for each instance; it should not be called at all if a host was given when the instance was created. All other methods can only be used after a connection has been made. + +The optional \var{timeout} parameter specifies a timeout in seconds for +the connection attempt. If is not specified, or passed as None, the +object timeout is used (the timeout that you passed when instantiating the +class); if the object timeout is also None, the global default timeout +setting will be used. \end{methoddesc} \begin{methoddesc}{getwelcome}{} Modified: python/trunk/Lib/ftplib.py ============================================================================== --- python/trunk/Lib/ftplib.py (original) +++ python/trunk/Lib/ftplib.py Fri Mar 30 15:00:35 2007 @@ -115,7 +115,7 @@ if user: self.login(user, passwd, acct) - def connect(self, host='', port=0): + def connect(self, host='', port=0, timeout=None): '''Connect to host. Arguments are: - host: hostname to connect to (string, default previous host) - port: port to connect to (integer, default previous port) @@ -124,6 +124,8 @@ self.host = host if port > 0: self.port = port + if timeout is not None: + self.timeout = timeout self.sock = socket.create_connection((self.host, self.port), self.timeout) self.af = self.sock.family self.file = self.sock.makefile('rb') Modified: python/trunk/Lib/test/test_ftplib.py ============================================================================== --- python/trunk/Lib/test/test_ftplib.py (original) +++ python/trunk/Lib/test/test_ftplib.py Fri Mar 30 15:00:35 2007 @@ -8,14 +8,20 @@ def server(evt): serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + serv.settimeout(3) serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) serv.bind(("", 9091)) serv.listen(5) - conn, addr = serv.accept() - conn.send("1 Hola mundo\n") - conn.close() - serv.close() - evt.set() + try: + conn, addr = serv.accept() + except socket.timeout: + pass + else: + conn.send("1 Hola mundo\n") + conn.close() + finally: + serv.close() + evt.set() class GeneralTests(TestCase): @@ -48,6 +54,25 @@ self.assertEqual(ftp.sock.gettimeout(), 30) ftp.sock.close() + def testTimeoutConnect(self): + ftp = ftplib.FTP() + ftp.connect("localhost", timeout=30) + self.assertEqual(ftp.sock.gettimeout(), 30) + ftp.sock.close() + + def testTimeoutDifferentOrder(self): + ftp = ftplib.FTP(timeout=30) + ftp.connect("localhost") + self.assertEqual(ftp.sock.gettimeout(), 30) + ftp.sock.close() + + def testTimeoutDirectAccess(self): + ftp = ftplib.FTP() + ftp.timeout = 30 + ftp.connect("localhost") + self.assertEqual(ftp.sock.gettimeout(), 30) + ftp.sock.close() + def testTimeoutNone(self): # None, having other default previous = socket.getdefaulttimeout() From python-checkins at python.org Fri Mar 30 16:01:28 2007 From: python-checkins at python.org (collin.winter) Date: Fri, 30 Mar 2007 16:01:28 +0200 (CEST) Subject: [Python-checkins] r54614 - python/trunk/Doc/api/concrete.tex Message-ID: <20070330140128.0AE2B1E4002@bag.python.org> Author: collin.winter Date: Fri Mar 30 16:01:25 2007 New Revision: 54614 Modified: python/trunk/Doc/api/concrete.tex Log: Bug #1688274: add documentation for C-level class objects. Modified: python/trunk/Doc/api/concrete.tex ============================================================================== --- python/trunk/Doc/api/concrete.tex (original) +++ python/trunk/Doc/api/concrete.tex Fri Mar 30 16:01:25 2007 @@ -2162,6 +2162,35 @@ \section{Other Objects \label{otherObjects}} +\subsection{Class Objects \label{classObjects}} + +\obindex{class} +Note that the class objects described here represent old-style classes, +which will go away in Python 3. When creating new types for extension +modules, you will want to work with type objects (section +\ref{typeObjects}). + +\begin{ctypedesc}{PyClassObject} + The C structure of the objects used to describe built-in classes. +\end{ctypedesc} + +\begin{cvardesc}{PyObject*}{PyClass_Type} + This is the type object for class objects; it is the same object as + \code{types.ClassType} in the Python layer. + \withsubitem{(in module types)}{\ttindex{ClassType}} +\end{cvardesc} + +\begin{cfuncdesc}{int}{PyClass_Check}{PyObject *o} + Return true if the object \var{o} is a class object, including + instances of types derived from the standard class object. Return + false in all other cases. +\end{cfuncdesc} + +\begin{cfuncdesc}{int}{PyClass_IsSubclass}{PyObject *klass, PyObject *base} + Return true if \var{klass} is a subclass of \var{base}. Return false in + all other cases. +\end{cfuncdesc} + \subsection{File Objects \label{fileObjects}} \obindex{file} From python-checkins at python.org Fri Mar 30 17:01:43 2007 From: python-checkins at python.org (marc-andre.lemburg) Date: Fri, 30 Mar 2007 17:01:43 +0200 (CEST) Subject: [Python-checkins] r54615 - python/trunk/Lib/distutils/__init__.py Message-ID: <20070330150143.017B01E4002@bag.python.org> Author: marc-andre.lemburg Date: Fri Mar 30 17:01:42 2007 New Revision: 54615 Modified: python/trunk/Lib/distutils/__init__.py Log: Bump the patch level version of distutils since there were a few bug fixes since the 2.5.0 release. Modified: python/trunk/Lib/distutils/__init__.py ============================================================================== --- python/trunk/Lib/distutils/__init__.py (original) +++ python/trunk/Lib/distutils/__init__.py Fri Mar 30 17:01:42 2007 @@ -20,4 +20,4 @@ # In general, major and minor version should loosely follow the Python # version number the distutils code was shipped with. # -__version__ = "2.5.0" +__version__ = "2.5.1" From python-checkins at python.org Fri Mar 30 17:18:04 2007 From: python-checkins at python.org (guido.van.rossum) Date: Fri, 30 Mar 2007 17:18:04 +0200 (CEST) Subject: [Python-checkins] r54616 - sandbox/trunk/abc/abc.py Message-ID: <20070330151804.CBF4D1E4002@bag.python.org> Author: guido.van.rossum Date: Fri Mar 30 17:18:01 2007 New Revision: 54616 Modified: sandbox/trunk/abc/abc.py Log: Add abstract class and method feature. Not used throughout yet. Modified: sandbox/trunk/abc/abc.py ============================================================================== --- sandbox/trunk/abc/abc.py (original) +++ sandbox/trunk/abc/abc.py Fri Mar 30 17:18:01 2007 @@ -17,21 +17,60 @@ import sys +def abstractmethod(funcobj): + """A decorator indicating abstract methods.""" + funcobj.__abstractmethod__ = True + return funcobj + + +class AbstractClass(type): + + def __new__(mcls, name, bases, namespace): + obj = super(AbstractClass, mcls).__new__(mcls, name, bases, namespace) + abstracts = set() + for base in bases: + abstracts.update(getattr(base, "__abstractmethods__", set())) + for name, value in namespace.items(): + if getattr(value, "__abstractmethod__", False): + abstracts.add(name) + obj.__abstractmethods__ = abstracts + return obj + + +class Abstract(metaclass=AbstractClass): + + def __new__(cls): + bad = set() + for name in cls.__abstractmethods__: + value = getattr(cls, name, None) + if getattr(value, "__abstractmethod__", False): + bad.add(name) + if bad: + raise TypeError("Can't instantiate class with abstract methods %s" % + ", ".join(sorted(bad))) + return super(Abstract, cls).__new__(cls) + + ### BASICS ### -class Hashable: +class Hashable(Abstract): """A hashable has one method, __hash__().""" + @abstractmethod def __hash__(self): return 0 -class Iterable: +Hashable() + + +class Iterable(Abstract): """An iterable has one method, __iter__().""" + @abstractmethod def __iter__(self): return Iterator() @@ -40,6 +79,7 @@ """An iterator has two methods, __iter__() and next().""" + @abstractmethod def next(self): raise StopIteration @@ -47,8 +87,9 @@ return self -class Sizeable: +class Sizeable(Abstract): + @abstractmethod def __len__(self): return 0 @@ -56,12 +97,13 @@ ### SETS ### -class BasicSet: +class BasicSet(Abstract): # XXX Alternative name: Container? Oracle (as in Delphi's Oracle)? """A basic set has __contains__() and that's it.""" + @abstractmethod def __contains__(self, elem): return False @@ -138,7 +180,7 @@ return frozenset(new) -class HashableSet(SizeableSet, HashableSet): +class HashableSet(SizeableSet, Hashable): def __hash__(self): """The hash value must match __eq__. @@ -227,7 +269,6 @@ yield key, self._mapping[key] def __contains__(self, item): - if not isinstance(item, Iterable): try: key, value = item except: From python-checkins at python.org Fri Mar 30 17:49:11 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 30 Mar 2007 17:49:11 +0200 (CEST) Subject: [Python-checkins] r54617 - python/trunk/Doc/lib/libasyncore.tex Message-ID: <20070330154911.9850C1E4003@bag.python.org> Author: georg.brandl Date: Fri Mar 30 17:49:05 2007 New Revision: 54617 Modified: python/trunk/Doc/lib/libasyncore.tex Log: Markup fix. Modified: python/trunk/Doc/lib/libasyncore.tex ============================================================================== --- python/trunk/Doc/lib/libasyncore.tex (original) +++ python/trunk/Doc/lib/libasyncore.tex Fri Mar 30 17:49:05 2007 @@ -46,7 +46,7 @@ \begin{funcdesc}{loop}{\optional{timeout\optional{, use_poll\optional{, map\optional{,count}}}}} Enter a polling loop that terminates after count passes or all open - channels have been closed. All arguments are optional. The \var(count) + channels have been closed. All arguments are optional. The \var{count} parameter defaults to None, resulting in the loop terminating only when all channels have been closed. The \var{timeout} argument sets the timeout parameter for the appropriate \function{select()} or From python-checkins at python.org Fri Mar 30 19:39:45 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 30 Mar 2007 19:39:45 +0200 (CEST) Subject: [Python-checkins] r54618 - python/trunk/Doc/lib/libdecimal.tex Message-ID: <20070330173945.044DA1E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 30 19:39:39 2007 New Revision: 54618 Modified: python/trunk/Doc/lib/libdecimal.tex Log: Label name fix. Modified: python/trunk/Doc/lib/libdecimal.tex ============================================================================== --- python/trunk/Doc/lib/libdecimal.tex (original) +++ python/trunk/Doc/lib/libdecimal.tex Fri Mar 30 19:39:39 2007 @@ -425,7 +425,7 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\subsection{Context objects \label{decimal-decimal}} +\subsection{Context objects \label{decimal-context}} Contexts are environments for arithmetic operations. They govern precision, set rules for rounding, determine which signals are treated as exceptions, and From python-checkins at python.org Fri Mar 30 19:47:22 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 30 Mar 2007 19:47:22 +0200 (CEST) Subject: [Python-checkins] r54619 - python/trunk/Doc/lib/libmailbox.tex Message-ID: <20070330174722.62FD01E4011@bag.python.org> Author: georg.brandl Date: Fri Mar 30 19:47:21 2007 New Revision: 54619 Modified: python/trunk/Doc/lib/libmailbox.tex Log: Duplicate label fix. Modified: python/trunk/Doc/lib/libmailbox.tex ============================================================================== --- python/trunk/Doc/lib/libmailbox.tex (original) +++ python/trunk/Doc/lib/libmailbox.tex Fri Mar 30 19:47:21 2007 @@ -1203,7 +1203,6 @@ \end{tableii} \subsection{Exceptions} -\label{mailbox-deprecated} The following exception classes are defined in the \module{mailbox} module: From python-checkins at python.org Fri Mar 30 19:48:40 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 30 Mar 2007 19:48:40 +0200 (CEST) Subject: [Python-checkins] r54620 - python/trunk/Doc/lib/libmailbox.tex Message-ID: <20070330174840.63A661E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 30 19:48:39 2007 New Revision: 54620 Modified: python/trunk/Doc/lib/libmailbox.tex Log: Markup fix. Modified: python/trunk/Doc/lib/libmailbox.tex ============================================================================== --- python/trunk/Doc/lib/libmailbox.tex (original) +++ python/trunk/Doc/lib/libmailbox.tex Fri Mar 30 19:48:39 2007 @@ -1285,13 +1285,13 @@ 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 +the \samp{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 +\samp{From_} line checking, using a regular expression that usually correctly +matched \samp{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 From python-checkins at python.org Fri Mar 30 19:57:32 2007 From: python-checkins at python.org (andrew.kuchling) Date: Fri, 30 Mar 2007 19:57:32 +0200 (CEST) Subject: [Python-checkins] r54621 - python/branches/amk-mailbox/Doc/whatsnew/whatsnew25.tex Message-ID: <20070330175732.BDF481E4002@bag.python.org> Author: andrew.kuchling Date: Fri Mar 30 19:57:31 2007 New Revision: 54621 Modified: python/branches/amk-mailbox/Doc/whatsnew/whatsnew25.tex Log: Add item Modified: python/branches/amk-mailbox/Doc/whatsnew/whatsnew25.tex ============================================================================== --- python/branches/amk-mailbox/Doc/whatsnew/whatsnew25.tex (original) +++ python/branches/amk-mailbox/Doc/whatsnew/whatsnew25.tex Fri Mar 30 19:57:31 2007 @@ -1294,6 +1294,17 @@ (Contributed by Alan McIntyre and committed at the NeedForSpeed sprint.) % Patch 1442927 +\item It's now illegal to mix iterating over a file +with \code{for line in \var{file}} and calling +the file object's \method{read()}/\method{readline()}/\method{readlines()} +methods. Iteration uses an internal buffer and the +\method{read*()} methods don't use that buffer. +Instead they would return the data following the buffer, causing the +data to appear out of order. Mixing iteration and these methods will +now trigger a \exception{ValueError} from the \method{read*()} method. +(Implemented by Thomas Wouters.) +% Patch 1397960 + \item The \module{struct} module now compiles structure format strings into an internal representation and caches this representation, yielding a 20\% speedup. (Contributed by Bob Ippolito From python-checkins at python.org Fri Mar 30 19:58:17 2007 From: python-checkins at python.org (andrew.kuchling) Date: Fri, 30 Mar 2007 19:58:17 +0200 (CEST) Subject: [Python-checkins] r54622 - python/branches/release25-maint/Doc/whatsnew/whatsnew25.tex Message-ID: <20070330175817.25F311E4002@bag.python.org> Author: andrew.kuchling Date: Fri Mar 30 19:58:16 2007 New Revision: 54622 Modified: python/branches/release25-maint/Doc/whatsnew/whatsnew25.tex Log: Add item Modified: python/branches/release25-maint/Doc/whatsnew/whatsnew25.tex ============================================================================== --- python/branches/release25-maint/Doc/whatsnew/whatsnew25.tex (original) +++ python/branches/release25-maint/Doc/whatsnew/whatsnew25.tex Fri Mar 30 19:58:16 2007 @@ -1294,6 +1294,17 @@ (Contributed by Alan McIntyre and committed at the NeedForSpeed sprint.) % Patch 1442927 +\item It's now illegal to mix iterating over a file +with \code{for line in \var{file}} and calling +the file object's \method{read()}/\method{readline()}/\method{readlines()} +methods. Iteration uses an internal buffer and the +\method{read*()} methods don't use that buffer. +Instead they would return the data following the buffer, causing the +data to appear out of order. Mixing iteration and these methods will +now trigger a \exception{ValueError} from the \method{read*()} method. +(Implemented by Thomas Wouters.) +% Patch 1397960 + \item The \module{struct} module now compiles structure format strings into an internal representation and caches this representation, yielding a 20\% speedup. (Contributed by Bob Ippolito From python-checkins at python.org Fri Mar 30 20:00:16 2007 From: python-checkins at python.org (andrew.kuchling) Date: Fri, 30 Mar 2007 20:00:16 +0200 (CEST) Subject: [Python-checkins] r54623 - python/trunk/Doc/whatsnew/whatsnew25.tex Message-ID: <20070330180016.A90D21E400F@bag.python.org> Author: andrew.kuchling Date: Fri Mar 30 20:00:15 2007 New Revision: 54623 Modified: python/trunk/Doc/whatsnew/whatsnew25.tex Log: Add item. (Oops, accidentally checked this in on my branch) Modified: python/trunk/Doc/whatsnew/whatsnew25.tex ============================================================================== --- python/trunk/Doc/whatsnew/whatsnew25.tex (original) +++ python/trunk/Doc/whatsnew/whatsnew25.tex Fri Mar 30 20:00:15 2007 @@ -1294,6 +1294,17 @@ (Contributed by Alan McIntyre and committed at the NeedForSpeed sprint.) % Patch 1442927 +\item It's now illegal to mix iterating over a file +with \code{for line in \var{file}} and calling +the file object's \method{read()}/\method{readline()}/\method{readlines()} +methods. Iteration uses an internal buffer and the +\method{read*()} methods don't use that buffer. +Instead they would return the data following the buffer, causing the +data to appear out of order. Mixing iteration and these methods will +now trigger a \exception{ValueError} from the \method{read*()} method. +(Implemented by Thomas Wouters.) +% Patch 1397960 + \item The \module{struct} module now compiles structure format strings into an internal representation and caches this representation, yielding a 20\% speedup. (Contributed by Bob Ippolito From python-checkins at python.org Fri Mar 30 21:01:39 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 30 Mar 2007 21:01:39 +0200 (CEST) Subject: [Python-checkins] r54624 - python/trunk/Doc/lib/libctypes.tex Message-ID: <20070330190139.629CC1E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 30 21:01:38 2007 New Revision: 54624 Modified: python/trunk/Doc/lib/libctypes.tex Log: Duplicate label fix. Modified: python/trunk/Doc/lib/libctypes.tex ============================================================================== --- python/trunk/Doc/lib/libctypes.tex (original) +++ python/trunk/Doc/lib/libctypes.tex Fri Mar 30 21:01:38 2007 @@ -2113,7 +2113,7 @@ \end{memberdesc} -\subsubsection{Fundamental data types\label{ctypes-fundamental-data-types}} +\subsubsection{Fundamental data types\label{ctypes-fundamental-data-types-2}} \begin{classdesc*}{_SimpleCData} This non-public class is the base class of all fundamental ctypes From python-checkins at python.org Fri Mar 30 21:14:04 2007 From: python-checkins at python.org (georg.brandl) Date: Fri, 30 Mar 2007 21:14:04 +0200 (CEST) Subject: [Python-checkins] r54625 - python/trunk/Doc/lib/liboptparse.tex Message-ID: <20070330191404.4451B1E4002@bag.python.org> Author: georg.brandl Date: Fri Mar 30 21:14:02 2007 New Revision: 54625 Modified: python/trunk/Doc/lib/liboptparse.tex Log: Markup fix. Modified: python/trunk/Doc/lib/liboptparse.tex ============================================================================== --- python/trunk/Doc/lib/liboptparse.tex (original) +++ python/trunk/Doc/lib/liboptparse.tex Fri Mar 30 21:14:02 2007 @@ -518,7 +518,7 @@ is then printed before the detailed option help. If you don't supply a usage string, \module{optparse} uses a bland but sensible -default: ``\code{usage: {\%}prog {[}options]"}, which is fine if your script +default: \code{usage: {\%}prog {[}options]"}, which is fine if your script doesn't take any positional arguments. \item {} From amk at amk.ca Fri Mar 30 21:32:27 2007 From: amk at amk.ca (A.M. Kuchling) Date: Fri, 30 Mar 2007 15:32:27 -0400 Subject: [Python-checkins] r54625 - python/trunk/Doc/lib/liboptparse.tex In-Reply-To: <20070330191404.4451B1E4002@bag.python.org> References: <20070330191404.4451B1E4002@bag.python.org> Message-ID: <20070330193227.GA23160@localhost.localdomain> On Fri, Mar 30, 2007 at 09:14:04PM +0200, georg.brandl wrote: > -default: ``\code{usage: {\%}prog {[}options]"}, which is fine if your script > +default: \code{usage: {\%}prog {[}options]"}, which is fine if your script ^ is this second quote mark necessary? --amk From python-checkins at python.org Sat Mar 31 03:20:26 2007 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 31 Mar 2007 03:20:26 +0200 (CEST) Subject: [Python-checkins] r54627 - sandbox/trunk/abc/abc.py Message-ID: <20070331012026.E3D861E4004@bag.python.org> Author: guido.van.rossum Date: Sat Mar 31 03:20:25 2007 New Revision: 54627 Modified: sandbox/trunk/abc/abc.py Log: Declare some more abstract methods. Modified: sandbox/trunk/abc/abc.py ============================================================================== --- sandbox/trunk/abc/abc.py (original) +++ sandbox/trunk/abc/abc.py Sat Mar 31 03:20:25 2007 @@ -63,9 +63,6 @@ return 0 -Hashable() - - class Iterable(Abstract): """An iterable has one method, __iter__().""" @@ -206,7 +203,7 @@ ### MAPPINGS ### -class BasicMapping: +class BasicMapping(Abstract): # XXX derive from (BasicSet)? @@ -217,6 +214,7 @@ Other dict methods are not supported. """ + @abstractmethod def __getitem__(self, key): raise KeyError @@ -385,6 +383,7 @@ raise TypeError return i + @abstractmethod def __getitem__(self, index): if isinstance(index, slice): return self.__getslice(index) @@ -413,6 +412,7 @@ stop = len(self) return self.__class__(self[i] for i in range(start, stop, step)) + @abstractmethod def __len__(self): return 0 @@ -443,6 +443,7 @@ return self.__class__(elem for seq in (self, other) for elem in seq) def __mul__(self, repeat): + # XXX Looks like we need an ABC to indicate integer-ness... if not isinstance(repeat, int) and not hasattr(repeat, "__index__"): return NotImplemented repeat = self.__index(repeat) From python-checkins at python.org Sat Mar 31 07:42:16 2007 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 31 Mar 2007 07:42:16 +0200 (CEST) Subject: [Python-checkins] r54628 - sandbox/trunk/abc/abc.py Message-ID: <20070331054216.7DF651E4003@bag.python.org> Author: guido.van.rossum Date: Sat Mar 31 07:42:16 2007 New Revision: 54628 Modified: sandbox/trunk/abc/abc.py Log: Fix the hashing. Modified: sandbox/trunk/abc/abc.py ============================================================================== --- sandbox/trunk/abc/abc.py (original) +++ sandbox/trunk/abc/abc.py Sat Mar 31 07:42:16 2007 @@ -183,16 +183,13 @@ """The hash value must match __eq__. All sets ought to compare equal if they contain the same elements, - regardless of how they are implemented; so there's not much freedom - for __eq__ or __hash__. + regardless of how they are implemented, and regardless of the + order of the elements; so there's not much freedom for __eq__ or + __hash__. We just XOR the hash of the elements. """ - # This particular algorithm is similar to tuple.__hash__(). - # Implementations are free to use a different algorithm. - mult = 1000003 - h = 0x345678 - for i, elem in enumerate(self): - h = ((h ^ hash(elem)) * mult) & sys.maxint - mult = (mult + (82520 + 2*i)) & sys.maxint + h = 0 + for elem in self: + h ^= hash(elem) return h @@ -477,3 +474,54 @@ continue return a < b return len(self) <= len(other) + + +class HashableSequence(Sequence, Hashable): + + def __hash__(self): + """The hash value must match __eq__. + + Since we want sequences to be equal iff their elements are equal + (regardless of the sequence type), this algorithm is (XXX + hopefully) identical to tuple.__hash__(). + """ + mask = sys.maxint*2 + 1 + mult = 1000003 + h = 0x345678 + n = len(self) + for i, elem in enumerate(self): + h = ((h ^ hash(elem)) * mult) & mask + mult = (mult + (82520 - 2 + 2*(n-i))) & mask + h += 97531 + h &= mask + if h > sys.maxint: + h -= mask + 1 + if h == -1: + h = -2 + return h + + +### test ### + + +def _test(): + # Test that HashableSequence.__hash__() emulates tuple.__hash__(). + class C(HashableSequence): + def __new__(cls, values): + obj = super(C, cls).__new__(cls) + obj.__values = list(values) + return obj + def __len__(self): + return len(self.__values) + def __getitem__(self, i): + return self.__values[i] + for l in ([], [0], [1], [0, 1], + list(range(-sys.maxint, sys.maxint, 100000)), + "The quick brown fox jumps over the lazy dog".split()): + a = C(l) + ha = hash(a) + htl = hash(tuple(l)) + assert ha == htl, (l, ha, htl) + +if __name__ == "__main__": + _test() From python-checkins at python.org Sat Mar 31 12:17:34 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2007 12:17:34 +0200 (CEST) Subject: [Python-checkins] r54629 - python/trunk/Doc/lib/liboptparse.tex Message-ID: <20070331101734.2976F1E4003@bag.python.org> Author: georg.brandl Date: Sat Mar 31 12:17:31 2007 New Revision: 54629 Modified: python/trunk/Doc/lib/liboptparse.tex Log: repair string literal. Modified: python/trunk/Doc/lib/liboptparse.tex ============================================================================== --- python/trunk/Doc/lib/liboptparse.tex (original) +++ python/trunk/Doc/lib/liboptparse.tex Sat Mar 31 12:17:31 2007 @@ -518,7 +518,7 @@ is then printed before the detailed option help. If you don't supply a usage string, \module{optparse} uses a bland but sensible -default: \code{usage: {\%}prog {[}options]"}, which is fine if your script +default: \code{"usage: {\%}prog {[}options]"}, which is fine if your script doesn't take any positional arguments. \item {} From python-checkins at python.org Sat Mar 31 13:55:02 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2007 13:55:02 +0200 (CEST) Subject: [Python-checkins] r54630 - python/trunk/Doc/lib/libtextwrap.tex Message-ID: <20070331115502.DB5B31E4003@bag.python.org> Author: georg.brandl Date: Sat Mar 31 13:54:58 2007 New Revision: 54630 Modified: python/trunk/Doc/lib/libtextwrap.tex Log: Markup fix. Modified: python/trunk/Doc/lib/libtextwrap.tex ============================================================================== --- python/trunk/Doc/lib/libtextwrap.tex (original) +++ python/trunk/Doc/lib/libtextwrap.tex Sat Mar 31 13:54:58 2007 @@ -54,7 +54,7 @@ in indented form. Note that tabs and spaces are both treated as whitespace, but they are -not equal: the lines \code{" {} hello"} and \code{"\textbackslash{}thello"} +not equal: the lines \code{" {} hello"} and \code{"\e thello"} are considered to have no common leading whitespace. (This behaviour is new in Python 2.5; older versions of this module incorrectly expanded tabs before searching for common leading whitespace.) From python-checkins at python.org Sat Mar 31 13:58:37 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2007 13:58:37 +0200 (CEST) Subject: [Python-checkins] r54631 - python/trunk/Doc/whatsnew/whatsnew23.tex Message-ID: <20070331115837.91CD91E4003@bag.python.org> Author: georg.brandl Date: Sat Mar 31 13:58:36 2007 New Revision: 54631 Modified: python/trunk/Doc/whatsnew/whatsnew23.tex Log: Duplicate label fix. Modified: python/trunk/Doc/whatsnew/whatsnew23.tex ============================================================================== --- python/trunk/Doc/whatsnew/whatsnew23.tex (original) +++ python/trunk/Doc/whatsnew/whatsnew23.tex Sat Mar 31 13:58:36 2007 @@ -896,7 +896,7 @@ \end{seealso} %====================================================================== -\section{PEP 307: Pickle Enhancements \label{section-pep305}} +\section{PEP 307: Pickle Enhancements \label{section-pep307}} The \module{pickle} and \module{cPickle} modules received some attention during the 2.3 development cycle. In 2.2, new-style classes From python-checkins at python.org Sat Mar 31 13:59:54 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2007 13:59:54 +0200 (CEST) Subject: [Python-checkins] r54632 - python/trunk/Doc/whatsnew/whatsnew24.tex Message-ID: <20070331115954.BE6C21E4003@bag.python.org> Author: georg.brandl Date: Sat Mar 31 13:59:54 2007 New Revision: 54632 Modified: python/trunk/Doc/whatsnew/whatsnew24.tex Log: Typo fix. Modified: python/trunk/Doc/whatsnew/whatsnew24.tex ============================================================================== --- python/trunk/Doc/whatsnew/whatsnew24.tex (original) +++ python/trunk/Doc/whatsnew/whatsnew24.tex Sat Mar 31 13:59:54 2007 @@ -1291,7 +1291,7 @@ [1, 2, 3] >>> list(i2) # Run the second iterator to exhaustion [1, 2, 3] ->\end{verbatim} +\end{verbatim} Note that \function{tee()} has to keep copies of the values returned by the iterator; in the worst case, it may need to keep all of them. From python-checkins at python.org Sat Mar 31 20:54:19 2007 From: python-checkins at python.org (neal.norwitz) Date: Sat, 31 Mar 2007 20:54:19 +0200 (CEST) Subject: [Python-checkins] r54633 - python/trunk/Modules/socketmodule.c Message-ID: <20070331185419.510831E4004@bag.python.org> Author: neal.norwitz Date: Sat Mar 31 20:54:18 2007 New Revision: 54633 Modified: python/trunk/Modules/socketmodule.c Log: Fix method names. Will backport. Modified: python/trunk/Modules/socketmodule.c ============================================================================== --- python/trunk/Modules/socketmodule.c (original) +++ python/trunk/Modules/socketmodule.c Sat Mar 31 20:54:18 2007 @@ -2384,7 +2384,7 @@ int buflen; /* Get the buffer's memory */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recv", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recv_into", kwlist, &buf, &buflen, &recvlen, &flags)) return NULL; assert(buf != 0 && buflen > 0); @@ -2559,8 +2559,9 @@ PyObject *addr = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recvfrom", kwlist, - &buf, &buflen, &recvlen, &flags)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recvfrom_into", + kwlist, &buf, &buflen, + &recvlen, &flags)) return NULL; assert(buf != 0 && buflen > 0); From python-checkins at python.org Sat Mar 31 20:56:13 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2007 20:56:13 +0200 (CEST) Subject: [Python-checkins] r54634 - python/trunk/Misc/NEWS python/trunk/Misc/python-config.in Message-ID: <20070331185613.D7BA01E4004@bag.python.org> Author: georg.brandl Date: Sat Mar 31 20:56:11 2007 New Revision: 54634 Modified: python/trunk/Misc/NEWS python/trunk/Misc/python-config.in Log: Bug #1655392: don't add -L/usr/lib/pythonX.Y/config to the LDFLAGS returned by python-config if Python was built with --enable-shared because that prevented the shared library from being used. Modified: python/trunk/Misc/NEWS ============================================================================== --- python/trunk/Misc/NEWS (original) +++ python/trunk/Misc/NEWS Sat Mar 31 20:56:11 2007 @@ -768,6 +768,10 @@ Build ----- +- Bug #1655392: don't add -L/usr/lib/pythonX.Y/config to the LDFLAGS + returned by python-config if Python was built with --enable-shared + because that prevented the shared library from being used. + - Patch #1569798: fix a bug in distutils when building Python from a directory within sys.exec_prefix. Modified: python/trunk/Misc/python-config.in ============================================================================== --- python/trunk/Misc/python-config.in (original) +++ python/trunk/Misc/python-config.in Sat Mar 31 20:56:11 2007 @@ -45,7 +45,9 @@ elif opt in ('--libs', '--ldflags'): libs = getvar('LIBS').split() + getvar('SYSLIBS').split() libs.append('-lpython'+pyver) - if opt == '--ldflags': + # add the prefix/lib/pythonX.Y/config dir, but only if there is no + # shared library in prefix/lib/. + if opt == '--ldflags' and not getvar('Py_ENABLE_SHARED'): libs.insert(0, '-L' + getvar('LIBPL')) print ' '.join(libs) From python-checkins at python.org Sat Mar 31 20:56:14 2007 From: python-checkins at python.org (neal.norwitz) Date: Sat, 31 Mar 2007 20:56:14 +0200 (CEST) Subject: [Python-checkins] r54635 - in python/branches/release25-maint: Lib/test/test_socket.py Misc/NEWS Modules/socketmodule.c Message-ID: <20070331185614.C8DC01E4004@bag.python.org> Author: neal.norwitz Date: Sat Mar 31 20:56:11 2007 New Revision: 54635 Modified: python/branches/release25-maint/Lib/test/test_socket.py python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Modules/socketmodule.c Log: Backport 54594: Fix SF #1688393, sock.recvfrom(-24) crashes Also fix some method names that were copied incorrectly (trunk fixed). Modified: python/branches/release25-maint/Lib/test/test_socket.py ============================================================================== --- python/branches/release25-maint/Lib/test/test_socket.py (original) +++ python/branches/release25-maint/Lib/test/test_socket.py Sat Mar 31 20:56:11 2007 @@ -583,6 +583,13 @@ def _testRecvFrom(self): self.cli.sendto(MSG, 0, (HOST, PORT)) + def testRecvFromNegative(self): + # Negative lengths passed to recvfrom should give ValueError. + self.assertRaises(ValueError, self.serv.recvfrom, -1) + + def _testRecvFromNegative(self): + self.cli.sendto(MSG, 0, (HOST, PORT)) + class TCPCloserTest(ThreadedTCPSocketTest): def testClose(self): Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sat Mar 31 20:56:11 2007 @@ -134,6 +134,8 @@ Extension Modules ----------------- +- Bug #1688393: Prevent crash in socket.recvfrom if length is negative. + - Bug #1622896: fix a rare corner case where the bz2 module raised an error in spite of a succesful compression. Modified: python/branches/release25-maint/Modules/socketmodule.c ============================================================================== --- python/branches/release25-maint/Modules/socketmodule.c (original) +++ python/branches/release25-maint/Modules/socketmodule.c Sat Mar 31 20:56:11 2007 @@ -2356,14 +2356,14 @@ int buflen; /* Get the buffer's memory */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recv", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recv_into", kwlist, &buf, &buflen, &recvlen, &flags)) return NULL; assert(buf != 0 && buflen > 0); if (recvlen < 0) { PyErr_SetString(PyExc_ValueError, - "negative buffersize in recv"); + "negative buffersize in recv_into"); return NULL; } if (recvlen == 0) { @@ -2479,6 +2479,12 @@ if (!PyArg_ParseTuple(args, "i|i:recvfrom", &recvlen, &flags)) return NULL; + if (recvlen < 0) { + PyErr_SetString(PyExc_ValueError, + "negative buffersize in recvfrom"); + return NULL; + } + buf = PyString_FromStringAndSize((char *) 0, recvlen); if (buf == NULL) return NULL; @@ -2525,14 +2531,15 @@ PyObject *addr = NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recvfrom", kwlist, - &buf, &buflen, &recvlen, &flags)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "w#|ii:recvfrom_into", + kwlist, &buf, &buflen, + &recvlen, &flags)) return NULL; assert(buf != 0 && buflen > 0); if (recvlen < 0) { PyErr_SetString(PyExc_ValueError, - "negative buffersize in recv"); + "negative buffersize in recvfrom_into"); return NULL; } if (recvlen == 0) { From python-checkins at python.org Sat Mar 31 20:58:21 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2007 20:58:21 +0200 (CEST) Subject: [Python-checkins] r54636 - python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Misc/python-config.in Message-ID: <20070331185821.EBDC31E4004@bag.python.org> Author: georg.brandl Date: Sat Mar 31 20:58:21 2007 New Revision: 54636 Modified: python/branches/release25-maint/Misc/NEWS python/branches/release25-maint/Misc/python-config.in Log: Backport docs for recv_into and recvfrom_into. Modified: python/branches/release25-maint/Misc/NEWS ============================================================================== --- python/branches/release25-maint/Misc/NEWS (original) +++ python/branches/release25-maint/Misc/NEWS Sat Mar 31 20:58:21 2007 @@ -426,6 +426,10 @@ Build ----- +- Bug #1655392: don't add -L/usr/lib/pythonX.Y/config to the LDFLAGS + returned by python-config if Python was built with --enable-shared + because that prevented the shared library from being used. + - Patch #1569798: fix a bug in distutils when building Python from a directory within sys.exec_prefix. Modified: python/branches/release25-maint/Misc/python-config.in ============================================================================== --- python/branches/release25-maint/Misc/python-config.in (original) +++ python/branches/release25-maint/Misc/python-config.in Sat Mar 31 20:58:21 2007 @@ -45,7 +45,9 @@ elif opt in ('--libs', '--ldflags'): libs = getvar('LIBS').split() + getvar('SYSLIBS').split() libs.append('-lpython'+pyver) - if opt == '--ldflags': + # add the prefix/lib/pythonX.Y/config dir, but only if there is no + # shared library in prefix/lib/. + if opt == '--ldflags' and not getvar('Py_ENABLE_SHARED'): libs.insert(0, '-L' + getvar('LIBPL')) print ' '.join(libs) From nnorwitz at gmail.com Sat Mar 31 20:59:55 2007 From: nnorwitz at gmail.com (Neal Norwitz) Date: Sat, 31 Mar 2007 11:59:55 -0700 Subject: [Python-checkins] r54625 - python/trunk/Doc/lib/liboptparse.tex In-Reply-To: <20070330191404.4451B1E4002@bag.python.org> References: <20070330191404.4451B1E4002@bag.python.org> Message-ID: On 3/30/07, georg.brandl wrote: > Author: georg.brandl > Date: Fri Mar 30 21:14:02 2007 > New Revision: 54625 > > Modified: > python/trunk/Doc/lib/liboptparse.tex Note the first lines of this file: % THIS FILE IS AUTO-GENERATED! DO NOT EDIT! % (Your changes will be lost the next time it is generated.) Greg still maintains Optik separately AFAIK. n From buildbot at python.org Sat Mar 31 21:20:56 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 31 Mar 2007 19:20:56 +0000 Subject: [Python-checkins] buildbot warnings in x86 W2k trunk Message-ID: <20070331192056.383531E400D@bag.python.org> The Buildbot has detected a new failure of x86 W2k trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520W2k%2520trunk/builds/170 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: andrew.kuchling,georg.brandl,neal.norwitz Build had warnings: warnings test Excerpt from the test logfile: 6 tests failed: test_os test_pep277 test_pkg test_rgbimg test_urllib test_winreg ====================================================================== ERROR: test_makedir (test.test_os.MakedirTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 376, in setUp os.mkdir(test_support.TESTFN) WindowsError: [Error 183] Cannot create a file when that file already exists: '@test' ====================================================================== ERROR: test_access (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 443, in test_access self.assertRaises(WindowsError, os.utime, test_support.TESTFN, 0) File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\unittest.py", line 329, in failUnlessRaises callableObj(*args, **kwargs) TypeError: utime() arg 2 must be a tuple (atime, mtime) ====================================================================== FAIL: test_traversal (test.test_os.WalkTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 313, in test_traversal self.assertEqual(len(all), 4) AssertionError: 5 != 4 ====================================================================== FAIL: test_chdir (test.test_os.Win32ErrorTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 434, in test_chdir self.assertRaises(WindowsError, os.chdir, test_support.TESTFN) AssertionError: WindowsError not raised sincerely, -The Buildbot From python-checkins at python.org Sat Mar 31 21:21:16 2007 From: python-checkins at python.org (georg.brandl) Date: Sat, 31 Mar 2007 21:21:16 +0200 (CEST) Subject: [Python-checkins] r54636 - svn:log Message-ID: <20070331192116.F38821E400F@bag.python.org> Author: georg.brandl Revision: 54636 Property Name: svn:log New Property Value: Bug #1655392: don't add -L/usr/lib/pythonX.Y/config to the LDFLAGS returned by python-config if Python was built with --enable-shared because that prevented the shared library from being used. (backport from rev. 54634) From python-checkins at python.org Sat Mar 31 21:31:39 2007 From: python-checkins at python.org (collin.winter) Date: Sat, 31 Mar 2007 21:31:39 +0200 (CEST) Subject: [Python-checkins] r54637 - python/trunk/Lib/test/test_os.py Message-ID: <20070331193139.008481E4004@bag.python.org> Author: collin.winter Date: Sat Mar 31 21:31:34 2007 New Revision: 54637 Modified: python/trunk/Lib/test/test_os.py Log: Shut up an occaisonal buildbot error due to test files being left around. Modified: python/trunk/Lib/test/test_os.py ============================================================================== --- python/trunk/Lib/test/test_os.py (original) +++ python/trunk/Lib/test/test_os.py Sat Mar 31 21:31:34 2007 @@ -373,6 +373,14 @@ class MakedirTests (unittest.TestCase): def setUp(self): + try: + os.rmdir(test_support.TESTFN) + except OSError: + pass + try: + os.unlink(test_support.TESTFN) + except OSError: + pass os.mkdir(test_support.TESTFN) def test_makedir(self): From collinw at gmail.com Sat Mar 31 21:34:12 2007 From: collinw at gmail.com (Collin Winter) Date: Sat, 31 Mar 2007 14:34:12 -0500 Subject: [Python-checkins] buildbot warnings in x86 W2k trunk In-Reply-To: <20070331192056.383531E400D@bag.python.org> References: <20070331192056.383531E400D@bag.python.org> Message-ID: <43aa6ff70703311234v399e4240uddf6f11d3439639@mail.gmail.com> On 3/31/07, buildbot at python.org wrote: > ERROR: test_makedir (test.test_os.MakedirTests) > ---------------------------------------------------------------------- > > Traceback (most recent call last): > File "C:\trentm\data\buildbot\python-slave\trunk.mick-windows\build\lib\test\test_os.py", line 376, in setUp > os.mkdir(test_support.TESTFN) > WindowsError: [Error 183] Cannot create a file when that file already exists: '@test' r54637 will hopefully shut this up. Collin Winter From buildbot at python.org Sat Mar 31 22:05:37 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 31 Mar 2007 20:05:37 +0000 Subject: [Python-checkins] buildbot warnings in x86 Ubuntu edgy (icc) trunk Message-ID: <20070331200537.254BB1E4004@bag.python.org> The Buildbot has detected a new failure of x86 Ubuntu edgy (icc) trunk. Full details are available at: http://www.python.org/dev/buildbot/all/x86%2520Ubuntu%2520edgy%2520%2528icc%2529%2520trunk/builds/1213 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: andrew.kuchling,georg.brandl,neal.norwitz Build had warnings: warnings test Excerpt from the test logfile: 1 test failed: test_timeout sincerely, -The Buildbot From python-checkins at python.org Sat Mar 31 22:27:52 2007 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 31 Mar 2007 22:27:52 +0200 (CEST) Subject: [Python-checkins] r54638 - sandbox/trunk/abc/abc.py sandbox/trunk/abc/test_abc.py Message-ID: <20070331202752.621771E4004@bag.python.org> Author: guido.van.rossum Date: Sat Mar 31 22:27:51 2007 New Revision: 54638 Added: sandbox/trunk/abc/test_abc.py (contents, props changed) Modified: sandbox/trunk/abc/abc.py Log: Create some unit tests. Add some docs to the abstractmethod decorator. Modified: sandbox/trunk/abc/abc.py ============================================================================== --- sandbox/trunk/abc/abc.py (original) +++ sandbox/trunk/abc/abc.py Sat Mar 31 22:27:51 2007 @@ -3,8 +3,8 @@ """Abstract Base Classes experiment. Note: this depends on the brand new Py3k feature that object.__ne__() -is implemented by calling object.__eq__() and reversing the outcome -(unless NotImplemented). +is implemented by calling __eq__() and reversing the outcome (unless +NotImplemented). XXX Should we use argument annotations here? @@ -18,27 +18,73 @@ def abstractmethod(funcobj): - """A decorator indicating abstract methods.""" + """A decorator indicating abstract methods. + + Requires that the class (directly or indirectly) derives from + Abstract, and that the metaclass is AbstractClass or derived from it + (deriving from Abstract ensure this). A class deriving from + Abstract cannot be instantiated unless all of its abstract methods + are overridden. The abstract methods can be called using any of the + the normal 'super' call mechanisms. + + Usage: + + class C(Abstract): + @abstractmethod + def my_abstract_method(self, ...): + ... + + When combining this with other decorators, this should come last: + + class C(Abstract): + @classmethod + @abstractmethod + def my_abstract_class_method(self, ...): + ... + """ funcobj.__abstractmethod__ = True return funcobj class AbstractClass(type): + """Metaclass to support the abstractmethod decorator.""" + def __new__(mcls, name, bases, namespace): - obj = super(AbstractClass, mcls).__new__(mcls, name, bases, namespace) + cls = super(AbstractClass, mcls).__new__(mcls, name, bases, namespace) abstracts = set() for base in bases: abstracts.update(getattr(base, "__abstractmethods__", set())) for name, value in namespace.items(): if getattr(value, "__abstractmethod__", False): abstracts.add(name) - obj.__abstractmethods__ = abstracts - return obj + cls.__abstractmethods__ = abstracts + return cls + + +class AbstractInstantiationError(TypeError): + + """Exception raised when an abstract class is instantiated.""" + + def __init__(self, abstract_methods): + TypeError.__init__(self) + self.abstract_methods = abstract_methods + + def __str__(self): + msg = ", ".join(sorted(self.abstract_methods)) + return "Can't instantiate class with abstract method(s) %s" % msg + + def __repr__(self): + return "AbstractInstantiationError(%r)" % (self.abstract_methods,) class Abstract(metaclass=AbstractClass): + """Base class to support the abstractmethod decorator. + + This implicitly sets the metaclass to AbstractClass. + """ + def __new__(cls): bad = set() for name in cls.__abstractmethods__: @@ -46,8 +92,7 @@ if getattr(value, "__abstractmethod__", False): bad.add(name) if bad: - raise TypeError("Can't instantiate class with abstract methods %s" % - ", ".join(sorted(bad))) + raise AbstractInstantiationError(bad) return super(Abstract, cls).__new__(cls) @@ -499,29 +544,3 @@ if h == -1: h = -2 return h - - -### test ### - - -def _test(): - # Test that HashableSequence.__hash__() emulates tuple.__hash__(). - class C(HashableSequence): - def __new__(cls, values): - obj = super(C, cls).__new__(cls) - obj.__values = list(values) - return obj - def __len__(self): - return len(self.__values) - def __getitem__(self, i): - return self.__values[i] - for l in ([], [0], [1], [0, 1], - list(range(-sys.maxint, sys.maxint, 100000)), - "The quick brown fox jumps over the lazy dog".split()): - a = C(l) - ha = hash(a) - htl = hash(tuple(l)) - assert ha == htl, (l, ha, htl) - -if __name__ == "__main__": - _test() Added: sandbox/trunk/abc/test_abc.py ============================================================================== --- (empty file) +++ sandbox/trunk/abc/test_abc.py Sat Mar 31 22:27:51 2007 @@ -0,0 +1,43 @@ +#!/usr/bin/env python3.0 +"""Unit tests for abc.py.""" + +import sys +import unittest + +import abc + +class ABCTestCase(unittest.TestCase): + + def test_abstract_method_machinery(self): + class C(abc.Abstract): + @abc.abstractmethod + def foo(self): pass + def bar(self): pass + self.assertRaises(abc.AbstractInstantiationError, C) + class D(C): + def bar(self): pass + self.assertRaises(abc.AbstractInstantiationError, D) + class E(D): + def foo(self): pass + E() + + def test_hashable_sequence_hash_matches_tuple_hash(self): + class C(abc.HashableSequence): + def __new__(cls, values): + obj = super(C, cls).__new__(cls) + obj.__values = list(values) + return obj + def __len__(self): + return len(self.__values) + def __getitem__(self, i): + return self.__values[i] + for l in ([], [0], [1], [0, 1], + list(range(-sys.maxint, sys.maxint, 100000)), + "The quick brown fox jumps over the lazy dog".split()): + hcl = hash(C(l)) + htl = hash(tuple(l)) + self.assertEqual(hcl, htl, repr((l, hcl, htl))) + + +if __name__ == "__main__": + unittest.main() From python-checkins at python.org Sat Mar 31 22:31:05 2007 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 31 Mar 2007 22:31:05 +0200 (CEST) Subject: [Python-checkins] r54639 - sandbox/trunk/abc/abc.py Message-ID: <20070331203105.C209E1E4004@bag.python.org> Author: guido.van.rossum Date: Sat Mar 31 22:31:05 2007 New Revision: 54639 Modified: sandbox/trunk/abc/abc.py Log: Reindent using 4-space indents. Modified: sandbox/trunk/abc/abc.py ============================================================================== --- sandbox/trunk/abc/abc.py (original) +++ sandbox/trunk/abc/abc.py Sat Mar 31 22:31:05 2007 @@ -18,82 +18,82 @@ def abstractmethod(funcobj): - """A decorator indicating abstract methods. + """A decorator indicating abstract methods. - Requires that the class (directly or indirectly) derives from - Abstract, and that the metaclass is AbstractClass or derived from it - (deriving from Abstract ensure this). A class deriving from - Abstract cannot be instantiated unless all of its abstract methods - are overridden. The abstract methods can be called using any of the - the normal 'super' call mechanisms. - - Usage: - - class C(Abstract): - @abstractmethod - def my_abstract_method(self, ...): - ... - - When combining this with other decorators, this should come last: - - class C(Abstract): - @classmethod - @abstractmethod - def my_abstract_class_method(self, ...): - ... - """ - funcobj.__abstractmethod__ = True - return funcobj + Requires that the class (directly or indirectly) derives from + Abstract, and that the metaclass is AbstractClass or derived from it + (deriving from Abstract ensure this). A class deriving from + Abstract cannot be instantiated unless all of its abstract methods + are overridden. The abstract methods can be called using any of the + the normal 'super' call mechanisms. + + Usage: + + class C(Abstract): + @abstractmethod + def my_abstract_method(self, ...): + ... + + When combining this with other decorators, this should come last: + + class C(Abstract): + @classmethod + @abstractmethod + def my_abstract_class_method(self, ...): + ... + """ + funcobj.__abstractmethod__ = True + return funcobj class AbstractClass(type): - """Metaclass to support the abstractmethod decorator.""" + """Metaclass to support the abstractmethod decorator.""" - def __new__(mcls, name, bases, namespace): - cls = super(AbstractClass, mcls).__new__(mcls, name, bases, namespace) - abstracts = set() - for base in bases: - abstracts.update(getattr(base, "__abstractmethods__", set())) - for name, value in namespace.items(): - if getattr(value, "__abstractmethod__", False): - abstracts.add(name) - cls.__abstractmethods__ = abstracts - return cls + def __new__(mcls, name, bases, namespace): + cls = super(AbstractClass, mcls).__new__(mcls, name, bases, namespace) + abstracts = set() + for base in bases: + abstracts.update(getattr(base, "__abstractmethods__", set())) + for name, value in namespace.items(): + if getattr(value, "__abstractmethod__", False): + abstracts.add(name) + cls.__abstractmethods__ = abstracts + return cls class AbstractInstantiationError(TypeError): - """Exception raised when an abstract class is instantiated.""" + """Exception raised when an abstract class is instantiated.""" - def __init__(self, abstract_methods): - TypeError.__init__(self) - self.abstract_methods = abstract_methods - - def __str__(self): - msg = ", ".join(sorted(self.abstract_methods)) - return "Can't instantiate class with abstract method(s) %s" % msg + def __init__(self, abstract_methods): + TypeError.__init__(self) + self.abstract_methods = abstract_methods + + def __str__(self): + msg = ", ".join(sorted(self.abstract_methods)) + return "Can't instantiate class with abstract method(s) %s" % msg - def __repr__(self): - return "AbstractInstantiationError(%r)" % (self.abstract_methods,) + def __repr__(self): + return "AbstractInstantiationError(%r)" % (self.abstract_methods,) class Abstract(metaclass=AbstractClass): - """Base class to support the abstractmethod decorator. + """Base class to support the abstractmethod decorator. - This implicitly sets the metaclass to AbstractClass. - """ + This implicitly sets the metaclass to AbstractClass. + """ - def __new__(cls): - bad = set() - for name in cls.__abstractmethods__: - value = getattr(cls, name, None) - if getattr(value, "__abstractmethod__", False): - bad.add(name) - if bad: - raise AbstractInstantiationError(bad) - return super(Abstract, cls).__new__(cls) + def __new__(cls): + bad = set() + for name in cls.__abstractmethods__: + value = getattr(cls, name, None) + if getattr(value, "__abstractmethod__", False): + bad.add(name) + if bad: + raise AbstractInstantiationError(bad) + return super(Abstract, cls).__new__(cls) ### BASICS ### @@ -101,39 +101,39 @@ class Hashable(Abstract): - """A hashable has one method, __hash__().""" + """A hashable has one method, __hash__().""" - @abstractmethod - def __hash__(self): - return 0 + @abstractmethod + def __hash__(self): + return 0 class Iterable(Abstract): - """An iterable has one method, __iter__().""" + """An iterable has one method, __iter__().""" - @abstractmethod - def __iter__(self): - return Iterator() + @abstractmethod + def __iter__(self): + return Iterator() class Iterator(Iterable): - """An iterator has two methods, __iter__() and next().""" + """An iterator has two methods, __iter__() and next().""" - @abstractmethod - def next(self): - raise StopIteration + @abstractmethod + def next(self): + raise StopIteration - def __iter__(self): - return self + def __iter__(self): + return self class Sizeable(Abstract): - @abstractmethod - def __len__(self): - return 0 + @abstractmethod + def __len__(self): + return 0 ### SETS ### @@ -141,101 +141,101 @@ class BasicSet(Abstract): - # XXX Alternative name: Container? Oracle (as in Delphi's Oracle)? + # XXX Alternative name: Container? Oracle (as in Delphi's Oracle)? - """A basic set has __contains__() and that's it.""" + """A basic set has __contains__() and that's it.""" - @abstractmethod - def __contains__(self, elem): - return False + @abstractmethod + def __contains__(self, elem): + return False class IterableSet(BasicSet, Iterable): - """An iterable set is a basic set that is also iterable. + """An iterable set is a basic set that is also iterable. - It may not have a length though; it may be infinite! + It may not have a length though; it may be infinite! - XXX Do we care about potentially infinite sets, or sets of - indeterminate size? - """ + XXX Do we care about potentially infinite sets, or sets of + indeterminate size? + """ class SizeableSet(IterableSet, Sizeable): - """A sizeable set is an iterable set that has a finite, known size. + """A sizeable set is an iterable set that has a finite, known size. - This enables a generic implementation of equality and ordering based - on set inclusion. + This enables a generic implementation of equality and ordering based + on set inclusion. - I don't see a use case for a non-iterable set that has a size. + I don't see a use case for a non-iterable set that has a size. - The idea here is that all you have to do is redefine __le__ and then - the other operations will automatically follow suit. - """ - - def __le__(self, other): - if not isinstance(other, SizeableSet): - return NotImplemented - if len(self) > len(other): - return False - for elem in self: - if elem not in other: - return False - return True + The idea here is that all you have to do is redefine __le__ and then + the other operations will automatically follow suit. + """ - def __lt__(self, other): - if not isinstance(other, SizeableSet): - return NotImplemented - return len(self) < len(other) and self.__le__(other) - - def __eq__(self, other): - if not isinstance(other, SizeableSet): - return NotImplemented - return len(self) == len(other) and self.__le__(other) - - # XXX Should we define __ge__ and __gt__ too? - - # XXX The following implementations of &, |, ^, - return frozen sets - # because we have to pick a concrete type. They are allowed to - # return any subclass of SizeableSet (but SizeableSet is not a - # concrete implementation). - - def __and__(self, other): - new = set(self) - new.intersection_update(other) - return frozenset(new) - - def __or__(self, other): - new = set(self) - new.update(other) - return frozenset(new) - - def __xor__(self, other): - new = set(self) - new.symmetric_difference_update(other) - return frozenset(new) - - def __sub__(self, other): - new = set(self) - new.difference_update(other) - return frozenset(new) + def __le__(self, other): + if not isinstance(other, SizeableSet): + return NotImplemented + if len(self) > len(other): + return False + for elem in self: + if elem not in other: + return False + return True + + def __lt__(self, other): + if not isinstance(other, SizeableSet): + return NotImplemented + return len(self) < len(other) and self.__le__(other) + + def __eq__(self, other): + if not isinstance(other, SizeableSet): + return NotImplemented + return len(self) == len(other) and self.__le__(other) + + # XXX Should we define __ge__ and __gt__ too? + + # XXX The following implementations of &, |, ^, - return frozen sets + # because we have to pick a concrete type. They are allowed to + # return any subclass of SizeableSet (but SizeableSet is not a + # concrete implementation). + + def __and__(self, other): + new = set(self) + new.intersection_update(other) + return frozenset(new) + + def __or__(self, other): + new = set(self) + new.update(other) + return frozenset(new) + + def __xor__(self, other): + new = set(self) + new.symmetric_difference_update(other) + return frozenset(new) + + def __sub__(self, other): + new = set(self) + new.difference_update(other) + return frozenset(new) class HashableSet(SizeableSet, Hashable): - def __hash__(self): - """The hash value must match __eq__. + def __hash__(self): + """The hash value must match __eq__. - All sets ought to compare equal if they contain the same elements, - regardless of how they are implemented, and regardless of the - order of the elements; so there's not much freedom for __eq__ or - __hash__. We just XOR the hash of the elements. - """ - h = 0 - for elem in self: - h ^= hash(elem) - return h + All sets ought to compare equal if they contain the same elements, + regardless of how they are implemented, and regardless of the + order of the elements; so there's not much freedom for __eq__ or + __hash__. We just XOR the hash of the elements. + """ + h = 0 + for elem in self: + h ^= hash(elem) + return h # class set(SizeableSet) @@ -247,157 +247,157 @@ class BasicMapping(Abstract): - # XXX derive from (BasicSet)? + # XXX derive from (BasicSet)? - """A basic mapping has __getitem__(), __contains__() and get(). + """A basic mapping has __getitem__(), __contains__() and get(). - The idea is that you only need to override __getitem__(). + The idea is that you only need to override __getitem__(). - Other dict methods are not supported. - """ + Other dict methods are not supported. + """ - @abstractmethod - def __getitem__(self, key): - raise KeyError - - def get(self, key, default=None): - try: - return self[key] - except KeyError: - return default - - def __contains__(self, key): - try: - self[key] - return True - except KeyError: - return False + @abstractmethod + def __getitem__(self, key): + raise KeyError + + def get(self, key, default=None): + try: + return self[key] + except KeyError: + return default + + def __contains__(self, key): + try: + self[key] + return True + except KeyError: + return False class IterableMapping(BasicMapping, Iterable): - def keys(self): - return KeysView(self) + def keys(self): + return KeysView(self) - def items(self): - return ItemsView(self) + def items(self): + return ItemsView(self) - def values(self): - return ValuesView(self) + def values(self): + return ValuesView(self) class _MappingView: - def __init__(self, mapping): - self._mapping = mapping + def __init__(self, mapping): + self._mapping = mapping class KeysView(_MappingView, BasicSet): - def __iter__(self): - for key in self._mapping: - yield key + def __iter__(self): + for key in self._mapping: + yield key - def __contains__(self, key): - return key in self._mapping + def __contains__(self, key): + return key in self._mapping class ItemsView(_MappingView, BasicSet): - def __iter__(self): - for key in self._mapping: - yield key, self._mapping[key] - - def __contains__(self, item): - try: - key, value = item - except: - return False - try: - val = self._mapping[key] - except KeyError: - return False - return value == val + def __iter__(self): + for key in self._mapping: + yield key, self._mapping[key] + + def __contains__(self, item): + try: + key, value = item + except: + return False + try: + val = self._mapping[key] + except KeyError: + return False + return value == val class ValuesView(_MappingView): - # Note: does not derive from BasicSet, and does not implement __contains__! + # Note: does not derive from BasicSet, and does not implement __contains__! - def __iter__(self): - for key in self._mapping: - yield self._mapping[key] + def __iter__(self): + for key in self._mapping: + yield self._mapping[key] class SizeableMapping(IterableMapping, Sizeable): - def keys(self): - return SizeableKeysView(self) + def keys(self): + return SizeableKeysView(self) - def items(self): - return SizeableItemsView(self) + def items(self): + return SizeableItemsView(self) - def values(self): - return SizeableValuesView(self) + def values(self): + return SizeableValuesView(self) - def __eq__(self, other): - if not isinstance(other, SizeableMapping): - return NotImplemented - if len(other) != len(self): - return False - # XXX Or: for key, value1 in self.items(): ? - for key in self: - value1 = self[key] - try: - value2 = other[key] - except KeyError: - return False - if value1 != value2: - return False - return True + def __eq__(self, other): + if not isinstance(other, SizeableMapping): + return NotImplemented + if len(other) != len(self): + return False + # XXX Or: for key, value1 in self.items(): ? + for key in self: + value1 = self[key] + try: + value2 = other[key] + except KeyError: + return False + if value1 != value2: + return False + return True class _SizeableMappingView(_MappingView, Sizeable): - def __len__(self): - return len(self._mapping) + def __len__(self): + return len(self._mapping) class SizeableKeysView(_SizeableMappingView, KeysView, SizeableSet): - pass + pass class SizeableItemsView(_SizeableMappingView, ItemsView, SizeableSet): - pass + pass class SizeableValuesView(_SizeableMappingView, ValuesView): - def __eq__(self, other): - if not (isinstance(other, Sizeable) and isinstance(other, Iterable)): - return NotImplemented - if len(self) != len(other): - return False - # XXX This is slow. Sometimes this could be optimized, but these - # are the semantics: we can't depend on the values to be hashable - # or comparable. - o_values = list(other) - for value in self: - for i, o_value in enumerate(o_values): - if value == o_value: - del o_values[i] - break - else: - return False - assert not o_values # self must have mutated somehow - return True - - def __contains__(self, value): - # This is slow, but these are the semantics. - for elem in self: - if elem == value: + def __eq__(self, other): + if not (isinstance(other, Sizeable) and isinstance(other, Iterable)): + return NotImplemented + if len(self) != len(other): + return False + # XXX This is slow. Sometimes this could be optimized, but these + # are the semantics: we can't depend on the values to be hashable + # or comparable. + o_values = list(other) + for value in self: + for i, o_value in enumerate(o_values): + if value == o_value: + del o_values[i] + break + else: + return False + assert not o_values # self must have mutated somehow return True - return False + + def __contains__(self, value): + # This is slow, but these are the semantics. + for elem in self: + if elem == value: + return True + return False ### SEQUENCES ### @@ -405,142 +405,142 @@ class Sequence(Sizeable, Iterable): - """A minimal sequence. + """A minimal sequence. - I'm not bothering with an unsized version; I don't see a use case. + I'm not bothering with an unsized version; I don't see a use case. - Concrete subclasses must override __new__ or __init__, __getitem__, - and __len__; they might want to override __add__ and __mul__. The - constructor signature is expected to support a single argument - giving an iterable providing the elements. - """ - - def __index(self, i): - # Internal helper to raise TypeError for non-integer(-castable) values - if not isinstance(i, int): - if not hasattr(i, "__index__"): - raise TypeError - i = i.__index__() - if not isinstance(i, int): - raise TypeError - return i - - @abstractmethod - def __getitem__(self, index): - if isinstance(index, slice): - return self.__getslice(index) - index = self.__index(index) - raise IndexError - - def __getslice(self, slc): - # XXX Would be nice to make this generally available? - start, stop, step = slc.start, slc.stop, slc.step - for index in start, stop, step: - if index is not None: - self.__index(index) - if step is None: - step = 1 - if step == 0: - raise ValueError - if step < 0: - if start is None: - start = len(self) - 1 - if stop is None: - stop = -1 - else: - if start is None: - start = 0 - if stop is None: - stop = len(self) - return self.__class__(self[i] for i in range(start, stop, step)) - - @abstractmethod - def __len__(self): - return 0 - - def __iter__(self): - i = 0 - while i < len(self): - yield self[i] - i += 1 - - def __reversed__(self): - i = len(self) - while i > 0: - i -= 1 - yield self[i] - - def index(self, value): - for i, elem in enumerate(self): - if elem == value: - return i - raise ValueError + Concrete subclasses must override __new__ or __init__, __getitem__, + and __len__; they might want to override __add__ and __mul__. The + constructor signature is expected to support a single argument + giving an iterable providing the elements. + """ - def count(self, value): - return sum(1 for elem in self if elem == value) + def __index(self, i): + # Internal helper to raise TypeError for non-integer(-castable) values + if not isinstance(i, int): + if not hasattr(i, "__index__"): + raise TypeError + i = i.__index__() + if not isinstance(i, int): + raise TypeError + return i - def __add__(self, other): - if not isinstance(other, Sequence): - return NotImplemented - return self.__class__(elem for seq in (self, other) for elem in seq) - - def __mul__(self, repeat): - # XXX Looks like we need an ABC to indicate integer-ness... - if not isinstance(repeat, int) and not hasattr(repeat, "__index__"): - return NotImplemented - repeat = self.__index(repeat) - return self.__class__(elem for i in range(repeat) for elem in self) - - def __eq__(self, other): - if not isinstance(other, Sequence): - return NotImplemented - if len(self) != len(other): - return False - for a, b in zip(self, other): - if a == b: - continue - return False - return len(self) == len(other) - - def __lt__(self, other): - if not isinstance(other, Sequence): - return NotImplemented - for a, b in zip(self, other): - if a == b: - continue - return a < b - return len(self) < len(other) - - def __le__(self, other): - if not isinstance(other, Sequence): - return NotImplemented - for a, b in zip(self, other): - if a == b: - continue - return a < b - return len(self) <= len(other) + @abstractmethod + def __getitem__(self, index): + if isinstance(index, slice): + return self.__getslice(index) + index = self.__index(index) + raise IndexError + + def __getslice(self, slc): + # XXX Would be nice to make this generally available? + start, stop, step = slc.start, slc.stop, slc.step + for index in start, stop, step: + if index is not None: + self.__index(index) + if step is None: + step = 1 + if step == 0: + raise ValueError + if step < 0: + if start is None: + start = len(self) - 1 + if stop is None: + stop = -1 + else: + if start is None: + start = 0 + if stop is None: + stop = len(self) + return self.__class__(self[i] for i in range(start, stop, step)) + + @abstractmethod + def __len__(self): + return 0 + + def __iter__(self): + i = 0 + while i < len(self): + yield self[i] + i += 1 + + def __reversed__(self): + i = len(self) + while i > 0: + i -= 1 + yield self[i] + + def index(self, value): + for i, elem in enumerate(self): + if elem == value: + return i + raise ValueError + + def count(self, value): + return sum(1 for elem in self if elem == value) + + def __add__(self, other): + if not isinstance(other, Sequence): + return NotImplemented + return self.__class__(elem for seq in (self, other) for elem in seq) + + def __mul__(self, repeat): + # XXX Looks like we need an ABC to indicate integer-ness... + if not isinstance(repeat, int) and not hasattr(repeat, "__index__"): + return NotImplemented + repeat = self.__index(repeat) + return self.__class__(elem for i in range(repeat) for elem in self) + + def __eq__(self, other): + if not isinstance(other, Sequence): + return NotImplemented + if len(self) != len(other): + return False + for a, b in zip(self, other): + if a == b: + continue + return False + return len(self) == len(other) + + def __lt__(self, other): + if not isinstance(other, Sequence): + return NotImplemented + for a, b in zip(self, other): + if a == b: + continue + return a < b + return len(self) < len(other) + + def __le__(self, other): + if not isinstance(other, Sequence): + return NotImplemented + for a, b in zip(self, other): + if a == b: + continue + return a < b + return len(self) <= len(other) class HashableSequence(Sequence, Hashable): - def __hash__(self): - """The hash value must match __eq__. + def __hash__(self): + """The hash value must match __eq__. - Since we want sequences to be equal iff their elements are equal - (regardless of the sequence type), this algorithm is (XXX - hopefully) identical to tuple.__hash__(). - """ - mask = sys.maxint*2 + 1 - mult = 1000003 - h = 0x345678 - n = len(self) - for i, elem in enumerate(self): - h = ((h ^ hash(elem)) * mult) & mask - mult = (mult + (82520 - 2 + 2*(n-i))) & mask - h += 97531 - h &= mask - if h > sys.maxint: - h -= mask + 1 - if h == -1: - h = -2 - return h + Since we want sequences to be equal iff their elements are equal + (regardless of the sequence type), this algorithm is (XXX + hopefully) identical to tuple.__hash__(). + """ + mask = sys.maxint*2 + 1 + mult = 1000003 + h = 0x345678 + n = len(self) + for i, elem in enumerate(self): + h = ((h ^ hash(elem)) * mult) & mask + mult = (mult + (82520 - 2 + 2*(n-i))) & mask + h += 97531 + h &= mask + if h > sys.maxint: + h -= mask + 1 + if h == -1: + h = -2 + return h From python-checkins at python.org Sat Mar 31 22:45:45 2007 From: python-checkins at python.org (guido.van.rossum) Date: Sat, 31 Mar 2007 22:45:45 +0200 (CEST) Subject: [Python-checkins] r54640 - sandbox/trunk/abc Message-ID: <20070331204545.C22EF1E4009@bag.python.org> Author: guido.van.rossum Date: Sat Mar 31 22:45:45 2007 New Revision: 54640 Modified: sandbox/trunk/abc/ (props changed) Log: Set the standard svn:ignore property. From buildbot at python.org Sat Mar 31 22:51:44 2007 From: buildbot at python.org (buildbot at python.org) Date: Sat, 31 Mar 2007 20:51:44 +0000 Subject: [Python-checkins] buildbot warnings in ia64 Ubuntu trunk trunk Message-ID: <20070331205145.2F1EC1E4004@bag.python.org> The Buildbot has detected a new failure of ia64 Ubuntu trunk trunk. Full details are available at: http://www.python.org/dev/buildbot/all/ia64%2520Ubuntu%2520trunk%2520trunk/builds/546 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: collin.winter Build had warnings: warnings failed slave lost sincerely, -The Buildbot From python-checkins at python.org Sat Mar 31 23:02:43 2007 From: python-checkins at python.org (marc-andre.lemburg) Date: Sat, 31 Mar 2007 23:02:43 +0200 (CEST) Subject: [Python-checkins] r54641 - python/branches/release25-maint/Lib/distutils/__init__.py Message-ID: <20070331210243.DA6F51E4004@bag.python.org> Author: marc-andre.lemburg Date: Sat Mar 31 23:02:43 2007 New Revision: 54641 Modified: python/branches/release25-maint/Lib/distutils/__init__.py Log: Bump the patch level version of distutils since there were a few bug fixes since the 2.5.0 release. Backport of r54615. Modified: python/branches/release25-maint/Lib/distutils/__init__.py ============================================================================== --- python/branches/release25-maint/Lib/distutils/__init__.py (original) +++ python/branches/release25-maint/Lib/distutils/__init__.py Sat Mar 31 23:02:43 2007 @@ -20,4 +20,4 @@ # In general, major and minor version should loosely follow the Python # version number the distutils code was shipped with. # -__version__ = "2.5.0" +__version__ = "2.5.1" From python-checkins at python.org Sat Mar 31 23:26:28 2007 From: python-checkins at python.org (sean.reifschneider) Date: Sat, 31 Mar 2007 23:26:28 +0200 (CEST) Subject: [Python-checkins] r54642 - sandbox/trunk/pybch/Tests/stringbench2.py Message-ID: <20070331212628.635391E4005@bag.python.org> Author: sean.reifschneider Date: Sat Mar 31 23:26:25 2007 New Revision: 54642 Added: sandbox/trunk/pybch/Tests/stringbench2.py (contents, props changed) Log: Adding files in preparation for removing pybch. Added: sandbox/trunk/pybch/Tests/stringbench2.py ============================================================================== --- (empty file) +++ sandbox/trunk/pybch/Tests/stringbench2.py Sat Mar 31 23:26:25 2007 @@ -0,0 +1,1199 @@ + +# Various microbenchmarks comparing unicode and byte string performance + +import timeit +import itertools +import operator +import re +import sys +import datetime +import optparse +from TestHelpers import Test + +REPEAT = 1 +REPEAT = 3 +#REPEAT = 7 + +_RANGE_1000 = range(1) +_RANGE_1000 = range(1) +_RANGE_100 = range(1) +_RANGE_10 = range(1) + +dups = {} +def bench(s, group, repeat_count): + def blah(f): + if f.__name__ in dups: + raise AssertionError("Multiple functions with same name: %r" % + (f.__name__,)) + dups[f.__name__] = 1 + f.comment = s + f.is_bench = True + f.group = group + f.repeat_count = repeat_count + return f + return blah + +def uses_re(f): + f.uses_re = True + +####### 'in' comparisons + + at bench('"A" in "A"*1000', "early match, single character", 1000) +def in_test_quick_match_single_character(STR): + s1 = STR("A" * 1000) + s2 = STR("A") + for x in _RANGE_1000: + s2 in s1 + + at bench('"B" in "A"*1000', "no match, single character", 1000) +def in_test_no_match_single_character(STR): + s1 = STR("A" * 1000) + s2 = STR("B") + for x in _RANGE_1000: + s2 in s1 + + + at bench('"AB" in "AB"*1000', "early match, two characters", 1000) +def in_test_quick_match_two_characters(STR): + s1 = STR("AB" * 1000) + s2 = STR("AB") + for x in _RANGE_1000: + s2 in s1 + + at bench('"BC" in "AB"*1000', "no match, two characters", 1000) +def in_test_no_match_two_character(STR): + s1 = STR("AB" * 1000) + s2 = STR("BC") + for x in _RANGE_1000: + s2 in s1 + + at bench('"BC" in ("AB"*300+"C")', "late match, two characters", 1000) +def in_test_slow_match_two_characters(STR): + s1 = STR("AB" * 300+"C") + s2 = STR("BC") + for x in _RANGE_1000: + s2 in s1 + + at bench('s="ABC"*33; (s+"E") in ((s+"D")*300+s+"E")', + "late match, 100 characters", 100) +def in_test_slow_match_100_characters(STR): + m = STR("ABC"*33) + s1 = (m+"D")*300 + m+"E" + s2 = m+"E" + for x in _RANGE_100: + s2 in s1 + +# Try with regex + at uses_re + at bench('s="ABC"*33; re.compile(s+"D").search((s+"D")*300+s+"E")', + "late match, 100 characters", 100) +def re_test_slow_match_100_characters(STR): + m = STR("ABC"*33) + s1 = (m+"D")*300 + m+"E" + s2 = m+"E" + pat = re.compile(s2) + search = pat.search + for x in _RANGE_100: + search(s1) + + +#### same tests as 'in' but use 'find' + +# XXX: TODO: Add rfind + + + + at bench('("A"*1000).find("A")', "early match, single character", 1000) +def find_quick_match_single_character(STR): + s1 = STR("A" * 1000) + s2 = STR("A") + s1_find = s1.find + for x in _RANGE_1000: + s1_find(s2) + + at bench('("A"*1000).find("B")', "no match, single character", 1000) +def find_test_no_match_single_character(STR): + s1 = STR("A" * 1000) + s2 = STR("B") + s1_find = s1.find + for x in _RANGE_1000: + s1_find(s2) + + + at bench('("AB"*1000).find("AB")', "early match, two characters", 1000) +def find_test_quick_match_two_characters(STR): + s1 = STR("AB" * 1000) + s2 = STR("AB") + s1_find = s1.find + for x in _RANGE_1000: + s1_find(s2) + + at bench('("AB"*1000).find("BC")', "no match, two characters", 1000) +def find_test_no_match_two_character(STR): + s1 = STR("AB" * 1000) + s2 = STR("BC") + s1_find = s1.find + for x in _RANGE_1000: + s1_find(s2) + + at bench('("AB"*300+"C").find("BC")', "late match, two characters", 1000) +def find_test_slow_match_two_characters(STR): + s1 = STR("AB" * 300+"C") + s2 = STR("BC") + s1_find = s1.find + for x in _RANGE_1000: + s1_find(s2) + + at bench('s="ABC"*33; ((s+"D")*500+s+"E").find(s)', + "late match, 100 characters", 100) +def find_test_slow_match_100_characters(STR): + m = STR("ABC"*33) + s1 = (m+"D")*500 + m+"E" + s2 = m+"E" + s1_find = s1.find + for x in _RANGE_100: + s1_find(s2) + +#### Now with index. +# Skip the ones which fail because that would include exception overhead. +# Add rindex tests. + + + at bench('("A"*1000).index("A")', "early match, single character", 1000) +def index_test_quick_match_single_character(STR): + s1 = STR("A" * 1000) + s2 = STR("A") + s1_index = s1.index + for x in _RANGE_1000: + s1_index(s2) + + + at bench('("AB"*1000).index("AB")', "early match, two characters", 1000) +def index_test_quick_match_two_characters(STR): + s1 = STR("AB" * 1000) + s2 = STR("AB") + s1_index = s1.index + for x in _RANGE_1000: + s1_index(s2) + + at bench('("AB"*300+"C").index("BC")', "late match, two characters", 1000) +def index_test_slow_match_two_characters(STR): + s1 = STR("AB" * 300+"C") + s2 = STR("BC") + s1_index = s1.index + for x in _RANGE_1000: + s1_index(s2) + + at bench('s="ABC"*33; ((s+"D")*500+s+"E").index(s)', + "late match, 100 characters", 100) +def index_test_slow_match_100_characters(STR): + m = STR("ABC"*33) + s1 = (m+"D")*500 + m+"E" + s2 = m+"E" + s1_index = s1.index + for x in _RANGE_100: + s1_index(s2) + +#### Benchmark the operator-based methods + + at bench('"A"*10', "repeat 1 character 10 times", 1000) +def repeat_single_10_times(STR): + s = STR("A") + for x in _RANGE_1000: + s * 10 + + at bench('"A"*1000', "repeat 1 character 1000 times", 1000) +def repeat_single_1000_times(STR): + s = STR("A") + for x in _RANGE_1000: + s * 1000 + + at bench('"ABCDE"*10', "repeat 5 characters 10 times", 1000) +def repeat_5_10_times(STR): + s = STR("ABCDE") + for x in _RANGE_1000: + s * 10 + + at bench('"ABCDE"*1000', "repeat 5 characters 1000 times", 1000) +def repeat_5_1000_times(STR): + s = STR("ABCDE") + for x in _RANGE_1000: + s * 1000 + +# + for concat + + at bench('"Andrew"+"Dalke"', "concat two strings", 1000) +def concat_two_strings(STR): + s1 = STR("Andrew") + s2 = STR("Dalke") + for x in _RANGE_1000: + s1+s2 + + at bench('s1+s2+s3+s4+...+s20', "concat 20 strings of words length 4 to 15", + 1000) +def concat_many_strings(STR): + s1=STR('TIXSGYNREDCVBHJ') + s2=STR('PUMTLXBZVDO') + s3=STR('FVZNJ') + s4=STR('OGDXUW') + s5=STR('WEIMRNCOYVGHKB') + s6=STR('FCQTNMXPUZH') + s7=STR('TICZJYRLBNVUEAK') + s8=STR('REYB') + s9=STR('PWUOQ') + s10=STR('EQHCMKBS') + s11=STR('AEVDFOH') + s12=STR('IFHVD') + s13=STR('JGTCNLXWOHQ') + s14=STR('ITSKEPYLROZAWXF') + s15=STR('THEK') + s16=STR('GHPZFBUYCKMNJIT') + s17=STR('JMUZ') + s18=STR('WLZQMTB') + s19=STR('KPADCBW') + s20=STR('TNJHZQAGBU') + for x in _RANGE_1000: + (s1 + s2+ s3+ s4+ s5+ s6+ s7+ s8+ s9+s10+ + s11+s12+s13+s14+s15+s16+s17+s18+s19+s20) + + +#### Benchmark join + + at bench('"A".join("")', + "join empty string, with 1 character sep", 100) +def join_empty_single(STR): + sep = STR("A") + s2 = STR("") + sep_join = sep.join + for x in _RANGE_100: + sep_join(s2) + + at bench('"ABCDE".join("")', + "join empty string, with 5 character sep", 100) +def join_empty_5(STR): + sep = STR("ABCDE") + s2 = STR("") + sep_join = sep.join + for x in _RANGE_100: + sep_join(s2) + + at bench('"A".join("ABC..Z")', + "join string with 26 characters, with 1 character sep", 1000) +def join_alphabet_single(STR): + sep = STR("A") + s2 = STR("ABCDEFGHIJKLMnOPQRSTUVWXYZ") + sep_join = sep.join + for x in _RANGE_1000: + sep_join(s2) + + at bench('"ABCDE".join("ABC..Z")', + "join string with 26 characters, with 5 character sep", 1000) +def join_alphabet_5(STR): + sep = STR("ABCDE") + s2 = STR("ABCDEFGHIJKLMnOPQRSTUVWXYZ") + sep_join = sep.join + for x in _RANGE_1000: + sep_join(s2) + + at bench('"A".join(list("ABC..Z"))', + "join list of 26 characters, with 1 character sep", 1000) +def join_alphabet_list_single(STR): + sep = STR("A") + s2 = list(STR("ABCDEFGHIJKLMnOPQRSTUVWXYZ")) + sep_join = sep.join + for x in _RANGE_1000: + sep_join(s2) + + at bench('"ABCDE".join(list("ABC..Z"))', + "join list of 26 characters, with 5 character sep", 1000) +def join_alphabet_list_five(STR): + sep = STR("ABCDE") + s2 = list(STR("ABCDEFGHIJKLMnOPQRSTUVWXYZ")) + sep_join = sep.join + for x in _RANGE_1000: + sep_join(s2) + + at bench('"A".join(["Bob"]*100))', + "join list of 100 words, with 1 character sep", 1000) +def join_100_words_single(STR): + sep = STR("A") + s2 = [STR("Bob")]*100 + sep_join = sep.join + for x in _RANGE_1000: + sep_join(s2) + + at bench('"ABCDE".join(["Bob"]*100))', + "join list of 100 words, with 5 character sep", 1000) +def join_100_words_5(STR): + sep = STR("ABCDE") + s2 = [STR("Bob")]*100 + sep_join = sep.join + for x in _RANGE_1000: + sep_join(s2) + +#### split tests + + at bench('("Here are some words. "*2).split()', "split whitespace (small)", 1000) +def whitespace_split(STR): + s = STR("Here are some words. "*2) + s_split = s.split + for x in _RANGE_1000: + s_split() + + at bench('("Here are some words. "*2).rsplit()', "split whitespace (small)", 1000) +def whitespace_rsplit(STR): + s = STR("Here are some words. "*2) + s_rsplit = s.rsplit + for x in _RANGE_1000: + s_rsplit() + + at bench('("Here are some words. "*2).split(None, 1)', + "split 1 whitespace", 1000) +def whitespace_split_1(STR): + s = STR("Here are some words. "*2) + s_split = s.split + N = None + for x in _RANGE_1000: + s_split(N, 1) + + at bench('("Here are some words. "*2).rsplit(None, 1)', + "split 1 whitespace", 1000) +def whitespace_rsplit_1(STR): + s = STR("Here are some words. "*2) + s_rsplit = s.rsplit + N = None + for x in _RANGE_1000: + s_rsplit(N, 1) + +human_text = """\ +Python is a dynamic object-oriented programming language that can be +used for many kinds of software development. It offers strong support +for integration with other languages and tools, comes with extensive +standard libraries, and can be learned in a few days. Many Python +programmers report substantial productivity gains and feel the language +encourages the development of higher quality, more maintainable code. + +Python runs on Windows, Linux/Unix, Mac OS X, OS/2, Amiga, Palm +Handhelds, and Nokia mobile phones. Python has also been ported to the +Java and .NET virtual machines. + +Python is distributed under an OSI-approved open source license that +makes it free to use, even for commercial products. +"""*25 +human_text_unicode = unicode(human_text) +def _get_human_text(STR): + if STR is unicode: + return human_text_unicode + if STR is str: + return human_text + raise AssertionError + + at bench('human_text.split()', "split whitespace (huge)", 10) +def whitespace_split_huge(STR): + s = _get_human_text(STR) + s_split = s.split + for x in _RANGE_10: + s_split() + + at bench('human_text.rsplit()', "split whitespace (huge)", 10) +def whitespace_rsplit_huge(STR): + s = _get_human_text(STR) + s_rsplit = s.rsplit + for x in _RANGE_10: + s_rsplit() + + + + at bench('"this\\nis\\na\\ntest\\n".split("\\n")', "split newlines", 1000) +def newlines_split(STR): + s = STR("this\nis\na\ntest\n") + s_split = s.split + for x in _RANGE_1000: + s_split("\n") + + + at bench('"this\\nis\\na\\ntest\\n".rsplit("\\n")', "split newlines", 1000) +def newlines_rsplit(STR): + s = STR("this\nis\na\ntest\n") + s_rsplit = s.rsplit + for x in _RANGE_1000: + s_rsplit("\n") + + at bench('"this\\nis\\na\\ntest\\n".splitlines()', "split newlines", 1000) +def newlines_splitlines(STR): + s = STR("this\nis\na\ntest\n") + s_splitlines = s.splitlines + for x in _RANGE_1000: + s_splitlines() + +## split text with 2000 newlines + +def _make_2000_lines(): + import random + r = random.Random(100) + chars = map(chr, range(32, 128)) + i = 0 + while i < len(chars): + chars[i] = " " + i += r.randrange(9) + s = "".join(chars) + s = s*4 + words = [] + for i in range(2000): + start = r.randrange(96) + n = r.randint(5, 65) + words.append(s[start:start+n]) + return "\n".join(words)+"\n" + +_text_with_2000_lines = _make_2000_lines() +_text_with_2000_lines_unicode = unicode(_text_with_2000_lines) +def _get_2000_lines(STR): + if STR is unicode: + return _text_with_2000_lines_unicode + if STR is str: + return _text_with_2000_lines + raise AssertionError + + + at bench('"...text...".split("\\n")', "split 2000 newlines", 10) +def newlines_split_2000(STR): + s = _get_2000_lines(STR) + s_split = s.split + for x in _RANGE_10: + s_split("\n") + + at bench('"...text...".rsplit("\\n")', "split 2000 newlines", 10) +def newlines_rsplit_2000(STR): + s = _get_2000_lines(STR) + s_rsplit = s.rsplit + for x in _RANGE_10: + s_rsplit("\n") + + at bench('"...text...".splitlines()', "split 2000 newlines", 10) +def newlines_splitlines_2000(STR): + s = _get_2000_lines(STR) + s_splitlines = s.splitlines + for x in _RANGE_10: + s_splitlines() + + +## split text on "--" characters + at bench( + '"this--is--a--test--of--the--emergency--broadcast--system".split("--")', + "split on multicharacter separator (small)", 1000) +def split_multichar_sep_small(STR): + s = STR("this--is--a--test--of--the--emergency--broadcast--system") + s_split = s.split + for x in _RANGE_1000: + s_split("--") + at bench( + '"this--is--a--test--of--the--emergency--broadcast--system".rsplit("--")', + "split on multicharacter separator (small)", 1000) +def rsplit_multichar_sep_small(STR): + s = STR("this--is--a--test--of--the--emergency--broadcast--system") + s_rsplit = s.rsplit + for x in _RANGE_1000: + s_rsplit("--") + +## split dna text on "ACTAT" characters + at bench('dna.split("ACTAT")', + "split on multicharacter separator (dna)", 10) +def split_multichar_sep_dna(STR): + s = _get_dna(STR) + s_split = s.split + for x in _RANGE_10: + s_split("ACTAT") + + at bench('dna.rsplit("ACTAT")', + "split on multicharacter separator (dna)", 10) +def rsplit_multichar_sep_dna(STR): + s = _get_dna(STR) + s_rsplit = s.rsplit + for x in _RANGE_10: + s_rsplit("ACTAT") + + + +## split with limits + +GFF3_example = "\t".join([ + "I", "Genomic_canonical", "region", "357208", "396183", ".", "+", ".", + "ID=Sequence:R119;note=Clone R119%3B Genbank AF063007;Name=R119"]) + + at bench('GFF3_example.split("\\t")', "tab split", 1000) +def tab_split_no_limit(STR): + s = STR(GFF3_example) + s_split = s.split + for x in _RANGE_1000: + s_split("\t") + + at bench('GFF3_example.split("\\t", 8)', "tab split", 1000) +def tab_split_limit(STR): + s = STR(GFF3_example) + s_split = s.split + for x in _RANGE_1000: + s_split("\t", 8) + + at bench('GFF3_example.rsplit("\\t")', "tab split", 1000) +def tab_rsplit_no_limit(STR): + s = STR(GFF3_example) + s_rsplit = s.rsplit + for x in _RANGE_1000: + s_rsplit("\t") + + at bench('GFF3_example.rsplit("\\t", 8)', "tab split", 1000) +def tab_rsplit_limit(STR): + s = STR(GFF3_example) + s_rsplit = s.rsplit + for x in _RANGE_1000: + s_rsplit("\t", 8) + +#### Count characters + + at bench('...text.with.2000.newlines.count("\\n")', + "count newlines", 10) +def count_newlines(STR): + s = _get_2000_lines(STR) + s_count = s.count + for x in _RANGE_10: + s_count("\n") + +# Orchid sequences concatenated, from Biopython +_dna = """ +CGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATCATTGTTGAGATCACATAATAATTGATCGGGTT +AATCTGGAGGATCTGTTTACTTTGGTCACCCATGAGCATTTGCTGTTGAAGTGACCTAGAATTGCCATCG +AGCCTCCTTGGGAGCTTTCTTGTTGGCGAGATCTAAACCCTTGCCCGGCGCAGTTTTGCTCCAAGTCGTT +TGACACATAATTGGTGAAGGGGGTGGCATCCTTCCCTGACCCTCCCCCAACTATTTTTTTAACAACTCTC +AGCAACGGAGACTCAGTCTTCGGCAAATGCGATAAATGGTGTGAATTGCAGAATCCCGTGCACCATCGAG +TCTTTGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCACGCCTGCCTGGGCATTGCGAGTCATAT +CTCTCCCTTAACGAGGCTGTCCATACATACTGTTCAGCCGGTGCGGATGTGAGTTTGGCCCCTTGTTCTT +TGGTACGGGGGGTCTAAGAGCTGCATGGGCTTTTGATGGTCCTAAATACGGCAAGAGGTGGACGAACTAT +GCTACAACAAAATTGTTGTGCAGAGGCCCCGGGTTGTCGTATTAGATGGGCCACCGTAATCTGAAGACCC +TTTTGAACCCCATTGGAGGCCCATCAACCCATGATCAGTTGATGGCCATTTGGTTGCGACCCCAGGTCAG +GTGAGCAACAGCTGTCGTAACAAGGTTTCCGTAGGGTGAACTGCGGAAGGATCATTGTTGAGATCACATA +ATAATTGATCGAGTTAATCTGGAGGATCTGTTTACTTGGGTCACCCATGGGCATTTGCTGTTGAAGTGAC +CTAGATTTGCCATCGAGCCTCCTTGGGAGCATCCTTGTTGGCGATATCTAAACCCTCAATTTTTCCCCCA +ATCAAATTACACAAAATTGGTGGAGGGGGTGGCATTCTTCCCTTACCCTCCCCCAAATATTTTTTTAACA +ACTCTCAGCAACGGATATCTCAGCTCTTGCATCGATGAAGAACCCACCGAAATGCGATAAATGGTGTGAA +TTGCAGAATCCCGTGAACCATCGAGTCTTTGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCACG +CCTGCCTGGGCATTGCGAGTCATATCTCTCCCTTAACGAGGCTGTCCATACATACTGTTCAGCCGGTGCG +GATGTGAGTTTGGCCCCTTGTTCTTTGGTACGGGGGGTCTAAGAGATGCATGGGCTTTTGATGGTCCTAA +ATACGGCAAGAGGTGGACGAACTATGCTACAACAAAATTGTTGTGCAAAGGCCCCGGGTTGTCGTATAAG +ATGGGCCACCGATATCTGAAGACCCTTTTGGACCCCATTGGAGCCCATCAACCCATGTCAGTTGATGGCC +ATTCGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATCATTGTTGAGATCACATAATAATTGATCGA +GTTAATCTGGAGGATCTGTTTACTTGGGTCACCCATGGGCATTTGCTGTTGAAGTGACCTAGATTTGCCA +TCGAGCCTCCTTGGGAGCTTTCTTGTTGGCGATATCTAAACCCTTGCCCGGCAGAGTTTTGGGAATCCCG +TGAACCATCGAGTCTTTGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCACGCCTGCCTGGGCAT +TGCGAGTCATATCTCTCCCTTAACGAGGCTGTCCATACACACCTGTTCAGCCGGTGCGGATGTGAGTTTG +GCCCCTTGTTCTTTGGTACGGGGGGTCTAAGAGCTGCATGGGCTTTTGATGGTCCTAAATACGGCAAGAG +GTGGACGAACTATGCTACAACAAAATTGTTGTGCAAAGGCCCCGGGTTGTCGTATTAGATGGGCCACCAT +AATCTGAAGACCCTTTTGAACCCCATTGGAGGCCCATCAACCCATGATCAGTTGATGGCCATTTGGTTGC +GACCCAGTCAGGTGAGGGTAGGTGAACCTGCGGAAGGATCATTGTTGAGATCACATAATAATTGATCGAG +TTAATCTGGAGGATCTGTTTACTTTGGTCACCCATGGGCATTTGCTGTTGAAGTGACCTAGATTTGCCAT +CGAGCCTCCTTGGGAGCTTTCTTGTTGGCGAGATCTAAACCCTTGCCCGGCGGAGTTTGGCGCCAAGTCA +TATGACACATAATTGGTGAAGGGGGTGGCATCCTGCCCTGACCCTCCCCAAATTATTTTTTTAACAACTC +TCAGCAACGGATATCTCGGCTCTTGCATCGATGAAGAACGCAGCGAAATGCGATAAATGGTGTGAATTGC +AGAATCCCGTGAACCATCGAGTCTTTGGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCACGCCT +GCCTGGGCATTGGGAATCATATCTCTCCCCTAACGAGGCTATCCAAACATACTGTTCATCCGGTGCGGAT +GTGAGTTTGGCCCCTTGTTCTTTGGTACCGGGGGTCTAAGAGCTGCATGGGCATTTGATGGTCCTCAAAA +CGGCAAGAGGTGGACGAACTATGCCACAACAAAATTGTTGTCCCAAGGCCCCGGGTTGTCGTATTAGATG +GGCCACCGTAACCTGAAGACCCTTTTGAACCCCATTGGAGGCCCATCAACCCATGATCAGTTGATGACCA +TTTGTTGCGACCCCAGTCAGCTGAGCAACCCGCTGAGTGGAAGGTCATTGCCGATATCACATAATAATTG +ATCGAGTTAATCTGGAGGATCTGTTTACTTGGTCACCCATGAGCATTTGCTGTTGAAGTGACCTAGATTT +GCCATCGAGCCTCCTTGGGAGTTTTCTTGTTGGCGAGATCTAAACCCTTGCCCGGCGGAGTTGTGCGCCA +AGTCATATGACACATAATTGGTGAAGGGGGTGGCATCCTGCCCTGACCCTCCCCAAATTATTTTTTTAAC +AACTCTCAGCAACGGATATCTCGGCTCTTGCATCGATGAAGAACGCAGCGAAATGCGATAAATGGTGTGA +ATTGCAGAATCCCGTGAACCATCGAGTCTTTGAACGCAAGTTGCGCCCGAGGCCATCAGGCCAAGGGCAC +GCCTGCCTGGGCATTGCGAGTCATATCTCTCCCTTAACGAGGCTGTCCATACATACTGTTCATCCGGTGC +GGATGTGAGTTTGGCCCCTTGTTCTTTGGTACGGGGGGTCTAAGAGCTGCATGGGCATTTGATGGTCCTC +AAAACGGCAAGAGGTGGACGAACTATGCTACAACCAAATTGTTGTCCCAAGGCCCCGGGTTGTCGTATTA +GATGGGCCACCGTAACCTGAAGACCCTTTTGAACCCCATTGGAGGCCCATCAACCCATGATCAGTTGATG +ACCATGTGTTGCGACCCCAGTCAGCTGAGCAACGCGCTGAGCGTAACAAGGTTTCCGTAGGTGGACCTCC +GGGAGGATCATTGTTGAGATCACATAATAATTGATCGAGGTAATCTGGAGGATCTGCATATTTTGGTCAC +""" +_dna = "".join(_dna.splitlines()) +_dna = _dna * 25 +_dna_unicode = unicode(_dna) + +def _get_dna(STR): + if STR is unicode: + return _dna_unicode + if STR is str: + return _dna + raise AssertionError + + at bench('dna.count("AACT")', "count AACT substrings in DNA example", 10) +def count_aact(STR): + seq = _get_dna(STR) + seq_count = seq.count + for x in _RANGE_10: + seq_count("AACT") + +##### startswith and endswith + + at bench('"Andrew".startswith("A")', 'startswith single character', 1000) +def startswith_single(STR): + s1 = STR("Andrew") + s2 = STR("A") + s1_startswith = s1.startswith + for x in _RANGE_1000: + s1_startswith(s2) + + at bench('"Andrew".startswith("Andrew")', 'startswith multiple characters', + 1000) +def startswith_multiple(STR): + s1 = STR("Andrew") + s2 = STR("Andrew") + s1_startswith = s1.startswith + for x in _RANGE_1000: + s1_startswith(s2) + + at bench('"Andrew".startswith("Anders")', + 'startswith multiple characters - not!', 1000) +def startswith_multiple_not(STR): + s1 = STR("Andrew") + s2 = STR("Anders") + s1_startswith = s1.startswith + for x in _RANGE_1000: + s1_startswith(s2) + + +# endswith + + at bench('"Andrew".endswith("w")', 'endswith single character', 1000) +def endswith_single(STR): + s1 = STR("Andrew") + s2 = STR("w") + s1_endswith = s1.endswith + for x in _RANGE_1000: + s1_endswith(s2) + + at bench('"Andrew".endswith("Andrew")', 'endswith multiple characters', 1000) +def endswith_multiple(STR): + s1 = STR("Andrew") + s2 = STR("Andrew") + s1_endswith = s1.endswith + for x in _RANGE_1000: + s1_endswith(s2) + + at bench('"Andrew".endswith("Anders")', + 'endswith multiple characters - not!', 1000) +def endswith_multiple_not(STR): + s1 = STR("Andrew") + s2 = STR("Anders") + s1_endswith = s1.endswith + for x in _RANGE_1000: + s1_endswith(s2) + +#### Strip + + at bench('"Hello!\\n".strip()', 'strip terminal newline', 1000) +def terminal_newline_strip_right(STR): + s = STR("Hello!\n") + s_strip = s.strip + for x in _RANGE_1000: + s_strip() + + at bench('"Hello!\\n".rstrip()', 'strip terminal newline', 1000) +def terminal_newline_rstrip(STR): + s = STR("Hello!\n") + s_rstrip = s.rstrip + for x in _RANGE_1000: + s_rstrip() + + at bench('"\\nHello!".strip()', 'strip terminal newline', 1000) +def terminal_newline_strip_left(STR): + s = STR("\nHello!") + s_strip = s.strip + for x in _RANGE_1000: + s_strip() + + at bench('"\\nHello!\\n".strip()', 'strip terminal newline', 1000) +def terminal_newline_strip_both(STR): + s = STR("\nHello!\n") + s_strip = s.strip + for x in _RANGE_1000: + s_strip() + + at bench('"\\nHello!".rstrip()', 'strip terminal newline', 1000) +def terminal_newline_lstrip(STR): + s = STR("\nHello!") + s_lstrip = s.lstrip + for x in _RANGE_1000: + s_lstrip() + +# Strip multiple spaces or tabs + + at bench('"Hello\\t \\t".strip()', 'strip terminal spaces and tabs', 1000) +def terminal_space_strip(STR): + s = STR("Hello\t \t!") + s_strip = s.strip + for x in _RANGE_1000: + s_strip() + + at bench('"Hello\\t \\t".rstrip()', 'strip terminal spaces and tabs', 1000) +def terminal_space_rstrip(STR): + s = STR("Hello!\t \t") + s_rstrip = s.rstrip + for x in _RANGE_1000: + s_rstrip() + + at bench('"\\t \\tHello".rstrip()', 'strip terminal spaces and tabs', 1000) +def terminal_space_lstrip(STR): + s = STR("\t \tHello!") + s_lstrip = s.lstrip + for x in _RANGE_1000: + s_lstrip() + + +#### replace + at bench('"This is a test".replace(" ", "\\t")', 'replace single character', + 1000) +def replace_single_character(STR): + s = STR("This is a test!") + from_str = STR(" ") + to_str = STR("\t") + s_replace = s.replace + for x in _RANGE_1000: + s_replace(from_str, to_str) + + at uses_re + at bench('re.sub(" ", "\\t", "This is a test"', 'replace single character', + 1000) +def replace_single_character_re(STR): + s = STR("This is a test!") + pat = re.compile(STR(" ")) + to_str = STR("\t") + pat_sub = pat.sub + for x in _RANGE_1000: + pat_sub(to_str, s) + + at bench('"...text.with.2000.lines...replace("\\n", " ")', + 'replace single character, big string', 10) +def replace_single_character_big(STR): + s = _get_2000_lines(STR) + from_str = STR("\n") + to_str = STR(" ") + s_replace = s.replace + for x in _RANGE_10: + s_replace(from_str, to_str) + + at uses_re + at bench('re.sub("\\n", " ", "...text.with.2000.lines...")', + 'replace single character, big string', 10) +def replace_single_character_big_re(STR): + s = _get_2000_lines(STR) + pat = re.compile(STR("\n")) + to_str = STR(" ") + pat_sub = pat.sub + for x in _RANGE_10: + pat_sub(to_str, s) + + + at bench('dna.replace("ATC", "ATT")', + 'replace multiple characters, dna', 10) +def replace_multiple_characters_dna(STR): + seq = _get_dna(STR) + from_str = STR("ATC") + to_str = STR("ATT") + seq_replace = seq.replace + for x in _RANGE_10: + seq_replace(from_str, to_str) + +# This increases the character count + at bench('"...text.with.2000.newlines...replace("\\n", "\\r\\n")', + 'replace and expand multiple characters, big string', 10) +def replace_multiple_character_big(STR): + s = _get_2000_lines(STR) + from_str = STR("\n") + to_str = STR("\r\n") + s_replace = s.replace + for x in _RANGE_10: + s_replace(from_str, to_str) + + +# This decreases the character count + at bench('"When shall we three meet again?".replace("ee", "")', + 'replace/remove multiple characters', 1000) +def replace_multiple_character_remove(STR): + s = STR("When shall we three meet again?") + from_str = STR("ee") + to_str = STR("") + s_replace = s.replace + for x in _RANGE_1000: + s_replace(from_str, to_str) + + +big_s = "A" + ("Z"*128*1024) +big_s_unicode = unicode(big_s) +def _get_big_s(STR): + if STR is unicode: return big_s_unicode + if STR is str: return big_s + raise AssertionError + +# The older replace implementation counted all matches in +# the string even when it only neeed to make one replacement. + at bench('("A" + ("Z"*128*1024)).replace("A", "BB", 1)', + 'quick replace single character match', 10) +def quick_replace_single_match(STR): + s = _get_big_s(STR) + from_str = STR("A") + to_str = STR("BB") + s_replace = s.replace + for x in _RANGE_10: + s_replace(from_str, to_str, 1) + + at bench('("A" + ("Z"*128*1024)).replace("AZZ", "BBZZ", 1)', + 'quick replace multiple character match', 10) +def quick_replace_multiple_match(STR): + s = _get_big_s(STR) + from_str = STR("AZZ") + to_str = STR("BBZZ") + s_replace = s.replace + for x in _RANGE_10: + s_replace(from_str, to_str, 1) + + +#### + +# CCP does a lot of this, for internationalisation of ingame messages. +_format = "The %(thing)s is %(place)s the %(location)s." +_format_dict = { "thing":"THING", "place":"PLACE", "location":"LOCATION", } +_format_unicode = unicode(_format) +_format_dict_unicode = dict([ (unicode(k), unicode(v)) for (k,v) in _format_dict.iteritems() ]) + +def _get_format(STR): + if STR is unicode: + return _format_unicode + if STR is str: + return _format + raise AssertionError + +def _get_format_dict(STR): + if STR is unicode: + return _format_dict_unicode + if STR is str: + return _format_dict + raise AssertionError + +# Formatting. + at bench('"The %(k1)s is %(k2)s the %(k3)s."%{"k1":"x","k2":"y","k3":"z",}', + 'formatting a string type with a dict', 1000) +def format_with_dict(STR): + s = _get_format(STR) + d = _get_format_dict(STR) + for x in _RANGE_1000: + s % d + + +#### Upper- and lower- case conversion + + at bench('("Where in the world is Carmen San Deigo?"*10).lower()', + "case conversion -- rare", 1000) +def lower_conversion_rare(STR): + s = STR("Where in the world is Carmen San Deigo?"*10) + s_lower = s.lower + for x in _RANGE_1000: + s_lower() + + at bench('("WHERE IN THE WORLD IS CARMEN SAN DEIGO?"*10).lower()', + "case conversion -- dense", 1000) +def lower_conversion_dense(STR): + s = STR("WHERE IN THE WORLD IS CARMEN SAN DEIGO?"*10) + s_lower = s.lower + for x in _RANGE_1000: + s_lower() + + + at bench('("wHERE IN THE WORLD IS cARMEN sAN dEIGO?"*10).upper()', + "case conversion -- rare", 1000) +def upper_conversion_rare(STR): + s = STR("Where in the world is Carmen San Deigo?"*10) + s_upper = s.upper + for x in _RANGE_1000: + s_upper() + + at bench('("where in the world is carmen san deigo?"*10).upper()', + "case conversion -- dense", 1000) +def upper_conversion_dense(STR): + s = STR("where in the world is carmen san deigo?"*10) + s_upper = s.upper + for x in _RANGE_1000: + s_upper() + + +# end of benchmarks + +################# + +class BenchTimer(timeit.Timer): + def best(self, repeat=1): + for i in range(1, 10): + number = 10**i + try: + x = self.timeit(number) + except: + self.print_exc() + raise + if x > 0.2: + break + times = [x] + for i in range(1, repeat): + times.append(self.timeit(number)) + return min(times) / number + +def main(): + (options, test_names) = parser.parse_args() + if options.str_only and options.unicode_only: + raise SystemExit("Only one of --8-bit and --unicode are allowed") + + bench_functions = [] + for (k,v) in globals().items(): + if hasattr(v, "is_bench"): + if test_names: + for name in test_names: + if name in v.group: + break + else: + # Not selected, ignore + continue + if options.skip_re and hasattr(v, "uses_re"): + continue + + bench_functions.append( (v.group, k, v) ) + bench_functions.sort() + + print "string\tunicode" + print "(in ms)\t(in ms)\t%\tcomment" + + str_total = uni_total = 0.0 + + for title, group in itertools.groupby(bench_functions, + operator.itemgetter(0)): + print 'class', title.replace(' ', '_').replace('-', '_') + '_Str', '(Test):' + print ' def test(self):' + groupList = list(group) + for g in groupList: + s = repr(g).split(' Author: sean.reifschneider Date: Sat Mar 31 23:32:37 2007 New Revision: 54643 Removed: sandbox/trunk/pybch/ Log: Removing pybch, since I could never get the results to stabilize.
    Name -

    Please note that if you have previously created or modified issue +

    NOTE: If you have previously created or modified issue reports using the sourceforge issue tracker previously used for python bugs, your username on sourceforge already exists in this tracker. Use the Password recovery form to From python-checkins at python.org Sun Mar 25 05:20:10 2007 From: python-checkins at python.org (facundo.batista) Date: Sun, 25 Mar 2007 05:20:10 +0200 (CEST) Subject: [Python-checkins] r54570 - python/trunk/Lib/test/test_httplib.py Message-ID: <20070325032010.BB90F1E4010@bag.python.org> Author: facundo.batista Date: Sun Mar 25 05:20:05 2007 New Revision: 54570 Modified: python/trunk/Lib/test/test_httplib.py Log: Closing the HTTP connection after each test, and listening more. Modified: python/trunk/Lib/test/test_httplib.py ============================================================================== --- python/trunk/Lib/test/test_httplib.py (original) +++ python/trunk/Lib/test/test_httplib.py Sun Mar 25 05:20:05 2007 @@ -160,7 +160,7 @@ self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) global PORT PORT = test_support.bind_port(self.serv, HOST, PORT) - self.serv.listen(1) + self.serv.listen(5) def tearDown(self): self.serv.close() @@ -174,11 +174,13 @@ httpConn = httplib.HTTPConnection(HOST, PORT) httpConn.connect() self.assertTrue(httpConn.sock.gettimeout() is None) + httpConn.close() # a value httpConn = httplib.HTTPConnection(HOST, PORT, timeout=30) httpConn.connect() self.assertEqual(httpConn.sock.gettimeout(), 30) + httpConn.close() # None, having other default previous = socket.getdefaulttimeout() @@ -189,6 +191,7 @@ finally: socket.setdefaulttimeout(previous) self.assertEqual(httpConn.sock.gettimeout(), 30) + httpConn.close() def test_main(verbose=None): From buildbot at python.org Sun Mar 25 08:38:32 2007 From: buildbot at python.org (buildbot at python.org) Date: Sun, 25 Mar 2007 06:38:32 +0000 Subject: [Python-checkins] buildbot warnings in MIPS Debian trunk Message-ID: <20070325063833.317741E401B@bag.python.org> The Buildbot has detected a new failure of MIPS Debian trunk. Full details are available at: http://www.python.org/dev/buildbot/all/MIPS%2520Debian%2520trunk/builds/709 Buildbot URL: http://www.python.org/dev/buildbot/all/ Build Reason: Build Source Stamp: [branch trunk] HEAD Blamelist: brett.cannon,facundo.batista,georg.brandl,ziga.seilnacht Build had warnings: warnings failed slave lost sincerely, -The Buildbot From python-checkins at python.org Sun Mar 25 17:51:53 2007 From: python-checkins at python.org (erik.forsberg) Date: Sun, 25 Mar 2007 17:51:53 +0200 (CEST) Subject: [Python-checkins] r54571 - tracker/importer/sfxmlhandlers.py Message-ID: <20070325155153.475F51E4011@bag.python.org> Author: erik.forsberg Date: Sun Mar 25 17:51:52 2007 New Revision: 54571 Modified: tracker/importer/sfxmlhandlers.py Log: Delete comment headers from sf. Resolves http://psf.upfronthosting.co.za/roundup/meta/issue91. Modified: tracker/importer/sfxmlhandlers.py ============================================================================== --- tracker/importer/sfxmlhandlers.py (original) +++ tracker/importer/sfxmlhandlers.py Sun Mar 25 17:51:52 2007 @@ -178,6 +178,11 @@ msg_filename = self.db.filename(self.db.msg.classname, msg_nodeid, create=1) ensureParentsExist(msg_filename) + + mo = re.search('^Logged In: (YES |NO )\nuser_id=[0-9]+\nOriginator: (YES|NO)\n', content, re.MULTILINE) + if mo: + content = content[mo.end():] + open(msg_filename, 'w').write(content.encode('utf-8')) return msg_nodeid From python-checkins at python.org Sun Mar 25 20:44:40 2007 From: python-checkins at python.org (georg.brandl) Date: Sun, 25 Mar 2007 20:44:40 +0200 (CEST) Subject: [Python-checkins] r54572 - python/trunk/Doc/mac/undoc.tex Message-ID: <20070325184440.058FF1E4011@bag.python.org> Author: georg.brandl Date: Sun Mar 25 20:44:35 2007 New Revision: 54572 Modified: python/trunk/Doc/mac/undoc.tex Log: Markup fix. Modified: python/trunk/Doc/mac/undoc.tex ============================================================================== --- python/trunk/Doc/mac/undoc.tex (original) +++ python/trunk/Doc/mac/undoc.tex Sun Mar 25 20:44:35 2007 @@ -21,7 +21,7 @@ \modulesynopsis{Helper module for BuildApplet, BuildApplication and macfreeze.} -\deprecated{2.4} +\deprecated{2.4}{} \section{\module{cfmfile} --- Code Fragment Resource module} \declaremodule{standard}{cfmfile} @@ -33,7 +33,7 @@ used by BuildApplication to combine all plugin modules to a single executable. -\deprecated{2.4} +\deprecated{2.4}{} \section{\module{icopen} --- Internet Config replacement for \method{open()}} \declaremodule{standard}{icopen} From python-checkins at python.org Sun Mar 25 21:05:01 2007 From: python-checkins at python.org (georg.brandl) Date: Sun, 25 Mar 2007 21:05:01 +0200 (CEST) Subject: [Python-checkins] r54573 - python/trunk/Doc/dist/dist.tex Message-ID: <20070325190501.1A5D31E4011@bag.python.org> Author: georg.brandl Date: Sun Mar 25 21:04:55 2007 New Revision: 54573 Modified: python/trunk/Doc/dist/dist.tex Log: Markup fix. Modified: python/trunk/Doc/dist/dist.tex ============================================================================== --- python/trunk/Doc/dist/dist.tex (original) +++ python/trunk/Doc/dist/dist.tex Sun Mar 25 21:04:55 2007 @@ -1802,9 +1802,9 @@ setup.py foo.py \end{verbatim} -(In all diagrams in this section, \verb|| will refer to the -distribution root directory.) A minimal setup script to describe this -situation would be: +(In all diagrams in this section, \var{\textless root\textgreater} +will refer to the distribution root directory.) A minimal setup script +to describe this situation would be: \begin{verbatim} from distutils.core import setup setup(name='foo', @@ -3179,7 +3179,7 @@ Note that this is not a fully-fledged string interpolation function. A valid \code{\$variable} can consist only of upper and lower case letters, -numbers and an underscore. No \{ \} or \( \) style quoting is available. +numbers and an underscore. No \{ \} or ( ) style quoting is available. \end{funcdesc} \begin{funcdesc}{grok_environment_error}{exc\optional{, prefix=\samp{'error: '}}} From python-checkins at python.org Mon Mar 26 16:55:24 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 26 Mar 2007 16:55:24 +0200 (CEST) Subject: [Python-checkins] r54574 - sandbox/trunk/2to3/fixes/util.py Message-ID: <20070326145524.8312F1E4018@bag.python.org> Author: collin.winter Date: Mon Mar 26 16:55:22 2007 New Revision: 54574 Modified: sandbox/trunk/2to3/fixes/util.py Log: Add comments, new portability section. Modified: sandbox/trunk/2to3/fixes/util.py ============================================================================== --- sandbox/trunk/2to3/fixes/util.py (original) +++ sandbox/trunk/2to3/fixes/util.py Mon Mar 26 16:55:22 2007 @@ -15,6 +15,10 @@ lparen_leaf = Leaf(token.LPAR, "(") rparen_leaf = Leaf(token.RPAR, ")") +########################################################### +### Common node-construction "macros" +########################################################### + def Assign(target, source): """Build an assignment statement""" if not isinstance(target, tuple): @@ -66,6 +70,10 @@ def String(string, prefix=None): """A string leaf""" return Leaf(token.STRING, string, prefix=prefix) + +########################################################### +### Determine whether a node represents a given literal +########################################################### def is_tuple(node): """Does the node represent a tuple literal?""" @@ -84,5 +92,23 @@ and isinstance(node.children[0], Leaf) and isinstance(node.children[-1], Leaf) and node.children[0].value == "[" - and node.children[-1].value == "]") + and node.children[-1].value == "]") + +########################################################### +### Common portability code. This allows fixers to do, eg, +### "from fixes.util import set" and forget about it. +########################################################### +try: + any = any +except NameError: + def any(l): + for o in l: + if o: + return True + return False + +try: + set = set +except NameError: + from sets import Set as set From python-checkins at python.org Mon Mar 26 16:57:32 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 26 Mar 2007 16:57:32 +0200 (CEST) Subject: [Python-checkins] r54575 - sandbox/trunk/2to3/fixes/fix_numliterals.py Message-ID: <20070326145732.438E51E401F@bag.python.org> Author: collin.winter Date: Mon Mar 26 16:57:29 2007 New Revision: 54575 Modified: sandbox/trunk/2to3/fixes/fix_numliterals.py Log: Fix py2.3-compat issue (no sets builtin). Modified: sandbox/trunk/2to3/fixes/fix_numliterals.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_numliterals.py (original) +++ sandbox/trunk/2to3/fixes/fix_numliterals.py Mon Mar 26 16:57:29 2007 @@ -8,7 +8,7 @@ import pytree from pgen2 import token from fixes import basefix -from fixes.util import Number +from fixes.util import Number, set class FixNumliterals(basefix.BaseFix): From python-checkins at python.org Mon Mar 26 17:09:41 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 26 Mar 2007 17:09:41 +0200 (CEST) Subject: [Python-checkins] r54576 - in sandbox/trunk/2to3: Grammar.txt tests/test_grammar.py Message-ID: <20070326150941.02A961E400B@bag.python.org> Author: collin.winter Date: Mon Mar 26 17:09:38 2007 New Revision: 54576 Modified: sandbox/trunk/2to3/Grammar.txt sandbox/trunk/2to3/tests/test_grammar.py Log: Update the grammar to support py3k's classdef syntax. Modified: sandbox/trunk/2to3/Grammar.txt ============================================================================== --- sandbox/trunk/2to3/Grammar.txt (original) +++ sandbox/trunk/2to3/Grammar.txt Mon Mar 26 17:09:38 2007 @@ -134,7 +134,7 @@ testlist: test (',' test)* [','] dictsetmaker: (test ':' test (',' test ':' test)* [',']) | (test (',' test)* [',']) -classdef: 'class' NAME ['(' [testlist] ')'] ':' suite +classdef: 'class' NAME ['(' [arglist] ')'] ':' suite arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) argument: test [gen_for] | test '=' test # Really [keyword '='] test Modified: sandbox/trunk/2to3/tests/test_grammar.py ============================================================================== --- sandbox/trunk/2to3/tests/test_grammar.py (original) +++ sandbox/trunk/2to3/tests/test_grammar.py Mon Mar 26 17:09:38 2007 @@ -131,6 +131,15 @@ self.validate("""0b101010""") self.invalid_syntax("""0b0101021""") + +class TestClassDef(GrammarTest): + def test_new_syntax(self): + self.validate("class B(t=7): pass") + self.validate("class B(t, *args): pass") + self.validate("class B(t, **kwargs): pass") + self.validate("class B(t, *args, **kwargs): pass") + self.validate("class B(t, y=9, *args, **kwargs): pass") + class TestGrammarFiles(GrammarTest): def test_python2(self): From python-checkins at python.org Mon Mar 26 17:20:22 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 26 Mar 2007 17:20:22 +0200 (CEST) Subject: [Python-checkins] r54577 - in sandbox/trunk/2to3: fixes/fix_next.py fixes/util.py tests/test_util.py Message-ID: <20070326152022.643771E400B@bag.python.org> Author: collin.winter Date: Mon Mar 26 17:20:19 2007 New Revision: 54577 Modified: sandbox/trunk/2to3/fixes/fix_next.py sandbox/trunk/2to3/fixes/util.py sandbox/trunk/2to3/tests/test_util.py Log: Move find_binding and support code out of fix_next and into fixes.util; add tests for find_binding. Modified: sandbox/trunk/2to3/fixes/fix_next.py ============================================================================== --- sandbox/trunk/2to3/fixes/fix_next.py (original) +++ sandbox/trunk/2to3/fixes/fix_next.py Mon Mar 26 17:20:19 2007 @@ -10,7 +10,7 @@ from pgen2 import token from pygram import python_symbols as syms from fixes import basefix -from fixes.util import Name, Call +from fixes.util import Name, Call, find_binding, any bind_warning = "Calls to builtin next() possibly shadowed by global binding" @@ -69,7 +69,7 @@ n = Name("__next__", prefix=name.get_prefix()) name.replace(n) elif attr: - # We don't do this transformation if we're assignment to "x.next". + # We don't do this transformation if we're assigning to "x.next". # Unfortunately, it doesn't seem possible to do this in PATTERN, # so it's being done here. if is_assign_target(node): @@ -94,69 +94,9 @@ node.shadowed_next = True -### The following functions are to find module-level bindings - -def find_binding(name, file_input): - for child in file_input.children: - if child.type == syms.for_stmt: - if find(name, child.children[1]): - return child - elif child.type == syms.funcdef and child.children[1].value == name: - return child - elif is_import_binding(child, name): - return child - elif child.type == syms.simple_stmt: - if child.children[0].type == syms.expr_stmt: - n = find(name, child.children[0].children[0]) - if n: - return n - -def find(name, node): - nodes = [node] - while nodes: - node = nodes.pop() - if isinstance(node, pytree.Node): - nodes.extend(node.children) - elif node.type == token.NAME and node.value == name: - return node - return None - -def is_import_binding(node, name): - if node.type == syms.simple_stmt: - i = node.children[0] - if i.type == syms.import_name: - imp = i.children[1] - if imp.type == syms.dotted_as_names: - for child in imp.children: - if child.type == syms.dotted_as_name: - if child.children[2].value == name: - return i - elif imp.type == syms.dotted_as_name: - last = imp.children[-1] - if last.type == token.NAME and last.value == name: - return i - elif i.type == syms.import_from: - n = i.children[3] - if n.type == syms.import_as_names: - if find(name, n): - return i - elif n.type == token.NAME and n.value == name: - return i - return None - - ### The following functions help test if node is part of an assignment ### target. -try: - any -except NameError: - def any(l): - for o in l: - if o: - return True - return False - def is_assign_target(node): assign = find_assign(node) if assign is None: Modified: sandbox/trunk/2to3/fixes/util.py ============================================================================== --- sandbox/trunk/2to3/fixes/util.py (original) +++ sandbox/trunk/2to3/fixes/util.py Mon Mar 26 17:20:19 2007 @@ -112,3 +112,66 @@ set = set except NameError: from sets import Set as set + +########################################################### +### The following functions are to find bindings in a suite +########################################################### + +_def_syms = set([syms.classdef, syms.funcdef]) +def find_binding(name, node): + for child in node.children: + if child.type == syms.for_stmt: + if _find(name, child.children[1]): + return child + elif _find(name, child.children[-1]): + return child + elif child.type in _def_syms and child.children[1].value == name: + return child + elif _is_import_binding(child, name): + return child + elif child.type == syms.simple_stmt: + if child.children[0].type == syms.expr_stmt: + n = _find(name, child.children[0].children[0]) + if n: + return n + +_block_syms = set([syms.funcdef, syms.classdef, syms.trailer]) +def _find(name, node): + nodes = [node] + while nodes: + node = nodes.pop() + if node.type > 256 and node.type not in _block_syms: + nodes.extend(node.children) + elif node.type == token.NAME and node.value == name: + return node + return None + +def _is_import_binding(node, name): + if node.type == syms.simple_stmt: + i = node.children[0] + if i.type == syms.import_name: + imp = i.children[1] + if imp.type == syms.dotted_as_names: + for child in imp.children: + if child.type == syms.dotted_as_name: + if child.children[2].value == name: + return i + elif child.type == token.NAME and child.value == name: + return i + elif imp.type == syms.dotted_as_name: + last = imp.children[-1] + if last.type == token.NAME and last.value == name: + return i + elif imp.type == token.NAME and imp.value == name: + return i + elif i.type == syms.import_from: + n = i.children[3] + if n.type == syms.import_as_names and _find(name, n): + return i + elif n.type == syms.import_as_name: + child = n.children[2] + if child.type == token.NAME and child.value == name: + return i + elif n.type == token.NAME and n.value == name: + return i + return None Modified: sandbox/trunk/2to3/tests/test_util.py ============================================================================== --- sandbox/trunk/2to3/tests/test_util.py (original) +++ sandbox/trunk/2to3/tests/test_util.py Mon Mar 26 17:20:19 2007 @@ -12,13 +12,15 @@ import pytree from fixes import util -def parse(code): + +def parse(code, strip_levels=0): # The topmost node is file_input, which we don't care about. # The next-topmost node is a *_stmt node, which we also don't care about tree = support.parse_string(code) - node = tree.children[0].children[0] - node.parent = None - return node + for i in range(strip_levels): + tree = tree.children[0] + tree.parent = None + return tree class MacroTestCase(support.TestCase): def assertStr(self, node, string): @@ -29,7 +31,7 @@ class Test_is_tuple(support.TestCase): def is_tuple(self, string): - return util.is_tuple(parse(string)) + return util.is_tuple(parse(string, strip_levels=2)) def test_valid(self): self.failUnless(self.is_tuple("(a, b)")) @@ -44,7 +46,7 @@ class Test_is_list(support.TestCase): def is_list(self, string): - return util.is_list(parse(string)) + return util.is_list(parse(string, strip_levels=2)) def test_valid(self): self.failUnless(self.is_list("[]")) @@ -60,7 +62,7 @@ class Test_Attr(MacroTestCase): def test(self): from fixes.util import Attr, Name - call = parse("foo()") + call = parse("foo()", strip_levels=2) self.assertStr(Attr(Name("a"), Name("b")), "a.b") self.assertStr(Attr(call, Name("b")), "foo().b") @@ -79,7 +81,102 @@ self.assertStr(Name("a"), "a") self.assertStr(Name("foo.foo().bar"), "foo.foo().bar") self.assertStr(Name("a", prefix="b"), "ba") + +class Test_find_binding(support.TestCase): + def find_binding(self, name, string): + return util.find_binding(name, parse(string)) + + def test_simple_assignment(self): + self.failUnless(self.find_binding("a", "a = b")) + self.failUnless(self.find_binding("a", "a = [b, c, d]")) + self.failUnless(self.find_binding("a", "a = foo()")) + self.failUnless(self.find_binding("a", "a = foo().foo.foo[6][foo]")) + self.failIf(self.find_binding("a", "foo = a")) + self.failIf(self.find_binding("a", "foo = (a, b, c)")) + + def test_tuple_assignment(self): + self.failUnless(self.find_binding("a", "(a,) = b")) + self.failUnless(self.find_binding("a", "(a, b, c) = [b, c, d]")) + self.failUnless(self.find_binding("a", "(c, (d, a), b) = foo()")) + self.failUnless(self.find_binding("a", "(a, b) = foo().foo.foo[6][foo]")) + self.failIf(self.find_binding("a", "(foo, b) = (b, a)")) + self.failIf(self.find_binding("a", "(foo, b, c) = (a, b, c)")) + + def test_list_assignment(self): + self.failUnless(self.find_binding("a", "[a] = b")) + self.failUnless(self.find_binding("a", "[a, b, c] = [b, c, d]")) + self.failUnless(self.find_binding("a", "[c, [d, a], b] = foo()")) + self.failUnless(self.find_binding("a", "[a, b] = foo().foo.foo[a][foo]")) + self.failIf(self.find_binding("a", "[foo, b] = (b, a)")) + self.failIf(self.find_binding("a", "[foo, b, c] = (a, b, c)")) + + def test_invalid_assignments(self): + self.failIf(self.find_binding("a", "foo.a = 5")) + self.failIf(self.find_binding("a", "foo[a] = 5")) + self.failIf(self.find_binding("a", "foo(a) = 5")) + self.failIf(self.find_binding("a", "foo(a, b) = 5")) + + def test_simple_import(self): + self.failUnless(self.find_binding("a", "import a")) + self.failUnless(self.find_binding("a", "import b, c, a, d")) + self.failIf(self.find_binding("a", "import b")) + self.failIf(self.find_binding("a", "import b, c, d")) + + def test_from_import(self): + self.failUnless(self.find_binding("a", "from x import a")) + self.failUnless(self.find_binding("a", "from a import a")) + self.failUnless(self.find_binding("a", "from x import b, c, a, d")) + self.failUnless(self.find_binding("a", "from x.b import a")) + self.failUnless(self.find_binding("a", "from x.b import b, c, a, d")) + self.failIf(self.find_binding("a", "from a import b")) + self.failIf(self.find_binding("a", "from a.d import b")) + self.failIf(self.find_binding("a", "from d.a import b")) + + def test_import_as(self): + self.failUnless(self.find_binding("a", "import b as a")) + self.failUnless(self.find_binding("a", "import b as a, c, a as f, d")) + self.failIf(self.find_binding("a", "import a as f")) + self.failIf(self.find_binding("a", "import b, c as f, d as e")) + + def test_from_import_as(self): + self.failUnless(self.find_binding("a", "from x import b as a")) + self.failUnless(self.find_binding("a", "from x import g as a, d as b")) + self.failUnless(self.find_binding("a", "from x.b import t as a")) + self.failUnless(self.find_binding("a", "from x.b import g as a, d")) + self.failIf(self.find_binding("a", "from a import b as t")) + self.failIf(self.find_binding("a", "from a.d import b as t")) + self.failIf(self.find_binding("a", "from d.a import b as t")) + + def test_function_def(self): + self.failUnless(self.find_binding("a", "def a(): pass")) + self.failUnless(self.find_binding("a", "def a(b, c, d): pass")) + self.failUnless(self.find_binding("a", "def a(): b = 7")) + self.failIf(self.find_binding("a", "def d(b, (c, a), e): pass")) + self.failIf(self.find_binding("a", "def d(a=7): pass")) + self.failIf(self.find_binding("a", "def d(a): pass")) + self.failIf(self.find_binding("a", "def d(): a = 7")) + + def test_class_def(self): + self.failUnless(self.find_binding("a", "class a: pass")) + self.failUnless(self.find_binding("a", "class a(): pass")) + self.failUnless(self.find_binding("a", "class a(b): pass")) + self.failUnless(self.find_binding("a", "class a(b, c=8): pass")) + self.failIf(self.find_binding("a", "class d: pass")) + self.failIf(self.find_binding("a", "class d(a): pass")) + self.failIf(self.find_binding("a", "class d(b, a=7): pass")) + self.failIf(self.find_binding("a", "class d(b, *a): pass")) + self.failIf(self.find_binding("a", "class d(b, **a): pass")) + self.failIf(self.find_binding("a", "class d: a = 7")) + + def test_for(self): + self.failUnless(self.find_binding("a", "for a in r: pass")) + self.failUnless(self.find_binding("a", "for a, b in r: pass")) + self.failUnless(self.find_binding("a", "for (a, b) in r: pass")) + self.failUnless(self.find_binding("a", "for c, (a,) in r: pass")) + self.failUnless(self.find_binding("a", "for c, (a, b) in r: pass")) + self.failUnless(self.find_binding("a", "for c in r: a = c")) + if __name__ == "__main__": import __main__ From python-checkins at python.org Mon Mar 26 18:45:06 2007 From: python-checkins at python.org (collin.winter) Date: Mon, 26 Mar 2007 18:45:06 +0200 (CEST) Subject: [Python-checkins] r54578 - in sandbox/trunk/2to3: fixes/util.py tests/test_util.py Message-ID: <20070326164506.3D5811E400C@bag.python.org> Author: collin.winter Date: Mon Mar 26 18:45:01 2007 New Revision: 54578 Modified: sandbox/trunk/2to3/fixes/util.py sandbox/trunk/2to3/tests/test_util.py Log: Add while and if suite support to find_binding. Modified: sandbox/trunk/2to3/fixes/util.py ============================================================================== --- sandbox/trunk/2to3/fixes/util.py (original) +++ sandbox/trunk/2to3/fixes/util.py Mon Mar 26 18:45:01 2007 @@ -125,6 +125,9 @@ return child elif _find(name, child.children[-1]): return child + elif child.type in (syms.if_stmt, syms.while_stmt): + if _find(name, child.children[-1]): + return child elif child.type in _def_syms and child.children[1].value == name: return child elif _is_import_binding(child, name): Modified: sandbox/trunk/2to3/tests/test_util.py ============================================================================== --- sandbox/trunk/2to3/tests/test_util.py (original) +++ sandbox/trunk/2to3/tests/test_util.py Mon Mar 26 18:45:01 2007 @@ -177,6 +177,14 @@ self.failUnless(self.find_binding("a", "for c, (a, b) in r: pass")) self.failUnless(self.find_binding("a", "for c in r: a = c")) + def test_if(self): + self.failUnless(self.find_binding("a", "if b in r: a = c")) + self.failIf(self.find_binding("a", "if a in r: d = e")) + + def test_while(self): + self.failUnless(self.find_binding("a", "while b in r: a = c")) + self.failIf(self.find_binding("a", "while a in r: d = e")) + if __name__ == "__main__": import __main__ From python-checkins at python.org Mon Mar 26 20:55:42 2007 From: python-checkins at python.org (erik.forsberg) Date: Mon, 26 Mar 2007 20:55:42 +0200 (CEST) Subject: [Python-checkins] r54579 - in tracker/instances/python-dev: detectors/no_texthtml.py html/file.item.html Message-ID: <20070326185542.DDE981E4006@bag.python.org> Author: erik.forsberg Date: Mon Mar 26 20:55:38 2007 New Revision: 54579 Added: tracker/instances/python-dev/detectors/no_texthtml.py Modified: tracker/instances/python-dev/html/file.item.html Log: Audit file instances and set content type to text/plain if user submitted text/html. Mention this on file editing page. Resolves http://psf.upfronthosting.co.za/roundup/meta/issue109. Added: tracker/instances/python-dev/detectors/no_texthtml.py ============================================================================== --- (empty file) +++ tracker/instances/python-dev/detectors/no_texthtml.py Mon Mar 26 20:55:38 2007 @@ -0,0 +1,9 @@ + +def audit_html_files(db, cl, nodeid, newvalues): + if newvalues['type'] == 'text/html': + newvalues['type'] = 'text/plain' + + +def init(db): + db.file.audit('set', audit_html_files) + db.file.audit('create', audit_html_files) Modified: tracker/instances/python-dev/html/file.item.html ============================================================================== --- tracker/instances/python-dev/html/file.item.html (original) +++ tracker/instances/python-dev/html/file.item.html Mon Mar 26 20:55:38 2007 @@ -25,7 +25,9 @@

    Content Type + Please note that + for security reasons, it's not permitted to set content type to text/html.