diff -r f768a3529ee7 -r a9e12b7cc207 extras/MySQL-python-1.2.3-python3.patch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extras/MySQL-python-1.2.3-python3.patch Fri Nov 25 18:17:27 2011 +0100 @@ -0,0 +1,2074 @@ +Python3 patch for MySQL-python-1.2.3. +Based on https://github.com/davispuh/MySQL-for-Python-3 +Removed incompatible (and absolutely unnecessary) changes. +diff -ru MySQL-python-1.2.3/_mysql.c MySQL-Python-1.2.3-python3/_mysql.c +--- MySQL-python-1.2.3/_mysql.c 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/_mysql.c 2011-10-05 12:49:58.000000000 +0200 +@@ -31,33 +31,17 @@ + #if defined(MS_WINDOWS) + #include + #include +-#include +-#else +-#include "my_config.h" + #endif ++#include "my_config.h" + #include "mysql.h" + #include "mysqld_error.h" + #include "errmsg.h" + +-#if PY_VERSION_HEX < 0x02020000 +-# define MyTuple_Resize(t,n,d) _PyTuple_Resize(t, n, d) +-# define MyMember(a,b,c,d,e) {a,b,c,d} +-# define MyMemberlist(x) struct memberlist x +-# define MyAlloc(s,t) PyObject_New(s,&t) +-# define MyFree(o) PyObject_Del(o) +-#else + # define MyTuple_Resize(t,n,d) _PyTuple_Resize(t, n) + # define MyMember(a,b,c,d,e) {a,b,c,d,e} + # define MyMemberlist(x) struct PyMemberDef x + # define MyAlloc(s,t) (s *) t.tp_alloc(&t,0) +-# define MyFree(ob) ob->ob_type->tp_free((PyObject *)ob) +-#endif +- +-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +-typedef int Py_ssize_t; +-#define PY_SSIZE_T_MAX INT_MAX +-#define PY_SSIZE_T_MIN INT_MIN +-#endif ++# define MyFree(ob) ob->ob_base.ob_type->tp_free((PyObject *)ob) + + static PyObject *_mysql_MySQLError; + static PyObject *_mysql_Warning; +@@ -86,7 +70,7 @@ + + typedef struct { + PyObject_HEAD +- PyObject *conn; ++ _mysql_ConnectionObject *conn; + MYSQL_RES *result; + int nfields; + int use; +@@ -102,17 +86,16 @@ + #define check_server_init(x) if (!_mysql_server_init_done) _mysql_server_init_done = 1 + #endif + +-PyObject * +-_mysql_Exception(_mysql_ConnectionObject *c) ++PyObject * _mysql_Exception(_mysql_ConnectionObject *c) + { +- PyObject *t, *e; ++ PyObject *t, *e, *code, *message; + int merr; + + if (!(t = PyTuple_New(2))) return NULL; + if (!_mysql_server_init_done) { + e = _mysql_InternalError; +- PyTuple_SET_ITEM(t, 0, PyInt_FromLong(-1L)); +- PyTuple_SET_ITEM(t, 1, PyString_FromString("server not initialized")); ++ PyTuple_SET_ITEM(t, 0, PyLong_FromLong(-1L)); ++ PyTuple_SET_ITEM(t, 1, PyUnicode_FromString("server not initialized")); + PyErr_SetObject(e, t); + Py_DECREF(t); + return NULL; +@@ -121,8 +104,8 @@ + if (!merr) + e = _mysql_InterfaceError; + else if (merr > CR_MAX_ERROR) { +- PyTuple_SET_ITEM(t, 0, PyInt_FromLong(-1L)); +- PyTuple_SET_ITEM(t, 1, PyString_FromString("error totally whack")); ++ PyTuple_SET_ITEM(t, 0, PyLong_FromLong(-1L)); ++ PyTuple_SET_ITEM(t, 1, PyUnicode_FromString("error totally whack")); + PyErr_SetObject(_mysql_InterfaceError, t); + Py_DECREF(t); + return NULL; +@@ -209,8 +192,12 @@ + e = _mysql_OperationalError; + break; + } +- PyTuple_SET_ITEM(t, 0, PyInt_FromLong((long)merr)); +- PyTuple_SET_ITEM(t, 1, PyString_FromString(mysql_error(&(c->connection)))); ++ code = PyLong_FromLong((long)merr); ++ message = PyUnicode_FromString(mysql_error(&(c->connection))); ++ PyTuple_SET_ITEM(t, 0, code ); ++ PyTuple_SET_ITEM(t, 1, message ); ++ PyObject_SetAttrString(e, "code", code ); ++ PyObject_SetAttrString(e, "message", message ); + PyErr_SetObject(e, t); + Py_DECREF(t); + return NULL; +@@ -259,7 +246,7 @@ + cmd_args_c = (char **) PyMem_Malloc(cmd_argc*sizeof(char *)); + for (i=0; i< cmd_argc; i++) { + item = PySequence_GetItem(cmd_args, i); +- s = PyString_AsString(item); ++ s = PyBytes_AsString(item); + Py_DECREF(item); + if (!s) { + PyErr_SetString(PyExc_TypeError, +@@ -284,7 +271,7 @@ + groups_c = (char **) PyMem_Malloc((1+groupc)*sizeof(char *)); + for (i=0; i< groupc; i++) { + item = PySequence_GetItem(groups, i); +- s = PyString_AsString(item); ++ s = PyBytes_AsString(item); + Py_DECREF(item); + if (!s) { + PyErr_SetString(PyExc_TypeError, +@@ -339,7 +326,7 @@ + PyObject *flag; + if (!PyArg_ParseTuple(args, "")) return NULL; + check_server_init(NULL); +- if (!(flag=PyInt_FromLong((long)mysql_thread_safe()))) return NULL; ++ if (!(flag=PyLong_FromLong((long)mysql_thread_safe()))) return NULL; + return flag; + } + #endif +@@ -372,7 +359,7 @@ + return -1; + if (!conv) conv = PyDict_New(); + if (!conv) return -1; +- self->conn = (PyObject *) conn; ++ self->conn = conn; + Py_INCREF(conn); + self->use = use; + Py_BEGIN_ALLOW_THREADS ; +@@ -392,7 +379,7 @@ + fields = mysql_fetch_fields(result); + for (i=0; i= 0x02020000 + static int _mysql_ResultObject_traverse( + _mysql_ResultObject *self, + visitproc visit, +@@ -451,10 +437,9 @@ + if (!(r = visit(self->converter, arg))) return r; + } + if (self->conn) +- return visit(self->conn, arg); ++ return visit((PyObject *)self->conn, arg); + return 0; + } +-#endif + + static int _mysql_ResultObject_clear( + _mysql_ResultObject *self) +@@ -515,7 +500,7 @@ + return -1; + + #define _stringsuck(d,t,s) {t=PyMapping_GetItemString(s,#d);\ +- if(t){d=PyString_AsString(t);Py_DECREF(t);}\ ++ if(t){d=PyBytes_AsString(t);Py_DECREF(t);}\ + PyErr_Clear();} + + if (ssl) { +@@ -663,7 +648,6 @@ + return (PyObject *) c; + } + +-#if PY_VERSION_HEX >= 0x02020000 + static int _mysql_ConnectionObject_traverse( + _mysql_ConnectionObject *self, + visitproc visit, +@@ -673,7 +657,7 @@ + return visit(self->converter, arg); + return 0; + } +-#endif ++ + + static int _mysql_ConnectionObject_clear( + _mysql_ConnectionObject *self) +@@ -862,7 +846,7 @@ + #endif + Py_END_ALLOW_THREADS + if (err > 0) return _mysql_Exception(self); +- return PyInt_FromLong(err); ++ return PyLong_FromLong(err); + } + + #if MYSQL_VERSION_ID >= 40100 +@@ -885,7 +869,7 @@ + err = mysql_set_server_option(&(self->connection), flags); + Py_END_ALLOW_THREADS + if (err) return _mysql_Exception(self); +- return PyInt_FromLong(err); ++ return PyLong_FromLong(err); + } + + static char _mysql_ConnectionObject_sqlstate__doc__[] = +@@ -906,7 +890,7 @@ + PyObject *args) + { + if (!PyArg_ParseTuple(args, "")) return NULL; +- return PyString_FromString(mysql_sqlstate(&(self->connection))); ++ return PyUnicode_FromString(mysql_sqlstate(&(self->connection))); + } + + static char _mysql_ConnectionObject_warning_count__doc__[] = +@@ -921,7 +905,7 @@ + PyObject *args) + { + if (!PyArg_ParseTuple(args, "")) return NULL; +- return PyInt_FromLong(mysql_warning_count(&(self->connection))); ++ return PyLong_FromLong(mysql_warning_count(&(self->connection))); + } + + #endif +@@ -939,7 +923,7 @@ + { + if (!PyArg_ParseTuple(args, "")) return NULL; + check_connection(self); +- return PyInt_FromLong((long)mysql_errno(&(self->connection))); ++ return PyLong_FromLong((long)mysql_errno(&(self->connection))); + } + + static char _mysql_ConnectionObject_error__doc__[] = +@@ -955,7 +939,7 @@ + { + if (!PyArg_ParseTuple(args, "")) return NULL; + check_connection(self); +- return PyString_FromString(mysql_error(&(self->connection))); ++ return PyUnicode_FromString(mysql_error(&(self->connection))); + } + + static char _mysql_escape_string__doc__[] = +@@ -966,18 +950,14 @@ + probably better off using connection.escape(o) instead, since\n\ + it will escape entire sequences as well as strings."; + +-static PyObject * +-_mysql_escape_string( +- _mysql_ConnectionObject *self, +- PyObject *args) ++static PyObject *_mysql_ConnectionObject_escape_string( _mysql_ConnectionObject *self, PyObject *args) + { + PyObject *str; + char *in, *out; + int len, size; + if (!PyArg_ParseTuple(args, "s#:escape_string", &in, &size)) return NULL; +- str = PyString_FromStringAndSize((char *) NULL, size*2+1); +- if (!str) return PyErr_NoMemory(); +- out = PyString_AS_STRING(str); ++ out = PyMem_New(char, size*2+1); ++ if (!out) return PyErr_NoMemory(); + #if MYSQL_VERSION_ID < 32321 + len = mysql_escape_string(out, in, size); + #else +@@ -987,10 +967,16 @@ + else + len = mysql_escape_string(out, in, size); + #endif +- if (_PyString_Resize(&str, len) < 0) return NULL; ++ str = PyUnicode_FromString(out); ++ PyMem_Del(out); + return (str); + } + ++static PyObject *_mysql_escape_string( PyObject *self, PyObject *args) ++{ ++ return _mysql_ConnectionObject_escape_string(NULL, args); ++} ++ + static char _mysql_string_literal__doc__[] = + "string_literal(obj) -- converts object obj into a SQL string literal.\n\ + This means, any special SQL characters are escaped, and it is enclosed\n\ +@@ -1001,43 +987,50 @@ + Use connection.string_literal(obj), if you use it at all.\n\ + _mysql.string_literal(obj) cannot handle character sets."; + +-static PyObject * +-_mysql_string_literal( +- _mysql_ConnectionObject *self, +- PyObject *args) ++static PyObject *_mysql_ConnectionObject_string_literal(_mysql_ConnectionObject *self, PyObject *args) + { +- PyObject *str, *s, *o, *d; ++ PyObject *str, *s, *s2, *o, *d; + char *in, *out; + int len, size; + if (!PyArg_ParseTuple(args, "O|O:string_literal", &o, &d)) return NULL; + s = PyObject_Str(o); + if (!s) return NULL; +- in = PyString_AsString(s); +- size = PyString_GET_SIZE(s); +- str = PyString_FromStringAndSize((char *) NULL, size*2+3); +- if (!str) return PyErr_NoMemory(); +- out = PyString_AS_STRING(str); ++ s2 = PyUnicode_AsUTF8String(s); ++ if (!s2) return NULL; ++ in = PyBytes_AsString(s2); ++ if (!in) return NULL; ++ size = PyBytes_GET_SIZE(s2); ++ out = PyMem_New(char, size*2+3); ++ if (!out) return PyErr_NoMemory(); + #if MYSQL_VERSION_ID < 32321 + len = mysql_escape_string(out+1, in, size); + #else + check_server_init(NULL); +- if (self && self->open) ++ if (self && self->open ) ++ { + len = mysql_real_escape_string(&(self->connection), out+1, in, size); +- else ++ } else ++ { + len = mysql_escape_string(out+1, in, size); ++ }; + #endif + *out = *(out+len+1) = '\''; +- if (_PyString_Resize(&str, len+2) < 0) return NULL; ++ *(out+len+2) = '\0'; ++ str = PyUnicode_FromString(out); ++ PyMem_Del(out); ++ Py_DECREF(s2); + Py_DECREF(s); + return (str); + } + ++static PyObject *_mysql_string_literal(PyObject *self, PyObject *args) ++{ ++ return _mysql_ConnectionObject_string_literal(NULL, args); ++} ++ + static PyObject *_mysql_NULL; + +-static PyObject * +-_escape_item( +- PyObject *item, +- PyObject *d) ++static PyObject *_escape_item( PyObject *item, PyObject *d) + { + PyObject *quoted=NULL, *itemtype, *itemconv; + if (!(itemtype = PyObject_Type(item))) +@@ -1047,11 +1040,11 @@ + if (!itemconv) { + PyErr_Clear(); + itemconv = PyObject_GetItem(d, +- (PyObject *) &PyString_Type); ++ (PyObject *) &PyUnicode_Type); + } + if (!itemconv) { + PyErr_SetString(PyExc_TypeError, +- "no default type converter defined"); ++ "no default type converter defined"); + goto error; + } + quoted = PyObject_CallFunction(itemconv, "OO", item, d); +@@ -1064,32 +1057,33 @@ + "escape(obj, dict) -- escape any special characters in object obj\n\ + using mapping dict to provide quoting functions for each type.\n\ + Returns a SQL literal string."; +-static PyObject * +-_mysql_escape( +- PyObject *self, +- PyObject *args) ++static PyObject *_mysql_ConnectionObject_escape( _mysql_ConnectionObject *self, PyObject *args) + { + PyObject *o=NULL, *d=NULL; + if (!PyArg_ParseTuple(args, "O|O:escape", &o, &d)) + return NULL; + if (d) { + if (!PyMapping_Check(d)) { +- PyErr_SetString(PyExc_TypeError, +- "argument 2 must be a mapping"); ++ PyErr_SetString(PyExc_TypeError, "argument 2 must be a mapping"); + return NULL; + } + return _escape_item(o, d); +- } else { +- if (!self) { +- PyErr_SetString(PyExc_TypeError, +- "argument 2 must be a mapping"); ++ } else ++ { ++ if (!self) ++ { ++ PyErr_SetString(PyExc_TypeError, "argument 2 must be a mapping"); + return NULL; + } +- return _escape_item(o, +- ((_mysql_ConnectionObject *) self)->converter); ++ return _escape_item(o, self->converter); + } + } + ++static PyObject *_mysql_escape( PyObject *self, PyObject *args) ++{ ++ return _mysql_ConnectionObject_escape(NULL, args); ++} ++ + static char _mysql_escape_sequence__doc__[] = + "escape_sequence(seq, dict) -- escape any special characters in sequence\n\ + seq using mapping dict to provide quoting functions for each type.\n\ +@@ -1160,20 +1154,28 @@ + the Cursor.description attribute.\n\ + "; + +-static PyObject * +-_mysql_ResultObject_describe( +- _mysql_ResultObject *self, +- PyObject *args) ++static PyObject * _mysql_ResultObject_describe ( _mysql_ResultObject *self, PyObject *args) + { +- PyObject *d; ++ PyObject *d = NULL; + MYSQL_FIELD *fields; + unsigned int i, n; +- if (!PyArg_ParseTuple(args, "")) return NULL; ++ ++ if ( !PyArg_ParseTuple(args, "")) ++ { ++ return NULL; ++ }; ++ + check_result_connection(self); ++ + n = mysql_num_fields(self->result); + fields = mysql_fetch_fields(self->result); +- if (!(d = PyTuple_New(n))) return NULL; +- for (i=0; iresult); + if (!(r = PyTuple_New(n))) return NULL; + length = mysql_fetch_lengths(self->result); ++ ++#if MYSQL_VERSION_ID >= 32321 ++ charset = mysql_character_set_name(&(self->conn->connection)); ++#else ++ charset = "latin1"; ++#endif ++ + for (i=0; iconverter, i); +- v = _mysql_field_to_python(c, row[i], length[i]); ++ v = _mysql_field_to_python(c, row[i], length[i], charset); + if (!v) goto error; + PyTuple_SET_ITEM(r, i, v); + } +@@ -1278,16 +1308,24 @@ + unsigned int n, i; + unsigned long *length; + PyObject *r, *c; +- MYSQL_FIELD *fields; ++ MYSQL_FIELD *fields; ++ const char *charset; + + n = mysql_num_fields(self->result); + if (!(r = PyDict_New())) return NULL; + length = mysql_fetch_lengths(self->result); + fields = mysql_fetch_fields(self->result); ++ ++#if MYSQL_VERSION_ID >= 32321 ++ charset = mysql_character_set_name(&(self->conn->connection)); ++#else ++ charset = "latin1"; ++#endif ++ + for (i=0; iconverter, i); +- v = _mysql_field_to_python(c, row[i], length[i]); ++ v = _mysql_field_to_python(c, row[i], length[i], charset); + if (!v) goto error; + if (!PyMapping_HasKeyString(r, fields[i].name)) { + PyMapping_SetItemString(r, fields[i].name, v); +@@ -1317,16 +1355,24 @@ + unsigned int n, i; + unsigned long *length; + PyObject *r, *c; +- MYSQL_FIELD *fields; ++ MYSQL_FIELD *fields; ++ const char *charset; + + n = mysql_num_fields(self->result); + if (!(r = PyDict_New())) return NULL; + length = mysql_fetch_lengths(self->result); + fields = mysql_fetch_fields(self->result); ++ ++#if MYSQL_VERSION_ID >= 32321 ++ charset = mysql_character_set_name(&(self->conn->connection)); ++#else ++ charset = "latin1"; ++#endif ++ + for (i=0; iconverter, i); +- v = _mysql_field_to_python(c, row[i], length[i]); ++ v = _mysql_field_to_python(c, row[i], length[i], charset); + if (!v) goto error; + { + int len=0; +@@ -1354,8 +1400,8 @@ + _mysql__fetch_row( + _mysql_ResultObject *self, + PyObject **r, +- int skiprows, +- int maxrows, ++ unsigned int skiprows, ++ unsigned int maxrows, + _PYFUNC *convert_row) + { + unsigned int i; +@@ -1516,7 +1562,7 @@ + #else + s = "latin1"; + #endif +- return PyString_FromString(s); ++ return PyUnicode_FromString(s); + } + + #if MYSQL_VERSION_ID >= 50007 +@@ -1578,15 +1624,15 @@ + mysql_get_character_set_info(&(self->connection), &cs); + if (!(result = PyDict_New())) return NULL; + if (cs.csname) +- PyDict_SetItemString(result, "name", PyString_FromString(cs.csname)); ++ PyDict_SetItemString(result, "name", PyUnicode_FromString(cs.csname)); + if (cs.name) +- PyDict_SetItemString(result, "collation", PyString_FromString(cs.name)); ++ PyDict_SetItemString(result, "collation", PyUnicode_FromString(cs.name)); + if (cs.comment) +- PyDict_SetItemString(result, "comment", PyString_FromString(cs.comment)); ++ PyDict_SetItemString(result, "comment", PyUnicode_FromString(cs.comment)); + if (cs.dir) +- PyDict_SetItemString(result, "dir", PyString_FromString(cs.dir)); +- PyDict_SetItemString(result, "mbminlen", PyInt_FromLong(cs.mbminlen)); +- PyDict_SetItemString(result, "mbmaxlen", PyInt_FromLong(cs.mbmaxlen)); ++ PyDict_SetItemString(result, "dir", PyUnicode_FromString(cs.dir)); ++ PyDict_SetItemString(result, "mbminlen", PyLong_FromLong(cs.mbminlen)); ++ PyDict_SetItemString(result, "mbmaxlen", PyLong_FromLong(cs.mbmaxlen)); + return result; + } + #endif +@@ -1596,12 +1642,12 @@ + the client library version."; + static PyObject * + _mysql_get_client_info( +- PyObject *self, +- PyObject *args) ++ PyObject *self, ++ PyObject *args) + { + if (!PyArg_ParseTuple(args, "")) return NULL; + check_server_init(NULL); +- return PyString_FromString(mysql_get_client_info()); ++ return PyUnicode_FromString(mysql_get_client_info()); + } + + static char _mysql_ConnectionObject_get_host_info__doc__[] = +@@ -1616,7 +1662,7 @@ + { + if (!PyArg_ParseTuple(args, "")) return NULL; + check_connection(self); +- return PyString_FromString(mysql_get_host_info(&(self->connection))); ++ return PyUnicode_FromString(mysql_get_host_info(&(self->connection))); + } + + static char _mysql_ConnectionObject_get_proto_info__doc__[] = +@@ -1631,7 +1677,7 @@ + { + if (!PyArg_ParseTuple(args, "")) return NULL; + check_connection(self); +- return PyInt_FromLong((long)mysql_get_proto_info(&(self->connection))); ++ return PyLong_FromLong((long)mysql_get_proto_info(&(self->connection))); + } + + static char _mysql_ConnectionObject_get_server_info__doc__[] = +@@ -1646,7 +1692,7 @@ + { + if (!PyArg_ParseTuple(args, "")) return NULL; + check_connection(self); +- return PyString_FromString(mysql_get_server_info(&(self->connection))); ++ return PyUnicode_FromString(mysql_get_server_info(&(self->connection))); + } + + static char _mysql_ConnectionObject_info__doc__[] = +@@ -1664,7 +1710,7 @@ + if (!PyArg_ParseTuple(args, "")) return NULL; + check_connection(self); + s = mysql_info(&(self->connection)); +- if (s) return PyString_FromString(s); ++ if (s) return PyUnicode_FromString(s); + Py_INCREF(Py_None); + return Py_None; + } +@@ -1739,9 +1785,9 @@ + if (!PyArg_ParseTuple(args, "")) return NULL; + check_connection(self); + #if MYSQL_VERSION_ID < 32224 +- return PyInt_FromLong((long)mysql_num_fields(&(self->connection))); ++ return PyNumber_FromLong((long)mysql_num_fields(&(self->connection))); + #else +- return PyInt_FromLong((long)mysql_field_count(&(self->connection))); ++ return PyLong_FromLong((long)mysql_field_count(&(self->connection))); + #endif + } + +@@ -1755,7 +1801,7 @@ + { + if (!PyArg_ParseTuple(args, "")) return NULL; + check_result_connection(self); +- return PyInt_FromLong((long)mysql_num_fields(self->result)); ++ return PyLong_FromLong((long)mysql_num_fields(self->result)); + } + + static char _mysql_ResultObject_num_rows__doc__[] = +@@ -1907,7 +1953,7 @@ + s = mysql_stat(&(self->connection)); + Py_END_ALLOW_THREADS + if (!s) return _mysql_Exception(self); +- return PyString_FromString(s); ++ return PyUnicode_FromString(s); + } + + static char _mysql_ConnectionObject_store_result__doc__[] = +@@ -1968,7 +2014,7 @@ + Py_BEGIN_ALLOW_THREADS + pid = mysql_thread_id(&(self->connection)); + Py_END_ALLOW_THREADS +- return PyInt_FromLong((long)pid); ++ return PyLong_FromLong((long)pid); + } + + static char _mysql_ConnectionObject_use_result__doc__[] = +@@ -2033,7 +2079,7 @@ + else + sprintf(buf, "<_mysql.connection closed at %lx>", + (long)self); +- return PyString_FromString(buf); ++ return PyUnicode_FromString(buf); + } + + static char _mysql_ResultObject_data_seek__doc__[] = +@@ -2089,7 +2135,7 @@ + return NULL; + } + r = mysql_row_tell(self->result); +- return PyInt_FromLong(r-self->result->data->data); ++ return PyLong_FromLong(r-self->result->data->data); + } + + static void +@@ -2109,7 +2155,7 @@ + char buf[300]; + sprintf(buf, "<_mysql.result object at %lx>", + (long)self); +- return PyString_FromString(buf); ++ return PyUnicode_FromString(buf); + } + + static PyMethodDef _mysql_ConnectionObject_methods[] = { +@@ -2207,13 +2253,13 @@ + }, + { + "escape", +- (PyCFunction)_mysql_escape, ++ (PyCFunction)_mysql_ConnectionObject_escape, + METH_VARARGS, + _mysql_escape__doc__ + }, + { + "escape_string", +- (PyCFunction)_mysql_escape_string, ++ (PyCFunction)_mysql_ConnectionObject_escape_string, + METH_VARARGS, + _mysql_escape_string__doc__ + }, +@@ -2309,7 +2355,7 @@ + }, + { + "string_literal", +- (PyCFunction)_mysql_string_literal, ++ (PyCFunction)_mysql_ConnectionObject_string_literal, + METH_VARARGS, + _mysql_string_literal__doc__}, + { +@@ -2332,7 +2378,7 @@ + "open", + T_INT, + offsetof(_mysql_ConnectionObject,open), +- RO, ++ READONLY, + "True if connection is open" + ), + MyMember( +@@ -2346,20 +2392,20 @@ + "server_capabilities", + T_UINT, + offsetof(_mysql_ConnectionObject,connection.server_capabilities), +- RO, ++ READONLY, + "Capabilites of server; consult MySQLdb.constants.CLIENT" + ), + MyMember( + "port", + T_UINT, + offsetof(_mysql_ConnectionObject,connection.port), +- RO, ++ READONLY, + "TCP/IP port of the server connection" + ), + MyMember( + "client_flag", + T_UINT, +- RO, ++ READONLY, + offsetof(_mysql_ConnectionObject,connection.client_flag), + "Client flags; refer to MySQLdb.constants.CLIENT" + ), +@@ -2423,127 +2469,22 @@ + "converter", + T_OBJECT, + offsetof(_mysql_ResultObject,converter), +- RO, ++ READONLY, + "Type conversion mapping" + ), + {NULL} /* Sentinel */ + }; +- +-static PyObject * +-_mysql_ConnectionObject_getattr( +- _mysql_ConnectionObject *self, +- char *name) +-{ +- PyObject *res; +- +- res = Py_FindMethod(_mysql_ConnectionObject_methods, (PyObject *)self, name); +- if (res != NULL) +- return res; +- PyErr_Clear(); +- if (strcmp(name, "closed") == 0) +- return PyInt_FromLong((long)!(self->open)); +-#if PY_VERSION_HEX < 0x02020000 +- return PyMember_Get((char *)self, _mysql_ConnectionObject_memberlist, name); +-#else +- { +- MyMemberlist(*l); +- for (l = _mysql_ConnectionObject_memberlist; l->name != NULL; l++) { +- if (strcmp(l->name, name) == 0) +- return PyMember_GetOne((char *)self, l); +- } +- PyErr_SetString(PyExc_AttributeError, name); +- return NULL; +- } +-#endif +-} +- +-static PyObject * +-_mysql_ResultObject_getattr( +- _mysql_ResultObject *self, +- char *name) +-{ +- PyObject *res; +- +- res = Py_FindMethod(_mysql_ResultObject_methods, (PyObject *)self, name); +- if (res != NULL) +- return res; +- PyErr_Clear(); +-#if PY_VERSION_HEX < 0x02020000 +- return PyMember_Get((char *)self, _mysql_ResultObject_memberlist, name); +-#else +- { +- MyMemberlist(*l); +- for (l = _mysql_ResultObject_memberlist; l->name != NULL; l++) { +- if (strcmp(l->name, name) == 0) +- return PyMember_GetOne((char *)self, l); +- } +- PyErr_SetString(PyExc_AttributeError, name); +- return NULL; +- } +-#endif +-} +- +-static int +-_mysql_ConnectionObject_setattr( +- _mysql_ConnectionObject *self, +- char *name, +- PyObject *v) +-{ +- if (v == NULL) { +- PyErr_SetString(PyExc_AttributeError, +- "can't delete connection attributes"); +- return -1; +- } +-#if PY_VERSION_HEX < 0x02020000 +- return PyMember_Set((char *)self, _mysql_ConnectionObject_memberlist, name, v); +-#else +- { +- MyMemberlist(*l); +- for (l = _mysql_ConnectionObject_memberlist; l->name != NULL; l++) +- if (strcmp(l->name, name) == 0) +- return PyMember_SetOne((char *)self, l, v); +- } +- PyErr_SetString(PyExc_AttributeError, name); +- return -1; +-#endif +-} +- +-static int +-_mysql_ResultObject_setattr( +- _mysql_ResultObject *self, +- char *name, +- PyObject *v) +-{ +- if (v == NULL) { +- PyErr_SetString(PyExc_AttributeError, +- "can't delete connection attributes"); +- return -1; +- } +-#if PY_VERSION_HEX < 0x02020000 +- return PyMember_Set((char *)self, _mysql_ResultObject_memberlist, name, v); +-#else +- { +- MyMemberlist(*l); +- for (l = _mysql_ResultObject_memberlist; l->name != NULL; l++) +- if (strcmp(l->name, name) == 0) +- return PyMember_SetOne((char *)self, l, v); +- } +- PyErr_SetString(PyExc_AttributeError, name); +- return -1; +-#endif +-} + + PyTypeObject _mysql_ConnectionObject_Type = { +- PyObject_HEAD_INIT(NULL) +- 0, ++ PyVarObject_HEAD_INIT(NULL, 0) + "_mysql.connection", /* (char *)tp_name For printing */ + sizeof(_mysql_ConnectionObject), + 0, + (destructor)_mysql_ConnectionObject_dealloc, /* tp_dealloc */ +- 0, /*tp_print*/ +- (getattrfunc)_mysql_ConnectionObject_getattr, /* tp_getattr */ +- (setattrfunc)_mysql_ConnectionObject_setattr, /* tp_setattr */ +- 0, /*tp_compare*/ ++ 0, /* tp_print*/ ++ 0, /* tp_getattr */ ++ 0, /* tp_setattr */ ++ 0, /* tp_compare*/ + (reprfunc)_mysql_ConnectionObject_repr, /* tp_repr */ + + /* Method suites for standard classes */ +@@ -2564,33 +2505,20 @@ + 0, /* (PyBufferProcs *) tp_as_buffer */ + + /* Flags to define presence of optional/expanded features */ +-#if PY_VERSION_HEX < 0x02020000 +- Py_TPFLAGS_DEFAULT, /* (long) tp_flags */ +-#else + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, +-#endif + _mysql_connect__doc__, /* (char *) tp_doc Documentation string */ +-#if PY_VERSION_HEX >= 0x02000000 + /* Assigned meaning in release 2.0 */ +-#if PY_VERSION_HEX >= 0x02020000 + /* call function for all accessible objects */ + (traverseproc) _mysql_ConnectionObject_traverse, /* tp_traverse */ + + /* delete references to contained objects */ + (inquiry) _mysql_ConnectionObject_clear, /* tp_clear */ +-#else +- /* not supporting pre-2.2 GC */ +- 0, +- 0, +-#endif +-#if PY_VERSION_HEX >= 0x02010000 + /* Assigned meaning in release 2.1 */ + /* rich comparisons */ + 0, /* (richcmpfunc) tp_richcompare */ + + /* weak reference enabler */ + 0, /* (long) tp_weaklistoffset */ +-#if PY_VERSION_HEX >= 0x02020000 + /* Added in release 2.2 */ + /* Iterators */ + 0, /* (getiterfunc) tp_iter */ +@@ -2612,22 +2540,18 @@ + 0, /* (PyObject *) tp_bases */ + 0, /* (PyObject *) tp_mro method resolution order */ + 0, /* (PyObject *) tp_defined */ +-#endif /* python 2.2 */ +-#endif /* python 2.1 */ +-#endif /* python 2.0 */ + } ; + + PyTypeObject _mysql_ResultObject_Type = { +- PyObject_HEAD_INIT(NULL) +- 0, ++ PyVarObject_HEAD_INIT(NULL, 0) + "_mysql.result", + sizeof(_mysql_ResultObject), + 0, + (destructor)_mysql_ResultObject_dealloc, /* tp_dealloc */ +- 0, /*tp_print*/ +- (getattrfunc)_mysql_ResultObject_getattr, /* tp_getattr */ +- (setattrfunc)_mysql_ResultObject_setattr, /* tp_setattr */ +- 0, /*tp_compare*/ ++ 0, /* tp_print */ ++ 0, /* tp_getattr */ ++ 0, /* tp_setattr */ ++ 0, /* tp_compare */ + (reprfunc)_mysql_ResultObject_repr, /* tp_repr */ + + /* Method suites for standard classes */ +@@ -2648,34 +2572,20 @@ + 0, /* (PyBufferProcs *) tp_as_buffer */ + + /* Flags to define presence of optional/expanded features */ +-#if PY_VERSION_HEX < 0x02020000 +- Py_TPFLAGS_DEFAULT, /* (long) tp_flags */ +-#else + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, +-#endif +- + _mysql_ResultObject__doc__, /* (char *) tp_doc Documentation string */ +-#if PY_VERSION_HEX >= 0x02000000 + /* Assigned meaning in release 2.0 */ +-#if PY_VERSION_HEX >= 0x02020000 + /* call function for all accessible objects */ + (traverseproc) _mysql_ResultObject_traverse, /* tp_traverse */ + + /* delete references to contained objects */ + (inquiry) _mysql_ResultObject_clear, /* tp_clear */ +-#else +- /* not supporting pre-2.2 GC */ +- 0, +- 0, +-#endif +-#if PY_VERSION_HEX >= 0x02010000 + /* Assigned meaning in release 2.1 */ + /* rich comparisons */ + 0, /* (richcmpfunc) tp_richcompare */ + + /* weak reference enabler */ + 0, /* (long) tp_weaklistoffset */ +-#if PY_VERSION_HEX >= 0x02020000 + /* Added in release 2.2 */ + /* Iterators */ + 0, /* (getiterfunc) tp_iter */ +@@ -2697,13 +2607,9 @@ + 0, /* (PyObject *) tp_bases */ + 0, /* (PyObject *) tp_mro method resolution order */ + 0, /* (PyObject *) tp_defined */ +-#endif /* python 2.2 */ +-#endif /* python 2.1 */ +-#endif /* python 2.0 */ + }; + +-static PyMethodDef +-_mysql_methods[] = { ++static PyMethodDef _mysql_methods[] = { + { + "connect", + (PyCFunction)_mysql_connect, +@@ -2775,16 +2681,11 @@ + {NULL, NULL} /* sentinel */ + }; + +-static PyObject * +-_mysql_NewException( +- PyObject *dict, +- PyObject *edict, +- char *name) ++static PyObject *_mysql_NewException( PyObject *dict, PyObject *edict, char *name) + { + PyObject *e; + +- if (!(e = PyDict_GetItemString(edict, name))) +- return NULL; ++ if (!(e = PyDict_GetItemString(edict, name))) return NULL; + if (PyDict_SetItemString(dict, name, e)) return NULL; + return e; + } +@@ -2806,85 +2707,111 @@ + (as of 3.23) are NOT implemented.\n\ + "; + +-DL_EXPORT(void) +-init_mysql(void) ++/* module definition */ ++static struct PyModuleDef mysqlModule = { ++ PyModuleDef_HEAD_INIT, ++ "_mysql", /* name of module */ ++ _mysql___doc__, /* module documentation */ ++ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ ++ _mysql_methods, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++}; ++ ++int CheckError() ++{ ++ if ( PyErr_Occurred() ) ++ { ++ PyErr_Print(); ++ PyErr_SetString(PyExc_ImportError, "_mysql: init failed"); ++ PyErr_Print(); ++ return -1; ++ }; ++ return 0; ++}; ++ ++PyMODINIT_FUNC PyInit__mysql(void) + { + PyObject *dict, *module, *emod, *edict; +- module = Py_InitModule4("_mysql", _mysql_methods, _mysql___doc__, +- (PyObject *)NULL, PYTHON_API_VERSION); +- if (!module) return; /* this really should never happen */ +- _mysql_ConnectionObject_Type.ob_type = &PyType_Type; +- _mysql_ResultObject_Type.ob_type = &PyType_Type; +-#if PY_VERSION_HEX >= 0x02020000 ++ ++ _mysql_ConnectionObject_Type.ob_base.ob_base.ob_type = &PyType_Type; ++ _mysql_ResultObject_Type.ob_base.ob_base.ob_type = &PyType_Type; + _mysql_ConnectionObject_Type.tp_alloc = PyType_GenericAlloc; + _mysql_ConnectionObject_Type.tp_new = PyType_GenericNew; +- _mysql_ConnectionObject_Type.tp_free = _PyObject_GC_Del; ++ _mysql_ConnectionObject_Type.tp_free = PyObject_GC_Del; + _mysql_ResultObject_Type.tp_alloc = PyType_GenericAlloc; + _mysql_ResultObject_Type.tp_new = PyType_GenericNew; +- _mysql_ResultObject_Type.tp_free = _PyObject_GC_Del; +-#endif ++ _mysql_ResultObject_Type.tp_free = PyObject_GC_Del; + +- if (!(dict = PyModule_GetDict(module))) goto error; +- if (PyDict_SetItemString(dict, "version_info", +- PyRun_String(QUOTE(version_info), Py_eval_input, +- dict, dict))) +- goto error; +- if (PyDict_SetItemString(dict, "__version__", +- PyString_FromString(QUOTE(__version__)))) +- goto error; +- if (PyDict_SetItemString(dict, "connection", +- (PyObject *)&_mysql_ConnectionObject_Type)) +- goto error; +- Py_INCREF(&_mysql_ConnectionObject_Type); +- if (PyDict_SetItemString(dict, "result", +- (PyObject *)&_mysql_ResultObject_Type)) +- goto error; +- Py_INCREF(&_mysql_ResultObject_Type); +- if (!(emod = PyImport_ImportModule("_mysql_exceptions"))) +- goto error; +- if (!(edict = PyModule_GetDict(emod))) goto error; +- if (!(_mysql_MySQLError = +- _mysql_NewException(dict, edict, "MySQLError"))) +- goto error; +- if (!(_mysql_Warning = +- _mysql_NewException(dict, edict, "Warning"))) +- goto error; +- if (!(_mysql_Error = +- _mysql_NewException(dict, edict, "Error"))) +- goto error; +- if (!(_mysql_InterfaceError = +- _mysql_NewException(dict, edict, "InterfaceError"))) +- goto error; +- if (!(_mysql_DatabaseError = +- _mysql_NewException(dict, edict, "DatabaseError"))) +- goto error; +- if (!(_mysql_DataError = +- _mysql_NewException(dict, edict, "DataError"))) +- goto error; +- if (!(_mysql_OperationalError = +- _mysql_NewException(dict, edict, "OperationalError"))) +- goto error; +- if (!(_mysql_IntegrityError = +- _mysql_NewException(dict, edict, "IntegrityError"))) +- goto error; +- if (!(_mysql_InternalError = +- _mysql_NewException(dict, edict, "InternalError"))) +- goto error; +- if (!(_mysql_ProgrammingError = +- _mysql_NewException(dict, edict, "ProgrammingError"))) +- goto error; +- if (!(_mysql_NotSupportedError = +- _mysql_NewException(dict, edict, "NotSupportedError"))) +- goto error; +- Py_DECREF(emod); +- if (!(_mysql_NULL = PyString_FromString("NULL"))) +- goto error; +- if (PyDict_SetItemString(dict, "NULL", _mysql_NULL)) goto error; +- error: +- if (PyErr_Occurred()) +- PyErr_SetString(PyExc_ImportError, +- "_mysql: init failed"); +- return; ++ if (PyType_Ready(&_mysql_ConnectionObject_Type) < 0) return NULL; ++ if (PyType_Ready(&_mysql_ResultObject_Type) < 0) return NULL; ++ ++ module = PyModule_Create2(&mysqlModule,PYTHON_API_VERSION); ++ ++ if (module == NULL) ++ { ++ return NULL; ++ }; ++ ++ dict = PyModule_GetDict(module); ++ if (PyDict_SetItemString(dict, "version_info", PyRun_String(QUOTE(version_info), Py_eval_input, dict, dict)) == -1) ++ { ++ } else if (PyDict_SetItemString(dict, "__version__", ++ PyUnicode_FromString(QUOTE(__version__))) == -1 ) ++ { ++ } else if (PyDict_SetItemString(dict, "connection", ++ (PyObject *)&_mysql_ConnectionObject_Type) == -1 ) ++ { ++ ++ } else ++ { ++ Py_INCREF(&_mysql_ConnectionObject_Type); ++ if ( PyDict_SetItemString(dict, "result",(PyObject *)&_mysql_ResultObject_Type) == -1 ) ++ { ++ ++ } else ++ { ++ Py_INCREF(&_mysql_ResultObject_Type); ++ emod = PyImport_ImportModule("_mysql_exceptions"); ++ if (emod != NULL ) ++ { ++ edict = PyModule_GetDict(emod); ++ _mysql_MySQLError = _mysql_NewException(dict, edict, "MySQLError"); ++ if (_mysql_MySQLError != NULL) ++ { ++ _mysql_Warning = _mysql_NewException(dict, edict, "Warning"); ++ _mysql_Error = _mysql_NewException(dict, edict, "Error"); ++ _mysql_InterfaceError = _mysql_NewException(dict, edict, "InterfaceError"); ++ _mysql_DatabaseError = _mysql_NewException(dict, edict, "DatabaseError"); ++ _mysql_DataError = _mysql_NewException(dict, edict, "DataError"); ++ _mysql_OperationalError = _mysql_NewException(dict, edict, "OperationalError"); ++ _mysql_IntegrityError = _mysql_NewException(dict, edict, "IntegrityError"); ++ _mysql_InternalError = _mysql_NewException(dict, edict, "InternalError"); ++ _mysql_ProgrammingError = _mysql_NewException(dict, edict, "ProgrammingError"); ++ _mysql_NotSupportedError = _mysql_NewException(dict, edict, "NotSupportedError"); ++ if ( _mysql_Warning != NULL && _mysql_Error != NULL && _mysql_InterfaceError != NULL && ++ _mysql_DatabaseError != NULL && _mysql_DataError != NULL && _mysql_OperationalError != NULL && ++ _mysql_IntegrityError != NULL && _mysql_InternalError != NULL && ++ _mysql_ProgrammingError != NULL && _mysql_NotSupportedError != NULL ++ ) ++ { ++ Py_DECREF(emod); ++ _mysql_NULL = PyUnicode_FromString("NULL"); ++ PyDict_SetItemString(dict, "NULL", _mysql_NULL); ++ }; ++ }; ++ }; ++ }; ++ }; ++ ++ if ( CheckError() == -1 ) ++ { ++ return NULL; ++ }; ++ ++ return module; + } + + +diff -ru MySQL-python-1.2.3/MySQLdb/connections.py MySQL-Python-1.2.3-python3/MySQLdb/connections.py +--- MySQL-python-1.2.3/MySQLdb/connections.py 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/MySQLdb/connections.py 2011-11-25 16:44:27.000000000 +0100 +@@ -6,7 +6,7 @@ + override Connection.default_cursor with a non-standard Cursor class. + + """ +-import cursors ++import MySQLdb.cursors + from _mysql_exceptions import Warning, Error, InterfaceError, DataError, \ + DatabaseError, OperationalError, IntegrityError, InternalError, \ + NotSupportedError, ProgrammingError +@@ -33,7 +33,7 @@ + connection.messages.append(error) + del cursor + del connection +- raise errorclass, errorvalue ++ raise errorclass(errorvalue) + + re_numeric_part = re.compile(r"^(\d+)") + +@@ -57,7 +57,7 @@ + + """MySQL Database Connection Object""" + +- default_cursor = cursors.Cursor ++ default_cursor = MySQLdb.cursors.Cursor + + def __init__(self, *args, **kwargs): + """ +@@ -109,17 +109,9 @@ + cursorclass + class object, used to create cursors (keyword only) + +- use_unicode +- If True, text-like columns are returned as unicode objects +- using the connection's character set. Otherwise, text-like +- columns are returned as strings. columns are returned as +- normal strings. Unicode objects will always be encoded to +- the connection's character set regardless of this setting. +- + charset + If supplied, the connection character set will be changed +- to this character set (MySQL-4.1 and newer). This implies +- use_unicode=True. ++ to this character set (MySQL-4.1 and newer). + + sql_mode + If supplied, the session SQL mode will be changed to this +@@ -143,15 +135,15 @@ + documentation for the MySQL C API for some hints on what they do. + + """ +- from constants import CLIENT, FIELD_TYPE +- from converters import conversions ++ from .constants import CLIENT, FIELD_TYPE ++ from .converters import conversions + from weakref import proxy, WeakValueDictionary + + import types + + kwargs2 = kwargs.copy() + +- if kwargs.has_key('conv'): ++ if 'conv' in kwargs: + conv = kwargs['conv'] + else: + conv = conversions +@@ -165,14 +157,8 @@ + kwargs2['conv'] = conv2 + + self.cursorclass = kwargs2.pop('cursorclass', self.default_cursor) +- charset = kwargs2.pop('charset', '') ++ charset = kwargs2.pop('charset', 'utf8') + +- if charset: +- use_unicode = True +- else: +- use_unicode = False +- +- use_unicode = kwargs2.pop('use_unicode', use_unicode) + sql_mode = kwargs2.pop('sql_mode', '') + + client_flag = kwargs.get('client_flag', 0) +@@ -197,19 +183,13 @@ + return db.string_literal(obj) + return string_literal + +- def _get_unicode_literal(): +- def unicode_literal(u, dummy=None): +- return db.literal(u.encode(unicode_literal.charset)) +- return unicode_literal +- +- def _get_string_decoder(): +- def string_decoder(s): +- return s.decode(string_decoder.charset) +- return string_decoder +- ++ def _get_bytes_literal(): ++ def bytes_literal(u, dummy=None): ++ return db.literal(u.decode(bytes_literal.charset)) ++ return bytes_literal ++ + string_literal = _get_string_literal() +- self.unicode_literal = unicode_literal = _get_unicode_literal() +- self.string_decoder = string_decoder = _get_string_decoder() ++ self.bytes_literal = bytes_literal = _get_bytes_literal() + if not charset: + charset = self.character_set_name() + self.set_character_set(charset) +@@ -217,14 +197,9 @@ + if sql_mode: + self.set_sql_mode(sql_mode) + +- if use_unicode: +- self.converter[FIELD_TYPE.STRING].append((None, string_decoder)) +- self.converter[FIELD_TYPE.VAR_STRING].append((None, string_decoder)) +- self.converter[FIELD_TYPE.VARCHAR].append((None, string_decoder)) +- self.converter[FIELD_TYPE.BLOB].append((None, string_decoder)) +- +- self.encoders[types.StringType] = string_literal +- self.encoders[types.UnicodeType] = unicode_literal ++ self.encoders[str] = string_literal ++ self.encoders[bytes] = bytes_literal ++ + self._transactional = self.server_capabilities & CLIENT.TRANSACTIONS + if self._transactional: + # PEP-249 requires autocommit to be initially off +@@ -297,8 +272,7 @@ + raise NotSupportedError("server is too old to set charset") + self.query('SET NAMES %s' % charset) + self.store_result() +- self.string_decoder.charset = charset +- self.unicode_literal.charset = charset ++ self.bytes_literal.charset = charset + + def set_sql_mode(self, sql_mode): + """Set the connection sql_mode. See MySQL documentation for +Pouze v MySQL-python-1.2.3/MySQLdb/constants: .cvsignore +Pouze v MySQL-Python-1.2.3-python3/MySQLdb/constants: __pycache__ +diff -ru MySQL-python-1.2.3/MySQLdb/converters.py MySQL-Python-1.2.3-python3/MySQLdb/converters.py +--- MySQL-python-1.2.3/MySQLdb/converters.py 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/MySQLdb/converters.py 2011-10-05 12:49:58.000000000 +0200 +@@ -33,9 +33,9 @@ + """ + + from _mysql import string_literal, escape_sequence, escape_dict, escape, NULL +-from constants import FIELD_TYPE, FLAG +-from times import * +-import types ++from .constants import FIELD_TYPE, FLAG ++from .times import * ++import datetime + import array + + try: +@@ -55,16 +55,16 @@ + """Convert something into a string via str().""" + return str(s) + +-def Unicode2Str(s, d): +- """Convert a unicode object to a string using the default encoding. ++def Bytes2Str(s, d): ++ """Convert a bytes object to a string using the default encoding. + This is only used as a placeholder for the real function, which + is connection-dependent.""" +- return s.encode() ++ return s.decode() + + Long2Int = Thing2Str + + def Float2Str(o, d): +- return '%.15g' % o ++ return '{:f}'.format(o) + + def None2NULL(o, d): + """Convert None to NULL.""" +@@ -115,30 +115,30 @@ + return Thing2Literal(o.tostring(), d) + + conversions = { +- types.IntType: Thing2Str, +- types.LongType: Long2Int, +- types.FloatType: Float2Str, +- types.NoneType: None2NULL, +- types.TupleType: escape_sequence, +- types.ListType: escape_sequence, +- types.DictType: escape_dict, +- types.InstanceType: Instance2Str, ++ int: Long2Int, ++ float: Float2Str, ++ type(None): None2NULL, ++ tuple: escape_sequence, ++ list: escape_sequence, ++ dict: escape_dict, ++ object: Instance2Str, + array.ArrayType: array2Str, +- types.StringType: Thing2Literal, # default +- types.UnicodeType: Unicode2Str, +- types.ObjectType: Instance2Str, +- types.BooleanType: Bool2Str, +- DateTimeType: DateTime2literal, +- DateTimeDeltaType: DateTimeDelta2literal, ++ str: Thing2Literal, # default ++ bytes: Bytes2Str, ++ bool: Bool2Str, ++ datetime.date: DateTime2literal, ++ datetime.time: DateTime2literal, ++ datetime.datetime: DateTime2literal, ++ datetime.timedelta: DateTimeDelta2literal, + set: Set2Str, + FIELD_TYPE.TINY: int, + FIELD_TYPE.SHORT: int, +- FIELD_TYPE.LONG: long, ++ FIELD_TYPE.LONG: int, + FIELD_TYPE.FLOAT: float, + FIELD_TYPE.DOUBLE: float, + FIELD_TYPE.DECIMAL: float, + FIELD_TYPE.NEWDECIMAL: float, +- FIELD_TYPE.LONGLONG: long, ++ FIELD_TYPE.LONGLONG: int, + FIELD_TYPE.INT24: int, + FIELD_TYPE.YEAR: int, + FIELD_TYPE.SET: Str2Set, +diff -ru MySQL-python-1.2.3/MySQLdb/cursors.py MySQL-Python-1.2.3-python3/MySQLdb/cursors.py +--- MySQL-python-1.2.3/MySQLdb/cursors.py 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/MySQLdb/cursors.py 2011-11-25 16:53:26.000000000 +0100 +@@ -7,7 +7,6 @@ + + import re + import sys +-from types import ListType, TupleType, UnicodeType + + + restr = (r"\svalues\s*" +@@ -153,13 +152,19 @@ + del self.messages[:] + db = self._get_db() + charset = db.character_set_name() +- if isinstance(query, unicode): +- query = query.encode(charset) ++ + if args is not None: ++ if isinstance(query, bytes): ++ query = query.decode(); ++ + query = query % db.literal(args) ++ ++ if isinstance(query, str): ++ query = query.encode(charset); ++ + try: + r = self._query(query) +- except TypeError, m: ++ except TypeError as m: + if m.args[0] in ("not enough arguments for format string", + "not all arguments converted"): + self.messages.append((ProgrammingError, m.args[0])) +@@ -197,8 +202,6 @@ + del self.messages[:] + db = self._get_db() + if not args: return +- charset = db.character_set_name() +- if isinstance(query, unicode): query = query.encode(charset) + m = insert_values.search(query) + if not m: + r = 0 +@@ -210,7 +213,7 @@ + qv = m.group(1) + try: + q = [ qv % db.literal(a) for a in args ] +- except TypeError, msg: ++ except TypeError as msg: + if msg.args[0] in ("not enough arguments for format string", + "not all arguments converted"): + self.errorhandler(self, ProgrammingError, msg.args[0]) +@@ -259,7 +262,7 @@ + for index, arg in enumerate(args): + q = "SET @_%s_%d=%s" % (procname, index, + db.literal(arg)) +- if isinstance(q, unicode): ++ if isinstance(q, str): + q = q.encode(charset) + self._query(q) + self.nextset() +@@ -267,7 +270,7 @@ + q = "CALL %s(%s)" % (procname, + ','.join(['@_%s_%d' % (procname, i) + for i in range(len(args))])) +- if type(q) is UnicodeType: ++ if type(q) is str: + q = q.encode(charset) + self._query(q) + self._executed = q +@@ -363,7 +366,7 @@ + r = value + else: + self.errorhandler(self, ProgrammingError, +- "unknown scroll mode %s" % `mode`) ++ "unknown scroll mode %r" % mode) + if r < 0 or r >= len(self._rows): + self.errorhandler(self, IndexError, "out of range") + self.rownumber = r +Pouze v MySQL-python-1.2.3/MySQLdb: .cvsignore +diff -ru MySQL-python-1.2.3/MySQLdb/__init__.py MySQL-Python-1.2.3-python3/MySQLdb/__init__.py +--- MySQL-python-1.2.3/MySQLdb/__init__.py 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/MySQLdb/__init__.py 2011-10-05 12:49:58.000000000 +0200 +@@ -14,7 +14,7 @@ + """ + + __revision__ = """$Revision: 603 $"""[11:-2] +-from release import __version__, version_info, __author__ ++from .release import __version__, version_info, __author__ + + import _mysql + +@@ -77,7 +77,7 @@ + + def Connect(*args, **kwargs): + """Factory function for connections.Connection.""" +- from connections import Connection ++ from .connections import Connection + return Connection(*args, **kwargs) + + connect = Connection = Connect +diff -ru MySQL-python-1.2.3/_mysql_exceptions.py MySQL-Python-1.2.3-python3/_mysql_exceptions.py +--- MySQL-python-1.2.3/_mysql_exceptions.py 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/_mysql_exceptions.py 2011-10-05 12:49:58.000000000 +0200 +@@ -5,9 +5,8 @@ + http://www.python.org/topics/database/DatabaseAPI-2.0.html + """ + +-from exceptions import Exception, StandardError, Warning + +-class MySQLError(StandardError): ++class MySQLError(Exception): + + """Exception related to operation with MySQL.""" + +@@ -80,4 +79,3 @@ + has transactions turned off.""" + + +-del Exception, StandardError +diff -ru MySQL-python-1.2.3/MySQL_python.egg-info/SOURCES.txt MySQL-Python-1.2.3-python3/MySQL_python.egg-info/SOURCES.txt +--- MySQL-python-1.2.3/MySQL_python.egg-info/SOURCES.txt 2010-06-17 09:22:07.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/MySQL_python.egg-info/SOURCES.txt 2011-11-25 16:54:24.000000000 +0100 +@@ -1,4 +1,3 @@ +-.cvsignore + HISTORY + MANIFEST.in + README +@@ -17,14 +16,12 @@ + MySQL_python.egg-info/SOURCES.txt + MySQL_python.egg-info/dependency_links.txt + MySQL_python.egg-info/top_level.txt +-MySQLdb/.cvsignore + MySQLdb/__init__.py + MySQLdb/connections.py + MySQLdb/converters.py + MySQLdb/cursors.py + MySQLdb/release.py + MySQLdb/times.py +-MySQLdb/constants/.cvsignore + MySQLdb/constants/CLIENT.py + MySQLdb/constants/CR.py + MySQLdb/constants/ER.py +@@ -32,7 +29,6 @@ + MySQLdb/constants/FLAG.py + MySQLdb/constants/REFRESH.py + MySQLdb/constants/__init__.py +-doc/.cvsignore + doc/FAQ.txt + doc/MySQLdb.txt + tests/capabilities.py +diff -ru MySQL-python-1.2.3/README MySQL-Python-1.2.3-python3/README +--- MySQL-python-1.2.3/README 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/README 2011-10-05 12:49:58.000000000 +0200 +@@ -8,22 +8,18 @@ + Prerequisites + ------------- + +-+ Python 2.3.4 or higher +++ Python 3.2 or higher + + * http://www.python.org/ + +- * Versions lower than 2.3 WON'T WORK. +- +- * 2.4 is the primary test environment. +- + * Red Hat Linux: + + - Make sure you have the Python development headers and libraries + (python-devel). + +-+ setuptools +++ distribute + +- * http://pypi.python.org/pypi/setuptools ++ * http://pypi.python.org/pypi/distribute/ + + + MySQL 3.23.32 or higher + +diff -ru MySQL-python-1.2.3/setup_common.py MySQL-Python-1.2.3-python3/setup_common.py +--- MySQL-python-1.2.3/setup_common.py 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/setup_common.py 2011-10-05 12:49:58.000000000 +0200 +@@ -1,4 +1,4 @@ +-from ConfigParser import SafeConfigParser ++from configparser import SafeConfigParser + + def get_metadata_and_options(): + config = SafeConfigParser() +@@ -7,8 +7,8 @@ + metadata = dict(config.items('metadata')) + options = dict(config.items('options')) + +- metadata['py_modules'] = filter(None, metadata['py_modules'].split('\n')) +- metadata['classifiers'] = filter(None, metadata['classifiers'].split('\n')) ++ metadata['py_modules'] = list(filter(None, metadata['py_modules'].split('\n'))) ++ metadata['classifiers'] = list(filter(None, metadata['classifiers'].split('\n'))) + + return metadata, options + +@@ -30,3 +30,4 @@ + __version__ = "%(version)s" + """ % metadata) + rel.close() ++ +diff -ru MySQL-python-1.2.3/setup_posix.py MySQL-Python-1.2.3-python3/setup_posix.py +--- MySQL-python-1.2.3/setup_posix.py 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/setup_posix.py 2011-11-25 17:13:11.000000000 +0100 +@@ -1,4 +1,4 @@ +-from ConfigParser import SafeConfigParser ++from configparser import SafeConfigParser + + # This dequote() business is required for some older versions + # of mysql_config +@@ -98,5 +98,5 @@ + return metadata, ext_options + + if __name__ == "__main__": +- print """You shouldn't be running this directly; it is used by setup.py.""" ++ print("""You shouldn't be running this directly; it is used by setup.py.""") + +diff -ru MySQL-python-1.2.3/setup.py MySQL-Python-1.2.3-python3/setup.py +--- MySQL-python-1.2.3/setup.py 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/setup.py 2011-10-05 12:49:58.000000000 +0200 +@@ -4,8 +4,8 @@ + import sys + from setuptools import setup, Extension + +-if not hasattr(sys, "hexversion") or sys.hexversion < 0x02030000: +- raise Error("Python 2.3 or newer is required") ++if not hasattr(sys, "hexversion") or sys.hexversion < 0x03000000: ++ raise Exception("Python 3.0 or newer is required") + + if os.name == "posix": + from setup_posix import get_config +diff -ru MySQL-python-1.2.3/setup_windows.py MySQL-Python-1.2.3-python3/setup_windows.py +--- MySQL-python-1.2.3/setup_windows.py 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/setup_windows.py 2011-10-05 12:49:58.000000000 +0200 +@@ -1,11 +1,11 @@ + def get_config(): +- import os, sys, _winreg ++ import os, sys, winreg + from setup_common import get_metadata_and_options, enabled, create_release_file + + metadata, options = get_metadata_and_options() + +- serverKey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, options['registry_key']) +- mysql_root, dummy = _winreg.QueryValueEx(serverKey,'Location') ++ serverKey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, options['registry_key']) ++ mysql_root, dummy = winreg.QueryValueEx(serverKey,options['location']) + + extra_objects = [] + static = enabled(options, 'static') +@@ -15,7 +15,7 @@ + else: + client = "mysqlclient" + +- library_dirs = [ os.path.join(mysql_root, r'lib\opt') ] ++ library_dirs = [ os.path.join(mysql_root, r'lib') ] + libraries = [ 'kernel32', 'advapi32', 'wsock32', client ] + include_dirs = [ os.path.join(mysql_root, r'include') ] + extra_compile_args = [ '/Zl' ] +@@ -43,5 +43,5 @@ + return metadata, ext_options + + if __name__ == "__main__": +- print """You shouldn't be running this directly; it is used by setup.py.""" ++ print ("""You shouldn't be running this directly; it is used by setup.py.""") + +diff -ru MySQL-python-1.2.3/site.cfg MySQL-Python-1.2.3-python3/site.cfg +--- MySQL-python-1.2.3/site.cfg 2010-06-17 09:21:56.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/site.cfg 2011-10-05 12:49:58.000000000 +0200 +@@ -15,4 +15,6 @@ + # The Windows registry key for MySQL. + # This has to be set for Windows builds to work. + # Only change this if you have a different version. +-registry_key = SOFTWARE\MySQL AB\MySQL Server 5.0 ++registry_key = SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{2DB39FB6-161E-44E7-B2A1-B654C85EFBC1} ++location = InstallLocation ++ +diff -ru MySQL-python-1.2.3/tests/capabilities.py MySQL-Python-1.2.3-python3/tests/capabilities.py +--- MySQL-python-1.2.3/tests/capabilities.py 2010-06-17 09:21:55.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/tests/capabilities.py 2011-10-05 12:49:58.000000000 +0200 +@@ -25,7 +25,7 @@ + self.connection = db + self.cursor = db.cursor() + self.BLOBText = ''.join([chr(i) for i in range(256)] * 100); +- self.BLOBUText = u''.join([unichr(i) for i in range(16384)]) ++ self.BLOBUText = ''.join([chr(i) for i in range(16384)]) + self.BLOBBinary = self.db_module.Binary(''.join([chr(i) for i in range(256)] * 16)) + + leak_test = True +@@ -35,11 +35,11 @@ + import gc + del self.cursor + orphans = gc.collect() +- self.failIf(orphans, "%d orphaned objects found after deleting cursor" % orphans) ++ self.assertFalse(orphans, "%d orphaned objects found after deleting cursor" % orphans) + + del self.connection + orphans = gc.collect() +- self.failIf(orphans, "%d orphaned objects found after deleting connection" % orphans) ++ self.assertFalse(orphans, "%d orphaned objects found after deleting connection" % orphans) + + def table_exists(self, name): + try: +@@ -81,18 +81,18 @@ + self.create_table(columndefs) + insert_statement = ('INSERT INTO %s VALUES (%s)' % + (self.table, +- ','.join(['%s'] * len(columndefs)))) ++ ','.join(['{!s}'] * len(columndefs)))) + data = [ [ generator(i,j) for j in range(len(columndefs)) ] + for i in range(self.rows) ] + if self.debug: +- print data ++ print(data) + self.cursor.executemany(insert_statement, data) + self.connection.commit() + # verify + self.cursor.execute('select * from %s' % self.table) + l = self.cursor.fetchall() + if self.debug: +- print l ++ print(l) + self.assertEquals(len(l), self.rows) + try: + for i in range(self.rows): +@@ -110,7 +110,7 @@ + self.create_table(columndefs) + insert_statement = ('INSERT INTO %s VALUES (%s)' % + (self.table, +- ','.join(['%s'] * len(columndefs)))) ++ ','.join(['{!s}'] * len(columndefs)))) + data = [ [ generator(i,j) for j in range(len(columndefs)) ] + for i in range(self.rows) ] + self.cursor.executemany(insert_statement, data) +@@ -122,33 +122,33 @@ + for i in range(self.rows): + for j in range(len(columndefs)): + self.assertEquals(l[i][j], generator(i,j)) +- delete_statement = 'delete from %s where col1=%%s' % self.table ++ delete_statement = 'delete from %s where col1={!s}' % self.table + self.cursor.execute(delete_statement, (0,)) + self.cursor.execute('select col1 from %s where col1=%s' % \ + (self.table, 0)) + l = self.cursor.fetchall() +- self.failIf(l, "DELETE didn't work") ++ self.assertFalse(l, "DELETE didn't work") + self.connection.rollback() + self.cursor.execute('select col1 from %s where col1=%s' % \ + (self.table, 0)) + l = self.cursor.fetchall() +- self.failUnless(len(l) == 1, "ROLLBACK didn't work") ++ self.assertTrue(len(l) == 1, "ROLLBACK didn't work") + self.cursor.execute('drop table %s' % (self.table)) + + def test_truncation(self): + columndefs = ( 'col1 INT', 'col2 VARCHAR(255)') + def generator(row, col): + if col == 0: return row +- else: return ('%i' % (row%10))*((255-self.rows/2)+row) ++ else: return ('{:d}'.format(row%10))*(round(255-self.rows/2)+row) + self.create_table(columndefs) + insert_statement = ('INSERT INTO %s VALUES (%s)' % + (self.table, +- ','.join(['%s'] * len(columndefs)))) ++ ','.join(['{!s}'] * len(columndefs)))) + + try: + self.cursor.execute(insert_statement, (0, '0'*256)) + except Warning: +- if self.debug: print self.cursor.messages ++ if self.debug: print(self.cursor.messages) + except self.connection.DataError: + pass + else: +@@ -163,7 +163,7 @@ + data.append(generator(i,j)) + self.cursor.execute(insert_statement,tuple(data)) + except Warning: +- if self.debug: print self.cursor.messages ++ if self.debug: print(self.cursor.messages) + except self.connection.DataError: + pass + else: +@@ -176,7 +176,7 @@ + for i in range(self.rows) ] + self.cursor.executemany(insert_statement, data) + except Warning: +- if self.debug: print self.cursor.messages ++ if self.debug: print(self.cursor.messages) + except self.connection.DataError: + pass + else: +diff -ru MySQL-python-1.2.3/tests/dbapi20.py MySQL-Python-1.2.3-python3/tests/dbapi20.py +--- MySQL-python-1.2.3/tests/dbapi20.py 2010-06-17 09:21:55.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/tests/dbapi20.py 2011-10-05 12:49:58.000000000 +0200 +@@ -177,8 +177,8 @@ + def test_Exceptions(self): + # Make sure required exceptions exist, and are in the + # defined heirarchy. +- self.failUnless(issubclass(self.driver.Warning,StandardError)) +- self.failUnless(issubclass(self.driver.Error,StandardError)) ++ self.failUnless(issubclass(self.driver.Warning,Exception)) ++ self.failUnless(issubclass(self.driver.Error,Exception)) + self.failUnless( + issubclass(self.driver.InterfaceError,self.driver.Error) + ) +@@ -382,27 +382,27 @@ + + if self.driver.paramstyle == 'qmark': + cur.execute( +- 'insert into %sbooze values (?)' % self.table_prefix, ++ 'insert into %sbooze values ({!s})' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'numeric': + cur.execute( +- 'insert into %sbooze values (:1)' % self.table_prefix, ++ 'insert into %sbooze values ({:1})' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'named': + cur.execute( +- 'insert into %sbooze values (:beer)' % self.table_prefix, ++ 'insert into %sbooze values ({beer})' % self.table_prefix, + {'beer':"Cooper's"} + ) + elif self.driver.paramstyle == 'format': + cur.execute( +- 'insert into %sbooze values (%%s)' % self.table_prefix, ++ 'insert into %sbooze values ({!s})' % self.table_prefix, + ("Cooper's",) + ) + elif self.driver.paramstyle == 'pyformat': + cur.execute( +- 'insert into %sbooze values (%%(beer)s)' % self.table_prefix, ++ 'insert into %sbooze values ({beer})' % self.table_prefix, + {'beer':"Cooper's"} + ) + else: +@@ -432,27 +432,27 @@ + margs = [ {'beer': "Cooper's"}, {'beer': "Boag's"} ] + if self.driver.paramstyle == 'qmark': + cur.executemany( +- 'insert into %sbooze values (?)' % self.table_prefix, ++ 'insert into %sbooze values ({!s})' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'numeric': + cur.executemany( +- 'insert into %sbooze values (:1)' % self.table_prefix, ++ 'insert into %sbooze values ({:1})' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'named': + cur.executemany( +- 'insert into %sbooze values (:beer)' % self.table_prefix, ++ 'insert into %sbooze values ({beer})' % self.table_prefix, + margs + ) + elif self.driver.paramstyle == 'format': + cur.executemany( +- 'insert into %sbooze values (%%s)' % self.table_prefix, ++ 'insert into %sbooze values ({!s})' % self.table_prefix, + largs + ) + elif self.driver.paramstyle == 'pyformat': + cur.executemany( +- 'insert into %sbooze values (%%(beer)s)' % ( ++ 'insert into %sbooze values ({beer})' % ( + self.table_prefix + ), + margs +@@ -706,7 +706,7 @@ + that returns two result sets, first the + number of rows in booze then "name from booze" + ''' +- raise NotImplementedError,'Helper not implemented' ++ raise NotImplementedError('Helper not implemented') + #sql=""" + # create procedure deleteme as + # begin +@@ -718,7 +718,7 @@ + + def help_nextset_tearDown(self,cur): + 'If cleaning up is needed after nextSetTest' +- raise NotImplementedError,'Helper not implemented' ++ raise NotImplementedError('Helper not implemented') + #cur.execute("drop procedure deleteme") + + def test_nextset(self): +@@ -751,7 +751,7 @@ + con.close() + + def test_nextset(self): +- raise NotImplementedError,'Drivers need to override this test' ++ raise NotImplementedError('Drivers need to override this test') + + def test_arraysize(self): + # Not much here - rest of the tests for this are in test_fetchmany +@@ -786,7 +786,7 @@ + + def test_setoutputsize(self): + # Real test for setoutputsize is driver dependant +- raise NotImplementedError,'Driver need to override this test' ++ raise NotImplementedError('Driver need to override this test') + + def test_None(self): + con = self._connect() +diff -ru MySQL-python-1.2.3/tests/test_MySQLdb_capabilities.py MySQL-Python-1.2.3-python3/tests/test_MySQLdb_capabilities.py +--- MySQL-python-1.2.3/tests/test_MySQLdb_capabilities.py 2010-06-17 09:21:55.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/tests/test_MySQLdb_capabilities.py 2011-10-05 12:49:58.000000000 +0200 +@@ -41,8 +41,7 @@ + db = self.connection + c = self.cursor + self.create_table(('pos INT', 'tree CHAR(20)')) +- c.executemany("INSERT INTO %s (pos,tree) VALUES (%%s,%%s)" % self.table, +- list(enumerate('ash birch cedar larch pine'.split()))) ++ c.executemany("INSERT INTO %s (pos,tree) VALUES ({!s},{!s})" % self.table, list(enumerate('ash birch cedar larch pine'.split())) ) + db.commit() + + c.execute(""" +@@ -77,9 +76,9 @@ + from MySQLdb.constants import ER + try: + self.cursor.execute("describe some_non_existent_table"); +- except self.connection.ProgrammingError, msg: +- self.failUnless(msg[0] == ER.NO_SUCH_TABLE) +- ++ except self.connection.ProgrammingError as msg: ++ self.assertTrue(msg.code == ER.NO_SUCH_TABLE) ++ + def test_ping(self): + self.connection.ping() + +@@ -90,4 +89,4 @@ + gc.enable() + gc.set_debug(gc.DEBUG_LEAK) + unittest.main() +- print '''"Huh-huh, he said 'unit'." -- Butthead''' ++ print ('''"Huh-huh, he said 'unit'." -- Butthead''') +diff -ru MySQL-python-1.2.3/tests/test_MySQLdb_dbapi20.py MySQL-Python-1.2.3-python3/tests/test_MySQLdb_dbapi20.py +--- MySQL-python-1.2.3/tests/test_MySQLdb_dbapi20.py 2010-06-17 09:21:55.000000000 +0200 ++++ MySQL-Python-1.2.3-python3/tests/test_MySQLdb_dbapi20.py 2011-10-05 12:49:58.000000000 +0200 +@@ -202,4 +202,4 @@ + + if __name__ == '__main__': + unittest.main() +- print '''"Huh-huh, he said 'unit'." -- Butthead''' ++ print ('''"Huh-huh, he said 'unit'." -- Butthead''')