On Fri, 2010-05-07 at 14:36 -0400, David Malcolm wrote: > On Fri, 2010-05-07 at 11:08 -0700, Kyle VanderBeek wrote: > > On Fri, May 7, 2010 at 9:05 AM, David Malcolm <dmalc...@redhat.com> > > wrote: > > On Fri, 2010-05-07 at 12:25 +0000, Rawhide Report wrote: > > > > Three more python 3 subpackages in today's "rawhide" heading > > for F14 - > > I've gone ahead and added these to the wiki here: > > > > https://fedoraproject.org/wiki/Features/Python3F13#Python_3_already_in_Fedora > > > > Are we missing anything? > > > > > > > > Crud, this probably means I need to either finish my pure-python MySQL > > driver, or work on making MySQLdb run with python3. :-) If you want > > :) > > > to update the upstream status for MySQLdb, we simply haven't started > > porting it. > > You're probably in a better position to give accurate status on that > page (it's a wiki, feel free to edit) > > I actually had a go at porting MySQLdb to py3k, I'll see if I can find > my source tree.
In the hope that's its helpful, attached is a messy, mostly-compiling port of the code. It's from SVN r633; this was an experiment I did back in November 2009. The .py parts are from 2to3 and are python 3 only, but ought to be regeneratable via 2to3. The .c parts are from my 2to3c code and some manual hacking. The aim is that they're compilable against both 2 and 3 from the same sources. (I may be misremembering all this) It may well not fully compile, and I'm definitely playing fast-and-loose with things like encodings. IIRC I was able to get it to compile, and to at least connect to MySQL from python3, but I'm definitely getting things wrong with anything non-ASCII, I'm afraid. (I'm assuming an invocation of 2to3 upon the .py code, and the use of the "distribute" fork of setuptools; I'm using python 3.1.1 FWIW) Hope this is helpful; I'd appreciate a shout-out to Red Hat if it does help. Dave
Index: MySQLdb/ez_setup.py =================================================================== --- MySQLdb/ez_setup.py (revision 633) +++ MySQLdb/ez_setup.py (working copy) @@ -62,10 +62,10 @@ if egg_name in md5_data: digest = md5(data).hexdigest() if digest != md5_data[egg_name]: - print >>sys.stderr, ( + print(( "md5 validation of %s failed! (Possible download problem?)" % egg_name - ) + ), file=sys.stderr) sys.exit(2) return data @@ -95,14 +95,14 @@ return do_download() try: pkg_resources.require("setuptools>="+version); return - except pkg_resources.VersionConflict, e: + except pkg_resources.VersionConflict as e: if was_imported: - print >>sys.stderr, ( + print(( "The required version of setuptools (>=%s) is not available, and\n" "can't be installed while this script is running. Please install\n" " a more recent version first, using 'easy_install -U setuptools'." "\n\n(Currently using %r)" - ) % (version, e.args[0]) + ) % (version, e.args[0]), file=sys.stderr) sys.exit(2) else: del pkg_resources, sys.modules['pkg_resources'] # reload ok @@ -121,7 +121,7 @@ with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ - import urllib2, shutil + import urllib.request, urllib.error, urllib.parse, shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) @@ -147,7 +147,7 @@ version, download_base, delay, url ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) - src = urllib2.urlopen(url) + src = urllib.request.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) @@ -208,10 +208,10 @@ os.unlink(egg) else: if setuptools.__version__ == '0.0.1': - print >>sys.stderr, ( + print(( "You have an obsolete version of setuptools installed. Please\n" "remove it from your system entirely before rerunning this script." - ) + ), file=sys.stderr) sys.exit(2) req = "setuptools>="+version @@ -230,8 +230,8 @@ from setuptools.command.easy_install import main main(argv) else: - print "Setuptools version",version,"or greater has been installed." - print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' + print("Setuptools version",version,"or greater has been installed.") + print('(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)') def update_md5(filenames): """Update our built-in md5 registry""" @@ -244,7 +244,7 @@ md5_data[base] = md5(f.read()).hexdigest() f.close() - data = [" %r: %r,\n" % it for it in md5_data.items()] + data = [" %r: %r,\n" % it for it in list(md5_data.items())] data.sort() repl = "".join(data) @@ -254,7 +254,7 @@ match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: - print >>sys.stderr, "Internal error!" + print("Internal error!", file=sys.stderr) sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] Index: MySQLdb/src/results.c =================================================================== --- MySQLdb/src/results.c (revision 633) +++ MySQLdb/src/results.c (working copy) @@ -184,7 +184,7 @@ if (!(d = PyTuple_New(n))) return NULL; for (i=0; i<n; i++) { PyObject *f; - if (!(f = PyInt_FromLong((long)fields[i].flags))) goto error; + if (!(f = PyLong_FromLong((long)fields[i].flags))) goto error; PyTuple_SET_ITEM(d, i, f); } return d; @@ -203,12 +203,12 @@ if (rowitem) { if (decoder != Py_None) v = PyObject_CallFunction(decoder, - "s#", + "y#", /* convert from raw bytes to a python "bytes" object */ rowitem, (int)length); else - v = PyString_FromStringAndSize(rowitem, - (int)length); + v = PyBytes_FromStringAndSize(rowitem, + (int)length); if (!v) return NULL; } else { @@ -439,7 +439,7 @@ PyObject *unused) { 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__[] = @@ -511,7 +511,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 @@ -531,7 +531,7 @@ char buf[300]; sprintf(buf, "<_mysql.result object at %lx>", (long)self); - return PyString_FromString(buf); + return PyUnicode_FromString(buf); } static PyMethodDef _mysql_ResultObject_methods[] = { @@ -591,47 +591,25 @@ "connection", T_OBJECT, offsetof(_mysql_ConnectionObject, connection), - RO, + READONLY, "Connection associated with result" }, { "decoders", T_OBJECT, offsetof(_mysql_ResultObject, decoders), - RO, + READONLY, "Field decoders for result set" }, { "fields", T_OBJECT, offsetof(_mysql_ResultObject, fields), - RO, + READONLY, "Field metadata for result set" }, {NULL} /* Sentinel */ }; -static PyObject * -_mysql_ResultObject_getattr( - _mysql_ResultObject *self, - char *name) -{ - PyObject *res; - struct PyMemberDef *l; - - res = Py_FindMethod(_mysql_ResultObject_methods, (PyObject *)self, name); - if (res != NULL) - return res; - PyErr_Clear(); - - 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; -} - static int _mysql_ResultObject_setattr( _mysql_ResultObject *self, @@ -655,14 +633,13 @@ } 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 */ + (getattrfunc)0, /* tp_getattr */ (setattrfunc)_mysql_ResultObject_setattr, /* tp_setattr */ 0, /*tp_compare*/ (reprfunc)_mysql_ResultObject_repr, /* tp_repr */ @@ -678,7 +655,7 @@ 0, /* (hashfunc) tp_hash */ 0, /* (ternaryfunc) tp_call */ 0, /* (reprfunc) tp_str */ - 0, /* (getattrofunc) tp_getattro */ + PyObject_GenericGetAttr, /* (getattrofunc) tp_getattro */ 0, /* (setattrofunc) tp_setattro */ /* Functions to access object as input/output buffer */ Index: MySQLdb/src/connections.c =================================================================== --- MySQLdb/src/connections.c (revision 633) +++ MySQLdb/src/connections.c (working copy) @@ -50,7 +50,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) { @@ -227,11 +227,11 @@ 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); + str = PyBytes_FromStringAndSize((char *) NULL, size*2+1); if (!str) return PyErr_NoMemory(); - out = PyString_AS_STRING(str); + out = PyBytes_AS_STRING(str); len = mysql_real_escape_string(&(self->connection), out, in, size); - if (_PyString_Resize(&str, len) < 0) return NULL; + if (_PyBytes_Resize(&str, len) < 0) return NULL; return (str); } @@ -252,12 +252,12 @@ char *in, *out; int len, size; if (!PyArg_ParseTuple(args, "s#:string_literal", &in, &size)) return NULL; - str = PyString_FromStringAndSize((char *) NULL, size*2+3); + str = PyBytes_FromStringAndSize((char *) NULL, size*2+3); if (!str) return PyErr_NoMemory(); - out = PyString_AS_STRING(str); + out = PyBytes_AS_STRING(str); len = mysql_real_escape_string(&(self->connection), out+1, in, size); *out = *(out+len+1) = '\''; - if (_PyString_Resize(&str, len+2) < 0) return NULL; + if (_PyBytes_Resize(&str, len+2) < 0) return NULL; return (str); } @@ -418,7 +418,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 @@ -441,7 +441,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__[] = @@ -461,7 +461,7 @@ _mysql_ConnectionObject *self, PyObject *unused) { - return PyString_FromString(mysql_sqlstate(&(self->connection))); + return PyUnicode_FromString(mysql_sqlstate(&(self->connection))); } static char _mysql_ConnectionObject_warning_count__doc__[] = @@ -475,7 +475,7 @@ _mysql_ConnectionObject *self, PyObject *unused) { - return PyInt_FromLong(mysql_warning_count(&(self->connection))); + return PyLong_FromLong(mysql_warning_count(&(self->connection))); } #endif @@ -492,7 +492,7 @@ PyObject *unused) { 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__[] = @@ -507,7 +507,7 @@ PyObject *unused) { check_connection(self); - return PyString_FromString(mysql_error(&(self->connection))); + return PyUnicode_FromString(mysql_error(&(self->connection))); } #if MYSQL_VERSION_ID >= 32303 @@ -570,7 +570,7 @@ #else s = "latin1"; #endif - return PyString_FromString(s); + return PyUnicode_FromString(s); } #if MYSQL_VERSION_ID >= 50007 @@ -631,15 +631,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 @@ -655,7 +655,7 @@ PyObject *unused) { 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__[] = @@ -669,7 +669,7 @@ PyObject *unused) { 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__[] = @@ -683,7 +683,7 @@ PyObject *unused) { 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__[] = @@ -701,7 +701,7 @@ 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; } @@ -775,9 +775,9 @@ { check_connection(self); #if MYSQL_VERSION_ID < 32224 - return PyInt_FromLong((long)mysql_num_fields(&(self->connection))); + return PyLong_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 } @@ -914,7 +914,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__[] = @@ -974,7 +974,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__[] = @@ -1038,7 +1038,7 @@ else sprintf(buf, "<_mysql.connection closed at %lx>", (long)self); - return PyString_FromString(buf); + return PyUnicode_FromString(buf); } static PyMethodDef _mysql_ConnectionObject_methods[] = { @@ -1255,7 +1255,7 @@ "open", T_INT, offsetof(_mysql_ConnectionObject, open), - RO, + READONLY, "True if connection is open" }, { @@ -1269,20 +1269,20 @@ "server_capabilities", T_UINT, offsetof(_mysql_ConnectionObject, connection.server_capabilities), - RO, + READONLY, "Capabilites of server; consult MySQLdb.constants.CLIENT" }, { "port", T_UINT, offsetof(_mysql_ConnectionObject, connection.port), - RO, + READONLY, "TCP/IP port of the server connection" }, { "client_flag", T_UINT, - RO, + READONLY, offsetof(_mysql_ConnectionObject, connection.client_flag), "Client flags; refer to MySQLdb.constants.CLIENT" }, @@ -1290,27 +1290,20 @@ }; static PyObject * -_mysql_ConnectionObject_getattr( +_mysql_ConnectionObject_getattro( _mysql_ConnectionObject *self, - char *name) + PyObject *name) { - PyObject *res; - struct PyMemberDef *l; - - 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)); - - for (l = _mysql_ConnectionObject_memberlist; l->name != NULL; l++) { - if (strcmp(l->name, name) == 0) - return PyMember_GetOne((char *)self, l); + if (!PyUnicode_Check(name)){ + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + name->ob_type->tp_name); + return NULL; } + if (PyUnicode_CompareWithASCIIString(name,"closed") == 0) + return PyLong_FromLong((long)!(self->open)); - PyErr_SetString(PyExc_AttributeError, name); - return NULL; + return PyObject_GenericGetAttr((PyObject*)self, name); } static int @@ -1336,14 +1329,13 @@ } PyTypeObject _mysql_ConnectionObject_Type = { - PyObject_HEAD_INIT(NULL) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "_mysql.connection", /* (char *)tp_name For printing */ sizeof(_mysql_ConnectionObject), /* tp_basicsize */ 0, (destructor)_mysql_ConnectionObject_dealloc, /* tp_dealloc */ 0, /*tp_print*/ - (getattrfunc)_mysql_ConnectionObject_getattr, /* tp_getattr */ + (getattrfunc)0, /* tp_getattr */ (setattrfunc)_mysql_ConnectionObject_setattr, /* tp_setattr */ 0, /*tp_compare*/ (reprfunc)_mysql_ConnectionObject_repr, /* tp_repr */ @@ -1359,7 +1351,7 @@ 0, /* (hashfunc) tp_hash */ 0, /* (ternaryfunc) tp_call */ 0, /* (reprfunc) tp_str */ - 0, /* (getattrofunc) tp_getattro */ + (getattrofunc) _mysql_ConnectionObject_getattro, /* tp_getattro */ 0, /* (setattrofunc) tp_setattro */ /* Functions to access object as input/output buffer */ @@ -1403,3 +1395,4 @@ 0, /* (PyObject *) tp_mro method resolution order */ 0, /* (PyObject *) tp_defined */ }; + Index: MySQLdb/src/mysqlmod.c =================================================================== --- MySQLdb/src/mysqlmod.c (revision 633) +++ MySQLdb/src/mysqlmod.c (working copy) @@ -26,8 +26,8 @@ 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; @@ -36,14 +36,14 @@ 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; } else { - PyObject *py_merr = PyInt_FromLong(merr); + PyObject *py_merr = PyLong_FromLong(merr); e = PyDict_GetItem(_mysql_error_map, py_merr); Py_DECREF(py_merr); if (!e) { @@ -51,8 +51,8 @@ else e = _mysql_OperationalError; } } - PyTuple_SET_ITEM(t, 0, PyInt_FromLong((long)merr)); - PyTuple_SET_ITEM(t, 1, PyString_FromString(mysql_error(&(c->connection)))); + PyTuple_SET_ITEM(t, 0, PyLong_FromLong((long)merr)); + PyTuple_SET_ITEM(t, 1, PyUnicode_FromString(mysql_error(&(c->connection)))); PyErr_SetObject(e, t); Py_DECREF(t); return NULL; @@ -101,11 +101,11 @@ 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, - "args must contain strings"); + "args must contain bytes"); goto finish; } cmd_args_c[i] = s; @@ -126,11 +126,11 @@ 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, - "groups must contain strings"); + "groups must contain bytes"); goto finish; } groups_c[i] = s; @@ -180,7 +180,7 @@ PyObject *unused) { check_server_init(NULL); - return PyInt_FromLong((long)mysql_thread_safe()); + return PyLong_FromLong((long)mysql_thread_safe()); } #endif @@ -236,7 +236,7 @@ if (!itemconv) { PyErr_Clear(); itemconv = PyObject_GetItem(d, - (PyObject *) &PyString_Type); + (PyObject *) &PyBytes_Type); } if (!itemconv) { PyErr_SetString(PyExc_TypeError, @@ -329,7 +329,7 @@ PyObject *unused) { check_server_init(NULL); - return PyString_FromString(mysql_get_client_info()); + return PyUnicode_FromString(mysql_get_client_info()); } extern PyTypeObject _mysql_ConnectionObject_Type; @@ -409,19 +409,43 @@ (as of 3.23) are NOT implemented.\n\ "; -PyMODINIT_FUNC -init_mysql(void) +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "_mysql",/* m_name */ + _mysql___doc__,/* m_doc */ + 0,/* m_size */ + _mysql_methods,/* m_methods */ + NULL,/* m_reload */ + NULL,/* m_traverse */ + NULL,/* m_clear */ + NULL,/* m_free */ +}; +#define MOD_ERROR_VAL NULL +#else +#define MOD_ERROR_VAL +#endif + +#if PY_MAJOR_VERSION >= 3 +PyMODINIT_FUNC PyInit__mysql(void) +#else +PyMODINIT_FUNC init_mysql(void) +#endif { PyObject *dict, *module, *emod, *edict, *version_tuple; +#if PY_MAJOR_VERSION >= 3 + module = PyModule_Create(&moduledef); +#else module = Py_InitModule3("_mysql", _mysql_methods, _mysql___doc__); +#endif if (!module) - return; /* this really should never happen */ + return MOD_ERROR_VAL; /* this really should never happen */ /* Populate final object settings */ - _mysql_ConnectionObject_Type.ob_type = &PyType_Type; - _mysql_ResultObject_Type.ob_type = &PyType_Type; - _mysql_FieldObject_Type.ob_type = &PyType_Type; + Py_TYPE(&_mysql_ConnectionObject_Type) = &PyType_Type; + Py_TYPE(&_mysql_ResultObject_Type) = &PyType_Type; + Py_TYPE(&_mysql_FieldObject_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; @@ -502,11 +526,16 @@ goto error; Py_DECREF(emod); + #if PY_MAJOR_VERSION >= 3 + return module; + #endif + error: if (PyErr_Occurred()) PyErr_SetString(PyExc_ImportError, "_mysql: init failed"); - return; + return NULL; } + Index: MySQLdb/src/fields.c =================================================================== --- MySQLdb/src/fields.c (revision 633) +++ MySQLdb/src/fields.c (working copy) @@ -61,7 +61,7 @@ _mysql_FieldObject_repr( _mysql_FieldObject *self) { - return PyString_FromFormat("<_mysql.field object at %p>", self); + return PyUnicode_FromFormat("<_mysql.field object at %p>", self); } static PyMethodDef _mysql_FieldObject_methods[] = { @@ -73,14 +73,14 @@ "result", T_OBJECT, offsetof(_mysql_FieldObject, result), - RO, + READONLY, "Result set" }, { "name", T_STRING, offsetof(_mysql_FieldObject, field.name), - RO, + READONLY, "The name of the field. If the field was given\n\ an alias with an AS clause, the value of name is the alias." }, @@ -88,14 +88,14 @@ "org_name", T_STRING, offsetof(_mysql_FieldObject, field.org_name), - RO, + READONLY, "The name of the field. Aliases are ignored." }, { "table", T_STRING, offsetof(_mysql_FieldObject, field.table), - RO, + READONLY, "The name of the table containing this field,\n\ if it isn't a calculated field. For calculated fields,\n\ the table value is an empty string. If the column is selected from a view,\n\ @@ -106,7 +106,7 @@ "org_table", T_STRING, offsetof(_mysql_FieldObject, field.org_table), - RO, + READONLY, "The name of the table. Aliases are ignored.\n\ If the column is selected from a view, org_table names the underlying table.\n" }, @@ -114,7 +114,7 @@ "db", T_STRING, offsetof(_mysql_FieldObject, field.db), - RO, + READONLY, "The name of the database that the field comes from.\n\ If the field is a calculated field, db is an empty string." }, @@ -122,14 +122,14 @@ "catalog", T_STRING, offsetof(_mysql_FieldObject, field.catalog), - RO, + READONLY, "The catalog name. This value is always \"def\"." }, { "length", T_ULONG, offsetof(_mysql_FieldObject, field.length), - RO, + READONLY, "The width of the field.\n\ as specified in the table definition.\n" }, @@ -137,7 +137,7 @@ "max_length", T_ULONG, offsetof(_mysql_FieldObject, field.max_length), - RO, + READONLY, "The maximum width of the field for the result set\n\ (the length of the longest field value for the rows actually in the\n\ result set). If you use conn.store_result(), this contains the\n\ @@ -148,21 +148,21 @@ "decimals", T_UINT, offsetof(_mysql_FieldObject, field.decimals), - RO, + READONLY, "The number of decimals for numeric fields.\n" }, { "charsetnr", T_UINT, offsetof(_mysql_FieldObject, field.charsetnr), - RO, + READONLY, "The character set number for the field." }, { "flags", T_UINT, offsetof(_mysql_FieldObject, field.flags), - RO, + READONLY, "Different bit-flags for the field.\n\ The bits are enumerated in MySQLdb.constants.FLAG.\n\ The flags value may have zero or more of these bits set.\n" @@ -171,35 +171,13 @@ "type", T_UINT, offsetof(_mysql_FieldObject, field.type), - RO, + READONLY, "The type of the field. The type values\n\ are enumerated in MySQLdb.constants.FIELD_TYPE.\n" }, {NULL} /* Sentinel */ }; -static PyObject * -_mysql_FieldObject_getattr( - _mysql_FieldObject *self, - char *name) -{ - PyObject *res; - struct PyMemberDef *l; - - res = Py_FindMethod(_mysql_FieldObject_methods, (PyObject *)self, name); - if (res != NULL) - return res; - PyErr_Clear(); - - for (l = _mysql_FieldObject_memberlist; l->name != NULL; l++) { - if (strcmp(l->name, name) == 0) - return PyMember_GetOne((char *)self, l); - } - - PyErr_SetString(PyExc_AttributeError, name); - return NULL; -} - static int _mysql_FieldObject_setattr( _mysql_FieldObject *self, @@ -224,14 +202,13 @@ } PyTypeObject _mysql_FieldObject_Type = { - PyObject_HEAD_INIT(NULL) - 0, + PyVarObject_HEAD_INIT(NULL, 0) "_mysql.field", sizeof(_mysql_FieldObject), 0, (destructor)_mysql_FieldObject_dealloc, /* tp_dealloc */ 0, /*tp_print*/ - (getattrfunc)_mysql_FieldObject_getattr, /* tp_getattr */ + (getattrfunc)0, /* tp_getattr */ (setattrfunc)_mysql_FieldObject_setattr, /* tp_setattr */ 0, /*tp_compare*/ (reprfunc)_mysql_FieldObject_repr, /* tp_repr */ @@ -247,7 +224,7 @@ 0, /* (hashfunc) tp_hash */ 0, /* (ternaryfunc) tp_call */ 0, /* (reprfunc) tp_str */ - 0, /* (getattrofunc) tp_getattro */ + PyObject_GenericGetAttr, /* (getattrofunc) tp_getattro */ 0, /* (setattrofunc) tp_setattro */ /* Functions to access object as input/output buffer */ @@ -291,3 +268,4 @@ 0, /* (PyObject *) tp_mro method resolution order */ 0, /* (PyObject *) tp_defined */ }; + Index: MySQLdb/src/mysqlmod.h =================================================================== --- MySQLdb/src/mysqlmod.h (revision 633) +++ MySQLdb/src/mysqlmod.h (working copy) @@ -14,7 +14,7 @@ #include "errmsg.h" #define MyAlloc(s,t) (s *) t.tp_alloc(&t,0) -#define MyFree(ob) ob->ob_type->tp_free((PyObject *)ob) +#define MyFree(ob) Py_TYPE(ob)->tp_free((PyObject *)ob) #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) typedef int Py_ssize_t; Index: MySQLdb/setup_common.py =================================================================== --- MySQLdb/setup_common.py (revision 633) +++ MySQLdb/setup_common.py (working copy) @@ -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'] = [_f for _f in metadata['py_modules'].split('\n') if _f] + metadata['classifiers'] = [_f for _f in metadata['classifiers'].split('\n') if _f] return metadata, options Index: MySQLdb/setup_windows.py =================================================================== --- MySQLdb/setup_windows.py (revision 633) +++ MySQLdb/setup_windows.py (working copy) @@ -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,'Location') extra_objects = [] static = enabled(options, 'static') @@ -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.""") Index: MySQLdb/tests/capabilities.py =================================================================== --- MySQLdb/tests/capabilities.py (revision 633) +++ MySQLdb/tests/capabilities.py (working copy) @@ -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(16834)]) + self.BLOBUText = ''.join([chr(i) for i in range(16834)]) self.BLOBBinary = self.db_module.Binary(''.join([chr(i) for i in range(256)] * 16)) leak_test = True @@ -85,14 +85,14 @@ 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): @@ -148,7 +148,7 @@ 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: Index: MySQLdb/tests/test_MySQLdb_dbapi20.py =================================================================== --- MySQLdb/tests/test_MySQLdb_dbapi20.py (revision 633) +++ MySQLdb/tests/test_MySQLdb_dbapi20.py (working copy) @@ -202,4 +202,4 @@ if __name__ == '__main__': unittest.main() - print '''"Huh-huh, he said 'unit'." -- Butthead''' + print('''"Huh-huh, he said 'unit'." -- Butthead''') Index: MySQLdb/tests/dbapi20.py =================================================================== --- MySQLdb/tests/dbapi20.py (revision 633) +++ MySQLdb/tests/dbapi20.py (working copy) @@ -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) ) @@ -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() Index: MySQLdb/tests/test_MySQLdb_capabilities.py =================================================================== --- MySQLdb/tests/test_MySQLdb_capabilities.py (revision 633) +++ MySQLdb/tests/test_MySQLdb_capabilities.py (working copy) @@ -78,32 +78,32 @@ 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.assertEqual(msg[0], ER.NO_SUCH_TABLE) def test_INSERT_VALUES(self): from MySQLdb.cursors import INSERT_VALUES query = """INSERT FOO (a, b, c) VALUES (%s, %s, %s)""" matched = INSERT_VALUES.match(query) - self.failUnless(matched) + self.assertTrue(matched) start = matched.group('start') end = matched.group('end') values = matched.group('values') - self.failUnless(start == """INSERT FOO (a, b, c) VALUES """) - self.failUnless(values == "(%s, %s, %s)") - self.failUnless(end == "") + self.assertTrue(start == """INSERT FOO (a, b, c) VALUES """) + self.assertTrue(values == "(%s, %s, %s)") + self.assertTrue(end == "") def test_ping(self): self.connection.ping() def test_literal_int(self): - self.failUnless("2" == self.connection.literal(2)) + self.assertEqual("2", self.connection.literal(2)) def test_literal_float(self): - self.failUnless("3.1415" == self.connection.literal(3.1415)) + self.assertEqual("3.1415", self.connection.literal(3.1415)) def test_literal_string(self): - self.failUnless("'foo'" == self.connection.literal("foo")) + self.assertEqual("'foo'", self.connection.literal("foo")) if __name__ == '__main__': @@ -112,4 +112,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''') Index: MySQLdb/setup_posix.py =================================================================== --- MySQLdb/setup_posix.py (revision 633) +++ MySQLdb/setup_posix.py (working copy) @@ -88,4 +88,4 @@ 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.""") Index: MySQLdb/MySQLdb/converters.py =================================================================== --- MySQLdb/MySQLdb/converters.py (revision 633) +++ MySQLdb/MySQLdb/converters.py (working copy) @@ -39,7 +39,6 @@ from MySQLdb.times import datetime_to_sql, timedelta_to_sql, \ timedelta_or_None, datetime_or_None, date_or_None, \ mysql_timestamp_converter -from types import InstanceType import array import datetime from decimal import Decimal @@ -90,10 +89,10 @@ """ if obj.__class__ in conv: return conv[obj.__class__](obj, conv) - classes = [ key for key in conv.keys() + classes = [ key for key in list(conv.keys()) if isinstance(obj, key) ] if not classes: - return conv[types.StringType](obj, conv) + return conv[bytes](obj, conv) conv[obj.__class__] = conv[classes[0]] return conv[classes[0]](obj, conv) @@ -102,16 +101,15 @@ simple_type_encoders = { int: object_to_sql, - long: object_to_sql, float: float_to_sql, type(None): None_to_sql, - unicode: unicode_to_sql, + str: unicode_to_sql, object: instance_to_sql, bool: bool_to_sql, datetime.datetime: datetime_to_sql, datetime.timedelta: timedelta_to_sql, set: Set_to_sql, - str: object_to_quoted_sql, # default + bytes: object_to_quoted_sql, # default } # This is for MySQL column types that can be converted directly @@ -145,7 +143,7 @@ # on the stack will be checked. def default_decoder(field): - return str + return bytes def default_encoder(value): return object_to_quoted_sql @@ -167,13 +165,13 @@ if field.type not in character_types: return None if field.charsetnr == 63: # BINARY - return str + return bytes charset = field.result.connection.character_set_name() - def char_to_unicode(s): + def bytes_to_unicode(s): return s.decode(charset) - return char_to_unicode + return bytes_to_unicode default_decoders = [ character_decoder, Index: MySQLdb/MySQLdb/cursors.py =================================================================== --- MySQLdb/MySQLdb/cursors.py (revision 633) +++ MySQLdb/MySQLdb/cursors.py (working copy) @@ -159,13 +159,13 @@ del self.messages[:] db = self._get_db() charset = db.character_set_name() - if isinstance(query, unicode): - query = query.encode(charset) try: if args is not None: query = query % tuple(map(self.connection.literal, args)) + if isinstance(query, str): + query = query.encode(charset) result = self._query(query) - except TypeError, msg: + except TypeError as msg: if msg.args[0] in ("not enough arguments for format string", "not all arguments converted"): self.messages.append((self.ProgrammingError, msg.args[0])) @@ -208,8 +208,8 @@ if not args: return charset = self.connection.character_set_name() - if isinstance(query, unicode): - query = query.encode(charset) + #if isinstance(query, str): + #query = query.encode(charset) matched = INSERT_VALUES.match(query) if not matched: self.rowcount = sum([ self.execute(query, arg) for arg in args ]) @@ -225,7 +225,7 @@ self._executed = multirow_query self.rowcount = int(self._query(multirow_query)) - except TypeError, msg: + except TypeError as msg: if msg.args[0] in ("not enough arguments for format string", "not all arguments converted"): self.messages.append((self.ProgrammingError, msg.args[0])) @@ -278,7 +278,7 @@ for index, arg in enumerate(args): query = "SET @_%s_%d=%s" % (procname, index, self.connection.literal(arg)) - if isinstance(query, unicode): + if isinstance(query, str): query = query.encode(charset) self._query(query) self.nextset() @@ -286,7 +286,7 @@ query = "CALL %s(%s)" % (procname, ','.join(['@_%s_%d' % (procname, i) for i in range(len(args))])) - if isinstance(query, unicode): + if isinstance(query, str): query = query.encode(charset) self._query(query) self._executed = query @@ -369,7 +369,7 @@ row = value else: self.errorhandler(self, self.ProgrammingError, - "unknown scroll mode %s" % `mode`) + "unknown scroll mode %s" % repr(mode)) if row < 0 or row >= len(self._rows): self.errorhandler(self, IndexError, "out of range") self.rownumber = row Index: MySQLdb/MySQLdb/exceptions.py =================================================================== --- MySQLdb/MySQLdb/exceptions.py (revision 633) +++ MySQLdb/MySQLdb/exceptions.py (working copy) @@ -12,16 +12,13 @@ # It would make things much cleaner for Python-2.5, but breaks older. try: - from exceptions import Exception, StandardError, Warning + from exceptions import Exception, Exception, Warning except ImportError: - import sys - e = sys.modules['exceptions'] - StandardError = e.StandardError - Warning = e.Warning + pass from MySQLdb.constants import ER -class MySQLError(StandardError): +class MySQLError(Exception): """Exception related to operation with MySQL.""" @@ -114,4 +111,4 @@ _map_error(NotSupportedError, ER.WARNING_NOT_COMPLETE_ROLLBACK, ER.NOT_SUPPORTED_YET, ER.FEATURE_DISABLED, ER.UNKNOWN_STORAGE_ENGINE) -del StandardError, _map_error, ER +del _map_error, ER Index: MySQLdb/MySQLdb/times.py =================================================================== --- MySQLdb/MySQLdb/times.py (revision 633) +++ MySQLdb/MySQLdb/times.py (working copy) @@ -191,7 +191,7 @@ """ try: - return date(*map(int, obj.split('-', 2))) + return date(*list(map(int, obj.split(b'-', 2)))) except ValueError: return None @@ -238,4 +238,4 @@ if __name__ == "__main__": import doctest doctest.testmod() - \ No newline at end of file + Index: MySQLdb/MySQLdb/connections.py =================================================================== --- MySQLdb/MySQLdb/connections.py (revision 633) +++ MySQLdb/MySQLdb/connections.py (working copy) @@ -29,7 +29,7 @@ connection.messages.append(error) del cursor del connection - raise errorclass, errorvalue + raise errorclass(errorvalue) class Connection(object):
_______________________________________________ python-devel mailing list python-devel@lists.fedoraproject.org https://admin.fedoraproject.org/mailman/listinfo/python-devel