]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- The C extensions are ported to Python 3 and will build under
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 27 Jul 2013 00:50:18 +0000 (20:50 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 27 Jul 2013 00:50:18 +0000 (20:50 -0400)
any supported CPython 2 or 3 environment. [ticket:2161]

doc/build/changelog/changelog_09.rst
doc/build/changelog/migration_09.rst
lib/sqlalchemy/cextension/processors.c
lib/sqlalchemy/cextension/resultproxy.c
lib/sqlalchemy/cextension/utils.c
setup.py
test/profiles.txt

index 868f5450f8d967cc674363db3d339f251345d2fe..5655ae78bd9d4806fa7e750c078321f48df864f4 100644 (file)
@@ -6,6 +6,13 @@
 .. changelog::
     :version: 0.9.0
 
+    .. change::
+        :tags: feature, general, py3k
+        :tickets: 2161
+
+        The C extensions are ported to Python 3 and will build under
+        any supported CPython 2 or 3 environment.
+
     .. change::
         :tags: feature, orm
         :tickets: 2268
         official Python driver.
 
     .. change::
-       :tags: feature, general
+       :tags: feature, general, py3k
        :tickets: 2671
 
         The codebase is now "in-place" for Python
index f1ebe7dd43e07974ee2612d4190c2eaf660ab0dc..428468729f583e11fe3d8cdbc1f597dc0a1a4571 100644 (file)
@@ -37,10 +37,15 @@ Python 3.   All SQLAlchemy modules and unit tests are now interpreted
 equally well with any Python interpreter from 2.6 forward, including
 the 3.1 and 3.2 interpreters.
 
-At the moment, the C extensions are still not fully ported to
-Python 3.
+:ticket:`2671`
 
+C Extensions Supported on Python 3
+-----------------------------------
 
+The C extensions have been ported to support Python 3 and now build
+in both Python 2 and Python 3 environments.
+
+:ticket:`2161`
 
 .. _behavioral_changes_09:
 
index 4e82ffc6b5a4eccade29a0630e0df335caae0132..34ae949f711761c75474c5b539359a264f90b66e 100644 (file)
@@ -1,7 +1,7 @@
 /*
 processors.c
 Copyright (C) 2010-2013 the SQLAlchemy authors and contributors <see AUTHORS file>
-Copyright (C) 2010 Gaetan de Menten gdementen@gmail.com
+Copyright (C) 2010-2011 Gaetan de Menten gdementen@gmail.com
 
 This module is part of SQLAlchemy and is released under
 the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -10,13 +10,15 @@ the MIT License: http://www.opensource.org/licenses/mit-license.php
 #include <Python.h>
 #include <datetime.h>
 
+#define MODULE_NAME "cprocessors"
+#define MODULE_DOC "Module containing C versions of data processing functions."
+
 #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
 
-
 static PyObject *
 int_to_boolean(PyObject *self, PyObject *arg)
 {
@@ -26,7 +28,12 @@ int_to_boolean(PyObject *self, PyObject *arg)
     if (arg == Py_None)
         Py_RETURN_NONE;
 
+
+#if PY_MAJOR_VERSION >= 3
+    l = PyLong_AsLong(arg);
+#else
     l = PyInt_AsLong(arg);
+#endif
     if (l == 0) {
         res = Py_False;
     } else if (l == 1) {
@@ -65,23 +72,48 @@ to_float(PyObject *self, PyObject *arg)
 static PyObject *
 str_to_datetime(PyObject *self, PyObject *arg)
 {
+#if PY_MAJOR_VERSION >= 3
+    PyObject *bytes;
+    PyObject *err_bytes;
+#endif
     const char *str;
+    int numparsed;
     unsigned int year, month, day, hour, minute, second, microsecond = 0;
     PyObject *err_repr;
 
     if (arg == Py_None)
         Py_RETURN_NONE;
 
+#if PY_MAJOR_VERSION >= 3
+    bytes = PyUnicode_AsASCIIString(arg);
+    if (bytes == NULL)
+        str = NULL;
+    else
+        str = PyBytes_AS_STRING(bytes);
+#else
     str = PyString_AsString(arg);
+#endif
     if (str == NULL) {
         err_repr = PyObject_Repr(arg);
         if (err_repr == NULL)
             return NULL;
+#if PY_MAJOR_VERSION >= 3
+        err_bytes = PyUnicode_AsASCIIString(err_repr);
+        if (err_bytes == NULL)
+            return NULL;
+        PyErr_Format(
+                PyExc_ValueError,
+                "Couldn't parse datetime string '%.200s' "
+                "- value is not a string.",
+                PyBytes_AS_STRING(err_bytes));
+        Py_DECREF(err_bytes);
+#else
         PyErr_Format(
                 PyExc_ValueError,
                 "Couldn't parse datetime string '%.200s' "
                 "- value is not a string.",
                 PyString_AsString(err_repr));
+#endif
         Py_DECREF(err_repr);
         return NULL;
     }
@@ -92,15 +124,30 @@ str_to_datetime(PyObject *self, PyObject *arg)
     not accept "2000-01-01 00:00:00.". I don't know which is better, but they
     should be coherent.
     */
-    if (sscanf(str, "%4u-%2u-%2u %2u:%2u:%2u.%6u", &year, &month, &day,
-               &hour, &minute, &second, &microsecond) < 6) {
+    numparsed = sscanf(str, "%4u-%2u-%2u %2u:%2u:%2u.%6u", &year, &month, &day,
+                       &hour, &minute, &second, &microsecond);
+#if PY_MAJOR_VERSION >= 3
+    Py_DECREF(bytes);
+#endif
+    if (numparsed < 6) {
         err_repr = PyObject_Repr(arg);
         if (err_repr == NULL)
             return NULL;
+#if PY_MAJOR_VERSION >= 3
+        err_bytes = PyUnicode_AsASCIIString(err_repr);
+        if (err_bytes == NULL)
+            return NULL;
+        PyErr_Format(
+                PyExc_ValueError,
+                "Couldn't parse datetime string: %.200s",
+                PyBytes_AS_STRING(err_bytes));
+        Py_DECREF(err_bytes);
+#else
         PyErr_Format(
                 PyExc_ValueError,
                 "Couldn't parse datetime string: %.200s",
                 PyString_AsString(err_repr));
+#endif
         Py_DECREF(err_repr);
         return NULL;
     }
@@ -111,22 +158,47 @@ str_to_datetime(PyObject *self, PyObject *arg)
 static PyObject *
 str_to_time(PyObject *self, PyObject *arg)
 {
+#if PY_MAJOR_VERSION >= 3
+    PyObject *bytes;
+    PyObject *err_bytes;
+#endif
     const char *str;
+    int numparsed;
     unsigned int hour, minute, second, microsecond = 0;
     PyObject *err_repr;
 
     if (arg == Py_None)
         Py_RETURN_NONE;
 
+#if PY_MAJOR_VERSION >= 3
+    bytes = PyUnicode_AsASCIIString(arg);
+    if (bytes == NULL)
+        str = NULL;
+    else
+        str = PyBytes_AS_STRING(bytes);
+#else
     str = PyString_AsString(arg);
+#endif
     if (str == NULL) {
         err_repr = PyObject_Repr(arg);
         if (err_repr == NULL)
             return NULL;
+
+#if PY_MAJOR_VERSION >= 3
+        err_bytes = PyUnicode_AsASCIIString(err_repr);
+        if (err_bytes == NULL)
+            return NULL;
+        PyErr_Format(
+                PyExc_ValueError,
+                "Couldn't parse time string '%.200s' - value is not a string.",
+                PyBytes_AS_STRING(err_bytes));
+        Py_DECREF(err_bytes);
+#else
         PyErr_Format(
                 PyExc_ValueError,
                 "Couldn't parse time string '%.200s' - value is not a string.",
                 PyString_AsString(err_repr));
+#endif
         Py_DECREF(err_repr);
         return NULL;
     }
@@ -137,15 +209,30 @@ str_to_time(PyObject *self, PyObject *arg)
     not accept "00:00:00.". I don't know which is better, but they should be
     coherent.
     */
-    if (sscanf(str, "%2u:%2u:%2u.%6u", &hour, &minute, &second,
-               &microsecond) < 3) {
+    numparsed = sscanf(str, "%2u:%2u:%2u.%6u", &hour, &minute, &second,
+                       &microsecond);
+#if PY_MAJOR_VERSION >= 3
+    Py_DECREF(bytes);
+#endif
+    if (numparsed < 3) {
         err_repr = PyObject_Repr(arg);
         if (err_repr == NULL)
             return NULL;
+#if PY_MAJOR_VERSION >= 3
+        err_bytes = PyUnicode_AsASCIIString(err_repr);
+        if (err_bytes == NULL)
+            return NULL;
+        PyErr_Format(
+                PyExc_ValueError,
+                "Couldn't parse time string: %.200s",
+                PyBytes_AS_STRING(err_bytes));
+        Py_DECREF(err_bytes);
+#else
         PyErr_Format(
                 PyExc_ValueError,
                 "Couldn't parse time string: %.200s",
                 PyString_AsString(err_repr));
+#endif
         Py_DECREF(err_repr);
         return NULL;
     }
@@ -155,34 +242,73 @@ str_to_time(PyObject *self, PyObject *arg)
 static PyObject *
 str_to_date(PyObject *self, PyObject *arg)
 {
+#if PY_MAJOR_VERSION >= 3
+    PyObject *bytes;
+    PyObject *err_bytes;
+#endif
     const char *str;
+    int numparsed;
     unsigned int year, month, day;
     PyObject *err_repr;
 
     if (arg == Py_None)
         Py_RETURN_NONE;
 
+#if PY_MAJOR_VERSION >= 3
+    bytes = PyUnicode_AsASCIIString(arg);
+    if (bytes == NULL)
+        str = NULL;
+    else
+        str = PyBytes_AS_STRING(bytes);
+#else
     str = PyString_AsString(arg);
+#endif
     if (str == NULL) {
         err_repr = PyObject_Repr(arg);
         if (err_repr == NULL)
             return NULL;
+#if PY_MAJOR_VERSION >= 3
+        err_bytes = PyUnicode_AsASCIIString(err_repr);
+        if (err_bytes == NULL)
+            return NULL;
+        PyErr_Format(
+                PyExc_ValueError,
+                "Couldn't parse date string '%.200s' - value is not a string.",
+                PyBytes_AS_STRING(err_bytes));
+        Py_DECREF(err_bytes);
+#else
         PyErr_Format(
                 PyExc_ValueError,
                 "Couldn't parse date string '%.200s' - value is not a string.",
                 PyString_AsString(err_repr));
+#endif
         Py_DECREF(err_repr);
         return NULL;
     }
 
-    if (sscanf(str, "%4u-%2u-%2u", &year, &month, &day) != 3) {
+    numparsed = sscanf(str, "%4u-%2u-%2u", &year, &month, &day);
+#if PY_MAJOR_VERSION >= 3
+    Py_DECREF(bytes);
+#endif
+    if (numparsed != 3) {
         err_repr = PyObject_Repr(arg);
         if (err_repr == NULL)
             return NULL;
+#if PY_MAJOR_VERSION >= 3
+        err_bytes = PyUnicode_AsASCIIString(err_repr);
+        if (err_bytes == NULL)
+            return NULL;
+        PyErr_Format(
+                PyExc_ValueError,
+                "Couldn't parse date string: %.200s",
+                PyBytes_AS_STRING(err_bytes));
+        Py_DECREF(err_bytes);
+#else
         PyErr_Format(
                 PyExc_ValueError,
                 "Couldn't parse date string: %.200s",
                 PyString_AsString(err_repr));
+#endif
         Py_DECREF(err_repr);
         return NULL;
     }
@@ -219,17 +345,35 @@ UnicodeResultProcessor_init(UnicodeResultProcessor *self, PyObject *args,
     PyObject *encoding, *errors = NULL;
     static char *kwlist[] = {"encoding", "errors", NULL};
 
+#if PY_MAJOR_VERSION >= 3
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "U|U:__init__", kwlist,
+                                     &encoding, &errors))
+        return -1;
+#else
     if (!PyArg_ParseTupleAndKeywords(args, kwds, "S|S:__init__", kwlist,
                                      &encoding, &errors))
         return -1;
+#endif
 
+#if PY_MAJOR_VERSION >= 3
+    encoding = PyUnicode_AsASCIIString(encoding);
+#else
     Py_INCREF(encoding);
+#endif
     self->encoding = encoding;
 
     if (errors) {
+#if PY_MAJOR_VERSION >= 3
+        errors = PyUnicode_AsASCIIString(errors);
+#else
         Py_INCREF(errors);
+#endif
     } else {
+#if PY_MAJOR_VERSION >= 3
+        errors = PyBytes_FromString("strict");
+#else
         errors = PyString_FromString("strict");
+#endif
         if (errors == NULL)
             return -1;
     }
@@ -248,11 +392,19 @@ UnicodeResultProcessor_process(UnicodeResultProcessor *self, PyObject *value)
     if (value == Py_None)
         Py_RETURN_NONE;
 
+#if PY_MAJOR_VERSION >= 3
+    if (PyBytes_AsStringAndSize(value, &str, &len))
+        return NULL;
+
+    encoding = PyBytes_AS_STRING(self->encoding);
+    errors = PyBytes_AS_STRING(self->errors);
+#else
     if (PyString_AsStringAndSize(value, &str, &len))
         return NULL;
 
     encoding = PyString_AS_STRING(self->encoding);
     errors = PyString_AS_STRING(self->errors);
+#endif
 
     return PyUnicode_Decode(str, len, encoding, errors);
 }
@@ -262,7 +414,11 @@ UnicodeResultProcessor_dealloc(UnicodeResultProcessor *self)
 {
     Py_XDECREF(self->encoding);
     Py_XDECREF(self->errors);
+#if PY_MAJOR_VERSION >= 3
+    Py_TYPE(self)->tp_free((PyObject*)self);
+#else
     self->ob_type->tp_free((PyObject*)self);
+#endif
 }
 
 static PyMethodDef UnicodeResultProcessor_methods[] = {
@@ -272,8 +428,7 @@ static PyMethodDef UnicodeResultProcessor_methods[] = {
 };
 
 static PyTypeObject UnicodeResultProcessorType = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                          /* ob_size */
+    PyVarObject_HEAD_INIT(NULL, 0)
     "sqlalchemy.cprocessors.UnicodeResultProcessor",        /* tp_name */
     sizeof(UnicodeResultProcessor),             /* tp_basicsize */
     0,                                          /* tp_itemsize */
@@ -323,7 +478,11 @@ DecimalResultProcessor_init(DecimalResultProcessor *self, PyObject *args,
 {
     PyObject *type, *format;
 
+#if PY_MAJOR_VERSION >= 3
+    if (!PyArg_ParseTuple(args, "OU", &type, &format))
+#else
     if (!PyArg_ParseTuple(args, "OS", &type, &format))
+#endif
         return -1;
 
     Py_INCREF(type);
@@ -343,11 +502,21 @@ DecimalResultProcessor_process(DecimalResultProcessor *self, PyObject *value)
     if (value == Py_None)
         Py_RETURN_NONE;
 
+    /* Decimal does not accept float values directly */
+    /* SQLite can also give us an integer here (see [ticket:2432]) */
+    /* XXX: starting with Python 3.1, we could use Decimal.from_float(f),
+                 but the result wouldn't be the same */
+
     args = PyTuple_Pack(1, value);
     if (args == NULL)
         return NULL;
 
+#if PY_MAJOR_VERSION >= 3
+    str = PyUnicode_Format(self->format, args);
+#else
     str = PyString_Format(self->format, args);
+#endif
+
     Py_DECREF(args);
     if (str == NULL)
         return NULL;
@@ -362,7 +531,11 @@ DecimalResultProcessor_dealloc(DecimalResultProcessor *self)
 {
     Py_XDECREF(self->type);
     Py_XDECREF(self->format);
+#if PY_MAJOR_VERSION >= 3
+    Py_TYPE(self)->tp_free((PyObject*)self);
+#else
     self->ob_type->tp_free((PyObject*)self);
+#endif
 }
 
 static PyMethodDef DecimalResultProcessor_methods[] = {
@@ -372,8 +545,7 @@ static PyMethodDef DecimalResultProcessor_methods[] = {
 };
 
 static PyTypeObject DecimalResultProcessorType = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                          /* ob_size */
+    PyVarObject_HEAD_INIT(NULL, 0)
     "sqlalchemy.DecimalResultProcessor",        /* tp_name */
     sizeof(DecimalResultProcessor),             /* tp_basicsize */
     0,                                          /* tp_itemsize */
@@ -413,11 +585,6 @@ static PyTypeObject DecimalResultProcessorType = {
     0,                                          /* tp_new */
 };
 
-#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
-#define PyMODINIT_FUNC void
-#endif
-
-
 static PyMethodDef module_methods[] = {
     {"int_to_boolean", int_to_boolean, METH_O,
      "Convert an integer to a boolean."},
@@ -434,23 +601,53 @@ static PyMethodDef module_methods[] = {
     {NULL, NULL, 0, NULL}        /* Sentinel */
 };
 
+#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+
+
+#if PY_MAJOR_VERSION >= 3
+
+static struct PyModuleDef module_def = {
+    PyModuleDef_HEAD_INIT,
+    MODULE_NAME,
+    MODULE_DOC,
+    -1,
+    module_methods
+};
+
+#define INITERROR return NULL
+
+PyObject *
+PyInit_cprocessors(void)
+
+#else
+
+#define INITERROR return
+
 PyMODINIT_FUNC
 initcprocessors(void)
+
+#endif
+
 {
     PyObject *m;
 
     UnicodeResultProcessorType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&UnicodeResultProcessorType) < 0)
-        return;
+        INITERROR;
 
     DecimalResultProcessorType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&DecimalResultProcessorType) < 0)
-        return;
+        INITERROR;
 
-    m = Py_InitModule3("cprocessors", module_methods,
-                       "Module containing C versions of data processing functions.");
+#if PY_MAJOR_VERSION >= 3
+    m = PyModule_Create(&module_def);
+#else
+    m = Py_InitModule3(MODULE_NAME, module_methods, MODULE_DOC);
+#endif
     if (m == NULL)
-        return;
+        INITERROR;
 
     PyDateTime_IMPORT;
 
@@ -461,5 +658,8 @@ initcprocessors(void)
     Py_INCREF(&DecimalResultProcessorType);
     PyModule_AddObject(m, "DecimalResultProcessor",
                        (PyObject *)&DecimalResultProcessorType);
-}
 
+#if PY_MAJOR_VERSION >= 3
+    return m;
+#endif
+}
index b70f9c271dc91ec8f54f66aefacdffc96cfba828..cd9e5e11dc5c466c7999561b67b2a2370f749e4e 100644 (file)
@@ -1,7 +1,7 @@
 /*
 resultproxy.c
 Copyright (C) 2010-2013 the SQLAlchemy authors and contributors <see AUTHORS file>
-Copyright (C) 2010 Gaetan de Menten gdementen@gmail.com
+Copyright (C) 2010-2011 Gaetan de Menten gdementen@gmail.com
 
 This module is part of SQLAlchemy and is released under
 the MIT License: http://www.opensource.org/licenses/mit-license.php
@@ -9,6 +9,9 @@ the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 #include <Python.h>
 
+#define MODULE_NAME "cresultproxy"
+#define MODULE_DOC "Module containing C versions of core ResultProxy classes."
+
 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
 typedef int Py_ssize_t;
 #define PY_SSIZE_T_MAX INT_MAX
@@ -150,7 +153,11 @@ BaseRowProxy_dealloc(BaseRowProxy *self)
     Py_XDECREF(self->row);
     Py_XDECREF(self->processors);
     Py_XDECREF(self->keymap);
+#if PY_MAJOR_VERSION >= 3
+    Py_TYPE(self)->tp_free((PyObject *)self);
+#else
     self->ob_type->tp_free((PyObject *)self);
+#endif
 }
 
 static PyObject *
@@ -245,14 +252,21 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key)
     PyObject *processor, *value, *processed_value;
     PyObject *row, *record, *result, *indexobject;
     PyObject *exc_module, *exception, *cstr_obj;
+#if PY_MAJOR_VERSION >= 3
+    PyObject *bytes;
+#endif
     char *cstr_key;
     long index;
     int key_fallback = 0;
     int tuple_check = 0;
 
+#if PY_MAJOR_VERSION < 3
     if (PyInt_CheckExact(key)) {
         index = PyInt_AS_LONG(key);
-    } else if (PyLong_CheckExact(key)) {
+    }
+#endif
+
+    if (PyLong_CheckExact(key)) {
         index = PyLong_AsLong(key);
         if ((index == -1) && PyErr_Occurred())
             /* -1 can be either the actual value, or an error flag. */
@@ -305,7 +319,21 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key)
             cstr_obj = PyObject_Str(key);
             if (cstr_obj == NULL)
                 return NULL;
+
+/*
+           FIXME: raise encoding error exception (in both versions below)
+           if the key contains non-ascii chars, instead of an
+           InvalidRequestError without any message like in the
+           python version.
+*/
+#if PY_MAJOR_VERSION >= 3
+            bytes = PyUnicode_AsASCIIString(cstr_obj);
+            if (bytes == NULL)
+                return NULL;
+            cstr_key = PyBytes_AS_STRING(bytes);
+#else
             cstr_key = PyString_AsString(cstr_obj);
+#endif
             if (cstr_key == NULL) {
                 Py_DECREF(cstr_obj);
                 return NULL;
@@ -318,7 +346,11 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key)
             return NULL;
         }
 
+#if PY_MAJOR_VERSION >= 3
+        index = PyLong_AsLong(indexobject);
+#else
         index = PyInt_AsLong(indexobject);
+#endif
         if ((index == -1) && PyErr_Occurred())
             /* -1 can be either the actual value, or an error flag. */
             return NULL;
@@ -357,13 +389,23 @@ BaseRowProxy_subscript(BaseRowProxy *self, PyObject *key)
 static PyObject *
 BaseRowProxy_getitem(PyObject *self, Py_ssize_t i)
 {
-    return BaseRowProxy_subscript((BaseRowProxy*)self, PyInt_FromSsize_t(i));
+    PyObject *index;
+
+#if PY_MAJOR_VERSION >= 3
+    index = PyLong_FromSsize_t(i);
+#else
+    index = PyInt_FromSsize_t(i);
+#endif
+    return BaseRowProxy_subscript((BaseRowProxy*)self, index);
 }
 
 static PyObject *
 BaseRowProxy_getattro(BaseRowProxy *self, PyObject *name)
 {
     PyObject *tmp;
+#if PY_MAJOR_VERSION >= 3
+    PyObject *err_bytes;
+#endif
 
     if (!(tmp = PyObject_GenericGetAttr((PyObject *)self, name))) {
         if (!PyErr_ExceptionMatches(PyExc_AttributeError))
@@ -375,11 +417,23 @@ BaseRowProxy_getattro(BaseRowProxy *self, PyObject *name)
 
     tmp = BaseRowProxy_subscript(self, name);
     if (tmp == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) {
+
+#if PY_MAJOR_VERSION >= 3
+        err_bytes = PyUnicode_AsASCIIString(name);
+        if (err_bytes == NULL)
+            return NULL;
+        PyErr_Format(
+                PyExc_AttributeError,
+                "Could not locate column in row for column '%.200s'",
+                PyBytes_AS_STRING(err_bytes)
+            );
+#else
         PyErr_Format(
                 PyExc_AttributeError,
                 "Could not locate column in row for column '%.200s'",
                 PyString_AsString(name)
             );
+#endif
         return NULL;
     }
     return tmp;
@@ -565,8 +619,7 @@ static PyMappingMethods BaseRowProxy_as_mapping = {
 };
 
 static PyTypeObject BaseRowProxyType = {
-    PyObject_HEAD_INIT(NULL)
-    0,                                  /* ob_size */
+    PyVarObject_HEAD_INIT(NULL, 0)
     "sqlalchemy.cresultproxy.BaseRowProxy",          /* tp_name */
     sizeof(BaseRowProxy),               /* tp_basicsize */
     0,                                  /* tp_itemsize */
@@ -606,34 +659,60 @@ static PyTypeObject BaseRowProxyType = {
     0                                   /* tp_new */
 };
 
+static PyMethodDef module_methods[] = {
+    {"safe_rowproxy_reconstructor", safe_rowproxy_reconstructor, METH_VARARGS,
+     "reconstruct a RowProxy instance from its pickled form."},
+    {NULL, NULL, 0, NULL}        /* Sentinel */
+};
 
 #ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
 #define PyMODINIT_FUNC void
 #endif
 
 
-static PyMethodDef module_methods[] = {
-    {"safe_rowproxy_reconstructor", safe_rowproxy_reconstructor, METH_VARARGS,
-     "reconstruct a RowProxy instance from its pickled form."},
-    {NULL, NULL, 0, NULL}        /* Sentinel */
+#if PY_MAJOR_VERSION >= 3
+
+static struct PyModuleDef module_def = {
+    PyModuleDef_HEAD_INIT,
+    MODULE_NAME,
+    MODULE_DOC,
+    -1,
+    module_methods
 };
 
+#define INITERROR return NULL
+
+PyObject *
+PyInit_cresultproxy(void)
+
+#else
+
+#define INITERROR return
+
 PyMODINIT_FUNC
 initcresultproxy(void)
+
+#endif
+
 {
     PyObject *m;
 
     BaseRowProxyType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&BaseRowProxyType) < 0)
-        return;
+        INITERROR;
 
-    m = Py_InitModule3("cresultproxy", module_methods,
-                       "Module containing C versions of core ResultProxy classes.");
+#if PY_MAJOR_VERSION >= 3
+    m = PyModule_Create(&module_def);
+#else
+    m = Py_InitModule3(MODULE_NAME, module_methods, MODULE_DOC);
+#endif
     if (m == NULL)
-        return;
+        INITERROR;
 
     Py_INCREF(&BaseRowProxyType);
     PyModule_AddObject(m, "BaseRowProxy", (PyObject *)&BaseRowProxyType);
 
+#if PY_MAJOR_VERSION >= 3
+    return m;
+#endif
 }
-
index 5928c41030b43e81ec95c5fb4b5f333496150cbc..b7dafdc50f726b1877b66868d72a274daab24071 100644 (file)
@@ -8,6 +8,9 @@ the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 #include <Python.h>
 
+#define MODULE_NAME "cutils"
+#define MODULE_DOC "Module containing C versions of utility functions."
+
 /*
     Given arguments from the calling form *multiparams, **params,
     return a list of bind parameter structures, usually a list of
@@ -172,26 +175,51 @@ distill_params(PyObject *self, PyObject *args)
        }
 }
 
-#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
-#define PyMODINIT_FUNC void
-#endif
-
-
 static PyMethodDef module_methods[] = {
     {"_distill_params", distill_params, METH_VARARGS,
      "Distill an execute() parameter structure."},
     {NULL, NULL, 0, NULL}        /* Sentinel */
 };
 
+#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
+#define PyMODINIT_FUNC void
+#endif
+
+#if PY_MAJOR_VERSION >= 3
+
+static struct PyModuleDef module_def = {
+    PyModuleDef_HEAD_INIT,
+    MODULE_NAME,
+    MODULE_DOC,
+    -1,
+    module_methods
+ };
+#endif
+
+
+#if PY_MAJOR_VERSION >= 3
+PyObject *
+PyInit_cutils(void)
+#else
 PyMODINIT_FUNC
 initcutils(void)
+#endif
 {
     PyObject *m;
 
-    m = Py_InitModule3("cutils", module_methods,
-                       "Internal utility functions.");
-    if (m == NULL)
-        return;
+#if PY_MAJOR_VERSION >= 3
+    m = PyModule_Create(&module_def);
+#else
+    m = Py_InitModule3(MODULE_NAME, module_methods, MODULE_DOC);
+#endif
 
+#if PY_MAJOR_VERSION >= 3
+    if (m == NULL)
+        return NULL;
+    return m;
+#else
+    if (m == NULL)
+       return;
+#endif
 }
 
index 5b506f529ae68c67962c71fc0b529c70ef59360f..8e7e62829db1d999582ce03e48bbf96a890d9a43 100644 (file)
--- a/setup.py
+++ b/setup.py
@@ -137,7 +137,7 @@ def run_setup(with_cext):
             **kwargs
           )
 
-if pypy or jython or py3k:
+if pypy or jython:
     run_setup(False)
     status_msgs(
         "WARNING: C extensions are not supported on " +
index c2ea3e95919143ebfa65c6b1884acf9a1ed851d3..4a392d2081371bb311a97d3b8667d257f5f05464 100644 (file)
@@ -1,15 +1,15 @@
 # /Users/classic/dev/sqlalchemy/test/profiles.txt
 # This file is written out on a per-environment basis.
-# For each test in aaa_profiling, the corresponding function and
+# For each test in aaa_profiling, the corresponding function and 
 # environment is located within this file.  If it doesn't exist,
 # the test is skipped.
-# If a callcount does exist, it is compared to what we received.
+# If a callcount does exist, it is compared to what we received. 
 # assertions are raised if the counts do not match.
-#
-# To add a new callcount test, apply the function_call_count
-# decorator and re-run the tests using the --write-profiles
+# 
+# To add a new callcount test, apply the function_call_count 
+# decorator and re-run the tests using the --write-profiles 
 # option - this file will be rewritten including the new count.
-#
+# 
 
 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_insert
 
@@ -25,6 +25,7 @@ test.aaa_profiling.test_compiler.CompileTest.test_insert 3.2_postgresql_psycopg2
 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.2_sqlite_pysqlite_nocextensions 74
 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.3_oracle_cx_oracle_nocextensions 76
 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.3_postgresql_psycopg2_nocextensions 74
+test.aaa_profiling.test_compiler.CompileTest.test_insert 3.3_sqlite_pysqlite_cextensions 76
 test.aaa_profiling.test_compiler.CompileTest.test_insert 3.3_sqlite_pysqlite_nocextensions 74
 
 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_select
@@ -41,6 +42,7 @@ test.aaa_profiling.test_compiler.CompileTest.test_select 3.2_postgresql_psycopg2
 test.aaa_profiling.test_compiler.CompileTest.test_select 3.2_sqlite_pysqlite_nocextensions 151
 test.aaa_profiling.test_compiler.CompileTest.test_select 3.3_oracle_cx_oracle_nocextensions 153
 test.aaa_profiling.test_compiler.CompileTest.test_select 3.3_postgresql_psycopg2_nocextensions 151
+test.aaa_profiling.test_compiler.CompileTest.test_select 3.3_sqlite_pysqlite_cextensions 157
 test.aaa_profiling.test_compiler.CompileTest.test_select 3.3_sqlite_pysqlite_nocextensions 151
 
 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_select_labels
@@ -57,6 +59,7 @@ test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.2_postgresql_p
 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.2_sqlite_pysqlite_nocextensions 185
 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.3_oracle_cx_oracle_nocextensions 187
 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.3_postgresql_psycopg2_nocextensions 185
+test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.3_sqlite_pysqlite_cextensions 191
 test.aaa_profiling.test_compiler.CompileTest.test_select_labels 3.3_sqlite_pysqlite_nocextensions 185
 
 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_update
@@ -73,6 +76,7 @@ test.aaa_profiling.test_compiler.CompileTest.test_update 3.2_postgresql_psycopg2
 test.aaa_profiling.test_compiler.CompileTest.test_update 3.2_sqlite_pysqlite_nocextensions 75
 test.aaa_profiling.test_compiler.CompileTest.test_update 3.3_oracle_cx_oracle_nocextensions 77
 test.aaa_profiling.test_compiler.CompileTest.test_update 3.3_postgresql_psycopg2_nocextensions 75
+test.aaa_profiling.test_compiler.CompileTest.test_update 3.3_sqlite_pysqlite_cextensions 77
 test.aaa_profiling.test_compiler.CompileTest.test_update 3.3_sqlite_pysqlite_nocextensions 75
 
 # TEST: test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause
@@ -89,6 +93,7 @@ test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.2_postgre
 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.2_sqlite_pysqlite_nocextensions 136
 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_oracle_cx_oracle_nocextensions 138
 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_postgresql_psycopg2_nocextensions 136
+test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_sqlite_pysqlite_cextensions 143
 test.aaa_profiling.test_compiler.CompileTest.test_update_whereclause 3.3_sqlite_pysqlite_nocextensions 136
 
 # TEST: test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline
@@ -99,6 +104,7 @@ test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_postgresql_psycop
 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_postgresql_psycopg2_nocextensions 51049
 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_cextensions 30008
 test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 2.7_sqlite_pysqlite_nocextensions 39025
+test.aaa_profiling.test_orm.DeferOptionsTest.test_baseline 3.3_sqlite_pysqlite_cextensions 31190
 
 # TEST: test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols
 
@@ -108,6 +114,7 @@ test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_postgresql
 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_postgresql_psycopg2_nocextensions 32835
 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_sqlite_pysqlite_cextensions 29812
 test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 2.7_sqlite_pysqlite_nocextensions 32817
+test.aaa_profiling.test_orm.DeferOptionsTest.test_defer_many_cols 3.3_sqlite_pysqlite_cextensions 30960
 
 # TEST: test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity
 
@@ -123,6 +130,7 @@ test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_
 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.2_sqlite_pysqlite_nocextensions 18987
 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.3_oracle_cx_oracle_nocextensions 18987
 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.3_postgresql_psycopg2_nocextensions 18987
+test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.3_sqlite_pysqlite_cextensions 18987
 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_identity 3.3_sqlite_pysqlite_nocextensions 18987
 
 # TEST: test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity
@@ -139,6 +147,7 @@ test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_
 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.2_sqlite_pysqlite_nocextensions 121822
 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.3_oracle_cx_oracle_nocextensions 130792
 test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.3_postgresql_psycopg2_nocextensions 121822
+test.aaa_profiling.test_orm.LoadManyToOneFromIdentityTest.test_many_to_one_load_no_identity 3.3_sqlite_pysqlite_cextensions 164074
 
 # TEST: test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks
 
@@ -153,6 +162,7 @@ test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 2.
 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.2_postgresql_psycopg2_nocextensions 20424
 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.3_oracle_cx_oracle_nocextensions 21244
 test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.3_postgresql_psycopg2_nocextensions 20344
+test.aaa_profiling.test_orm.MergeBackrefsTest.test_merge_pending_with_all_pks 3.3_sqlite_pysqlite_cextensions 23404
 
 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_load
 
@@ -167,6 +177,7 @@ test.aaa_profiling.test_orm.MergeTest.test_merge_load 2.7_sqlite_pysqlite_nocext
 test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.2_postgresql_psycopg2_nocextensions 1332
 test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.3_oracle_cx_oracle_nocextensions 1366
 test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.3_postgresql_psycopg2_nocextensions 1357
+test.aaa_profiling.test_orm.MergeTest.test_merge_load 3.3_sqlite_pysqlite_cextensions 1598
 
 # TEST: test.aaa_profiling.test_orm.MergeTest.test_merge_no_load
 
@@ -182,6 +193,7 @@ test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.2_postgresql_psycopg2
 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.2_sqlite_pysqlite_nocextensions 127,19
 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_oracle_cx_oracle_nocextensions 134,19
 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_postgresql_psycopg2_nocextensions 127,19
+test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_sqlite_pysqlite_cextensions 134,19
 test.aaa_profiling.test_orm.MergeTest.test_merge_no_load 3.3_sqlite_pysqlite_nocextensions 127,19
 
 # TEST: test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect
@@ -198,6 +210,7 @@ test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.2_postgresql_psy
 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.2_sqlite_pysqlite_nocextensions 75
 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.3_oracle_cx_oracle_nocextensions 74
 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.3_postgresql_psycopg2_nocextensions 74
+test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.3_sqlite_pysqlite_cextensions 74
 test.aaa_profiling.test_pool.QueuePoolTest.test_first_connect 3.3_sqlite_pysqlite_nocextensions 74
 
 # TEST: test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect
@@ -214,6 +227,7 @@ test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.2_postgresql_ps
 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.2_sqlite_pysqlite_nocextensions 23
 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.3_oracle_cx_oracle_nocextensions 22
 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.3_postgresql_psycopg2_nocextensions 22
+test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.3_sqlite_pysqlite_cextensions 23
 test.aaa_profiling.test_pool.QueuePoolTest.test_second_connect 3.3_sqlite_pysqlite_nocextensions 22
 
 # TEST: test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect
@@ -230,6 +244,7 @@ test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.2_po
 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.2_sqlite_pysqlite_nocextensions 8
 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.3_oracle_cx_oracle_nocextensions 8
 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.3_postgresql_psycopg2_nocextensions 8
+test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.3_sqlite_pysqlite_cextensions 8
 test.aaa_profiling.test_pool.QueuePoolTest.test_second_samethread_connect 3.3_sqlite_pysqlite_nocextensions 8
 
 # TEST: test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute
@@ -246,6 +261,7 @@ test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute
 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.2_sqlite_pysqlite_nocextensions 41
 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.3_oracle_cx_oracle_nocextensions 41
 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.3_postgresql_psycopg2_nocextensions 41
+test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.3_sqlite_pysqlite_cextensions 41
 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_connection_execute 3.3_sqlite_pysqlite_nocextensions 41
 
 # TEST: test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute
@@ -262,6 +278,7 @@ test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.2_
 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.2_sqlite_pysqlite_nocextensions 71
 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.3_oracle_cx_oracle_nocextensions 71
 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.3_postgresql_psycopg2_nocextensions 71
+test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.3_sqlite_pysqlite_cextensions 71
 test.aaa_profiling.test_resultset.ExecutionTest.test_minimal_engine_execute 3.3_sqlite_pysqlite_nocextensions 71
 
 # TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile
@@ -278,6 +295,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.2
 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.2_sqlite_pysqlite_nocextensions 15
 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.3_oracle_cx_oracle_nocextensions 15
 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.3_postgresql_psycopg2_nocextensions 15
+test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.3_sqlite_pysqlite_cextensions 15
 test.aaa_profiling.test_resultset.ResultSetTest.test_contains_doesnt_compile 3.3_sqlite_pysqlite_nocextensions 15
 
 # TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_string
@@ -294,6 +312,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.2_postgresql_psyco
 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.2_sqlite_pysqlite_nocextensions 14430
 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.3_oracle_cx_oracle_nocextensions 14548
 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.3_postgresql_psycopg2_nocextensions 14457
+test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.3_sqlite_pysqlite_cextensions 453
 test.aaa_profiling.test_resultset.ResultSetTest.test_string 3.3_sqlite_pysqlite_nocextensions 14430
 
 # TEST: test.aaa_profiling.test_resultset.ResultSetTest.test_unicode
@@ -310,6 +329,7 @@ test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.2_postgresql_psyc
 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.2_sqlite_pysqlite_nocextensions 14430
 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.3_oracle_cx_oracle_nocextensions 14548
 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.3_postgresql_psycopg2_nocextensions 14457
+test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.3_sqlite_pysqlite_cextensions 453
 test.aaa_profiling.test_resultset.ResultSetTest.test_unicode 3.3_sqlite_pysqlite_nocextensions 14430
 
 # TEST: test.aaa_profiling.test_zoomark.ZooMarkTest.test_profile_1a_populate