Index: psycopg/adapter_asis.c
===================================================================
--- psycopg/adapter_asis.c	(Revision 956)
+++ psycopg/adapter_asis.c	(Arbeitskopie)
@@ -22,7 +22,9 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <structmember.h>
+#if PY_MAJOR_VERSION < 3
 #include <stringobject.h>
+#endif
 #include <string.h>
 
 #define PSYCOPG_MODULE
@@ -38,7 +40,7 @@
 asis_str(asisObject *self)
 {
     if (self->wrapped == Py_None) {
-        return PyString_FromString("NULL");
+        return Text_FromUTF8("NULL");
     }
     else {
         return PyObject_Str(self->wrapped);
@@ -73,7 +75,7 @@
 /* object member list */
 
 static struct PyMemberDef asisObject_members[] = {
-    {"adapted", T_OBJECT, offsetof(asisObject, wrapped), RO},
+    {"adapted", T_OBJECT, offsetof(asisObject, wrapped), READONLY},
     {NULL}
 };
 
@@ -157,8 +159,7 @@
 "AsIs(str) -> new AsIs adapter object"
 
 PyTypeObject asisType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.AsIs",
     sizeof(asisObject),
     0,
Index: psycopg/connection_type.c
===================================================================
--- psycopg/connection_type.c	(Revision 956)
+++ psycopg/connection_type.c	(Arbeitskopie)
@@ -22,7 +22,9 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <structmember.h>
+#if PY_MAJOR_VERSION < 3
 #include <stringobject.h>
+#endif
 
 #include <string.h>
 #include <ctype.h>
@@ -270,23 +272,23 @@
 
 static struct PyMemberDef connectionObject_members[] = {
 #ifdef PSYCOPG_EXTENSIONS
-    {"closed", T_LONG, offsetof(connectionObject, closed), RO,
+    {"closed", T_LONG, offsetof(connectionObject, closed), READONLY,
         "True if the connection is closed."},
     {"isolation_level", T_LONG,
-        offsetof(connectionObject, isolation_level), RO,
+        offsetof(connectionObject, isolation_level), READONLY,
         "The current isolation level."},
-    {"encoding", T_STRING, offsetof(connectionObject, encoding), RO,
+    {"encoding", T_STRING, offsetof(connectionObject, encoding), READONLY,
         "The current client encoding."},
-    {"notices", T_OBJECT, offsetof(connectionObject, notice_list), RO},
-    {"notifies", T_OBJECT, offsetof(connectionObject, notifies), RO},
-    {"dsn", T_STRING, offsetof(connectionObject, dsn), RO,
+    {"notices", T_OBJECT, offsetof(connectionObject, notice_list), READONLY},
+    {"notifies", T_OBJECT, offsetof(connectionObject, notifies), READONLY},
+    {"dsn", T_STRING, offsetof(connectionObject, dsn), READONLY,
         "The current connection string."},
     {"status", T_INT,
-        offsetof(connectionObject, status), RO,
+        offsetof(connectionObject, status), READONLY,
         "The current transaction status."},
-    {"string_types", T_OBJECT, offsetof(connectionObject, string_types), RO,
+    {"string_types", T_OBJECT, offsetof(connectionObject, string_types), READONLY,
         "A set of typecasters to convert textual values."},
-    {"binary_types", T_OBJECT, offsetof(connectionObject, binary_types), RO,
+    {"binary_types", T_OBJECT, offsetof(connectionObject, binary_types), READONLY,
         "A set of typecasters to convert binary values."},
 #endif
     {NULL}
@@ -429,8 +431,7 @@
 "    ProgrammingError, IntegrityError, DataError, NotSupportedError"
 
 PyTypeObject connectionType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.connection",
     sizeof(connectionObject),
     0,
Index: psycopg/typecast_binary.c
===================================================================
--- psycopg/typecast_binary.c	(Revision 956)
+++ psycopg/typecast_binary.c	(Arbeitskopie)
@@ -38,7 +38,7 @@
         self->base, self->len
       );
     free(self->base);
-    self->ob_type->tp_free((PyObject *) self);
+    Py_TYPE(self)->tp_free((PyObject *) self);
 }
 
 static PyObject *
@@ -50,6 +50,8 @@
       );
 }
 
+#if PY_MAJOR_VERSION < 3
+/* XXX support 3.0 buffer protocol */
 static Py_ssize_t
 chunk_getreadbuffer(chunkObject *self, Py_ssize_t segment, void **ptr)
 {
@@ -78,12 +80,24 @@
     (segcountproc) chunk_getsegcount,
     (charbufferproc) NULL
 };
+#else
+/* 3.0 buffer interface */
+int chunk_getbuffer(PyObject *_self, Py_buffer *view, int flags)
+{
+    chunkObject *self = (chunkObject*)_self;
+    return PyBuffer_FillInfo(view, _self, self->base, self->len, 1, flags);
+}
+static PyBufferProcs chunk_as_buffer =
+{
+    chunk_getbuffer,
+    NULL,
+};
+#endif
 
 #define chunk_doc "memory chunk"
 
 PyTypeObject chunkType = {
-    PyObject_HEAD_INIT(NULL)
-    0,                          /* ob_size */
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.chunk",   /* tp_name */
     sizeof(chunkObject),        /* tp_basicsize */
     0,                          /* tp_itemsize */
@@ -203,8 +217,13 @@
 
     /* size_t->Py_ssize_t cast was validated above: */
     chunk->len = (Py_ssize_t) len;
+#if PY_MAJOR_VERSION < 3
     if ((res = PyBuffer_FromObject((PyObject *)chunk, 0, chunk->len)) == NULL)
         goto fail;
+#else
+    if ((res = PyMemoryView_FromObject((PyObject*)chunk)) == NULL)
+	goto fail;
+#endif
     /* PyBuffer_FromObject() created a new reference.  We'll release our
      * reference held in 'chunk' in the 'cleanup' clause. */
 
Index: psycopg/microprotocols_proto.c
===================================================================
--- psycopg/microprotocols_proto.c	(Revision 956)
+++ psycopg/microprotocols_proto.c	(Arbeitskopie)
@@ -22,7 +22,9 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <structmember.h>
+#if PY_MAJOR_VERSION < 3
 #include <stringobject.h>
+#endif
 
 #include <string.h>
 
@@ -101,7 +103,7 @@
 
 static struct PyMemberDef isqlquoteObject_members[] = {
     /* DBAPI-2.0 extensions (exception objects) */
-    {"_wrapped", T_OBJECT, offsetof(isqlquoteObject, wrapped), RO},
+    {"_wrapped", T_OBJECT, offsetof(isqlquoteObject, wrapped), READONLY},
     {NULL}
 };
 
@@ -158,8 +160,7 @@
 "returning the SQL representation of the object.\n\n"
 
 PyTypeObject isqlquoteType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.ISQLQuote",
     sizeof(isqlquoteObject),
     0,
Index: psycopg/cursor_type.c
===================================================================
--- psycopg/cursor_type.c	(Revision 956)
+++ psycopg/cursor_type.c	(Arbeitskopie)
@@ -20,7 +20,7 @@
  */
 
 #define PY_SSIZE_T_CLEAN
-#include <Python.h>
+#include "psycopg/python.h"
 #include <structmember.h>
 #include <string.h>
 
@@ -38,7 +38,32 @@
 
 extern PyObject *pyPsycopgTzFixedOffsetTimezone;
 
+static PyObject*
+encode_to_connection(cursorObject *self, PyObject *text)
+{
+    PyObject *enc = PyDict_GetItemString(psycoEncodings,
+					 self->conn->encoding);
+    /* enc is a borrowed reference; we won't decref it */
+    
+    if (enc) {
+        #if PY_MAJOR_VERSION < 3
+	text = PyUnicode_AsEncodedString(text, PyString_AsString(enc), NULL);
+        #else
+	text = PyObject_CallMethod(text, "encode", "O", enc);
+        #endif
+	/* if there was an error during the encoding from unicode to the
+	   target encoding, we just let the exception propagate */
+	if (text == NULL) { return NULL; }
+    } else {
+	PyErr_Format(InterfaceError,
+		     "can't encode unicode SQL statement to %s",
+		     self->conn->encoding);
+	return NULL;
+    }
+    return text;
+}
 
+
 /** DBAPI methods **/
 
 /* close method - close the cursor */
@@ -85,7 +110,7 @@
        just before returning. we also init *new to NULL to exit with an error
        if we can't complete the mogrification */
     n = *new = NULL;
-    c = PyString_AsString(fmt);
+    c = Bytes_AsString(fmt);
 
     while(*c) {
         /* handle plain percent symbol in format string */
@@ -114,7 +139,7 @@
             for (d = c + 2; *d && *d != ')'; d++);
 
             if (*d == ')') {
-                key = PyString_FromStringAndSize(c+2, (Py_ssize_t) (d-c-2));
+                key = Text_FromUTF8AndSize(c+2, (Py_ssize_t) (d-c-2));
                 value = PyObject_GetItem(var, key);
                 /* key has refcnt 1, value the original value + 1 */
 
@@ -142,7 +167,7 @@
                        optimization over the adapting code and can go away in
                        the future if somebody finds a None adapter usefull. */
                     if (value == Py_None) {
-                        t = PyString_FromString("NULL");
+                        t = Text_FromUTF8("NULL");
                         PyDict_SetItem(n, key, t);
                         /* t is a new object, refcnt = 1, key is at 2 */
 
@@ -218,7 +243,7 @@
             d = c+1;
 
             if (value == Py_None) {
-                PyTuple_SET_ITEM(n, index, PyString_FromString("NULL"));
+                PyTuple_SET_ITEM(n, index, Text_FromUTF8("NULL"));
                 while (*d && !isalpha(*d)) d++;
                 if (*d) *d = 's';
                 Py_DECREF(value);
@@ -265,27 +290,22 @@
         goto fail;
     }
 
+#if PY_MAJOR_VERSION < 3
     if (PyString_Check(sql)) {
         /* Necessary for ref-count symmetry with the unicode case: */
         Py_INCREF(sql);
     }
-    else if (PyUnicode_Check(sql)) {
-        PyObject *enc = PyDict_GetItemString(psycoEncodings,
-                                             self->conn->encoding);
-        /* enc is a borrowed reference; we won't decref it */
-
-        if (enc) {
-            sql = PyUnicode_AsEncodedString(sql, PyString_AsString(enc), NULL);
-            /* if there was an error during the encoding from unicode to the
-               target encoding, we just let the exception propagate */
-            if (sql == NULL) { goto fail; }
-        } else {
-            PyErr_Format(InterfaceError,
-                         "can't encode unicode SQL statement to %s",
-                         self->conn->encoding);
-            goto fail;
-        }
+    else 
+    if (PyUnicode_Check(sql)) {
+	sql = encode_to_connection(self, sql);
+	if (!sql)
+	    goto fail;
     }
+#else
+    if (PyUnicode_Check(sql)) {
+	Py_INCREF(sql);
+    }
+#endif
     else {
         /* the  is not unicode or string, raise an error */
         PyErr_SetString(PyExc_TypeError,
@@ -343,7 +363,19 @@
 
     if (vars && vars != Py_None)
     {
-        if(_mogrify(vars, operation, self->conn, &cvt) == -1) { goto fail; }
+	PyObject *operation_ascii;
+	int result;
+	if (Bytes_Check(operation)) {
+	    operation_ascii = operation;
+	    Py_INCREF(operation);
+	} else
+	    operation_ascii = PyUnicode_AsEncodedString(operation, "ascii",
+							NULL);
+	if (!operation_ascii)
+	    goto fail;
+	result = _mogrify(vars, operation_ascii, self->conn, &cvt);
+	Py_DECREF(operation_ascii);
+        if(result == -1) { goto fail; }
     }
 
     if (vars && cvt) {
@@ -357,8 +389,13 @@
            and return the appropriate ProgrammingError. we do that by grabbing
            the curren exception (we will later restore it if the type or the
            strings do not match.) */
+	#if PY_MAJOR_VERSION < 3
+	fquery = PyString_Format(operation, cvt);
+	#else
+	fquery = PyUnicode_Format(operation, cvt);
+	#endif
 
-        if (!(fquery = PyString_Format(operation, cvt))) {
+        if (!fquery) {
             PyObject *err, *arg, *trace;
             int pe = 0;
 
@@ -371,7 +408,18 @@
                 if (PyObject_HasAttrString(arg, "args")) {
                     PyObject *args = PyObject_GetAttrString(arg, "args");
                     PyObject *str = PySequence_GetItem(args, 0);
-                    const char *s = PyString_AS_STRING(str);
+		    #if PY_MAJOR_VERSION > 2
+		    PyObject *str_ascii = PyUnicode_AsEncodedString(str,
+								    "ascii",
+								    NULL);
+		    Py_DECREF(str);
+		    if (!str_ascii) {
+			Py_DECREF(args);
+			goto fail;
+		    }
+		    str = str_ascii;
+		    #endif
+                    const char *s = Bytes_AS_STRING(str);
 
                     Dprintf("psyco_curs_execute:     -> %s", s);
 
@@ -399,9 +447,15 @@
         }
 
         if (self->name != NULL) {
+	    #if PY_MAJOR_VERSION < 3
             self->query = PyString_FromFormat(
                 "DECLARE %s CURSOR WITHOUT HOLD FOR %s",
                 self->name, PyString_AS_STRING(fquery));
+	    #else
+            self->query = PyUnicode_FromFormat(
+                "DECLARE %s CURSOR WITHOUT HOLD FOR %U",
+                self->name, fquery);
+	    #endif
             Py_DECREF(fquery);
         }
         else {
@@ -410,9 +464,15 @@
     }
     else {
         if (self->name != NULL) {
+	    #if PY_MAJOR_VERSION < 3
             self->query = PyString_FromFormat(
                 "DECLARE %s CURSOR WITHOUT HOLD FOR %s",
                 self->name, PyString_AS_STRING(operation));
+	    #else
+            self->query = PyUnicode_FromFormat(
+                "DECLARE %s CURSOR WITHOUT HOLD FOR %U",
+                self->name, operation);
+	    #endif
         }
         else {
             /* Transfer reference ownership of the str in operation to
@@ -423,9 +483,14 @@
         }
     }
 
-    /* At this point, the SQL statement must be str, not unicode */
+    if (PyUnicode_Check(self->query)) {
+	PyObject *query_conn = encode_to_connection(self, self->query);
+	if (!query_conn) goto fail;
+	Py_DECREF(self->query);
+	self->query = query_conn;
+    }
     
-    res = pq_execute(self, PyString_AS_STRING(self->query), async);
+    res = pq_execute(self, Bytes_AS_STRING(self->query), async);
     Dprintf("psyco_curs_execute: res = %d, pgres = %p", res, self->pgres);
     if (res == -1) { goto fail; }
 
@@ -544,6 +609,7 @@
 {
     PyObject *vars = NULL, *cvt = NULL, *operation = NULL;
     PyObject *fquery;
+    PyObject *operation_ascii;
 
     static char *kwlist[] = {"query", "vars", NULL};
 
@@ -553,10 +619,21 @@
     }
 
     if (PyUnicode_Check(operation)) {
-        PyErr_SetString(NotSupportedError,
-                        "unicode queries not yet supported");
-        return NULL;
+	operation_ascii = PyUnicode_AsEncodedString(operation, "ascii", NULL);
+	if (!operation_ascii)
+	    return NULL;
     }
+#if PY_MAJOR_VERSION < 3
+    else if (PyString_Check(operation)) {
+	Py_INCREF(operation);
+	operation_ascii = operation;
+    } 
+#endif
+    else {
+	PyErr_SetString(PyExc_TypeError, "query must be a string");
+	return NULL;
+    }
+	
 
     EXC_IF_CURS_CLOSED(self);
     IFCLEARPGRES(self->pgres);
@@ -569,11 +646,21 @@
 
     if (vars)
     {
-        if(_mogrify(vars, operation, self->conn, &cvt) == -1) return NULL;
+        if(_mogrify(vars, operation_ascii, self->conn, &cvt) == -1) return NULL;
     }
 
+    Py_DECREF(operation_ascii);
+
     if (vars && cvt) {
-        if (!(fquery = PyString_Format(operation, cvt))) {
+#if PY_MAJOR_VERSION < 3
+	if (PyUnicode_Check(operation))
+	    fquery = PyUnicode_Format(operation, cvt);
+	else
+	    fquery = PyString_Format(operation, cvt);
+#else
+	fquery = PyUnicode_Format(operation, cvt);
+#endif
+        if (!fquery) {
             PyObject *err, *arg, *trace;
             int pe = 0;
 
@@ -586,7 +673,20 @@
                 if (PyObject_HasAttrString(arg, "args")) {
                     PyObject *args = PyObject_GetAttrString(arg, "args");
                     PyObject *str = PySequence_GetItem(args, 0);
-                    const char *s = PyString_AS_STRING(str);
+                    const char *s;
+		    #if PY_MAJOR_VERSION > 2
+		    PyObject *str_ascii = PyUnicode_AsEncodedString(str,
+								    "ascii",
+								    NULL);
+		    Py_DECREF(str);
+		    if (!str_ascii) {
+			Py_DECREF(args);
+			return NULL;
+		    }
+		    str = str_ascii;
+		    #endif
+		    
+		    s = Bytes_AS_STRING(str);
 
                     Dprintf("psyco_curs_execute:     -> %s", s);
 
@@ -973,8 +1073,10 @@
     sql[sl-2] = ')';
     sql[sl-1] = '\0';
 
-    operation = PyString_FromString(sql);
+    operation = Text_FromUTF8(sql);
     PyMem_Free((void*)sql);
+    if (!operation)
+	return NULL;
 
     if (_psyco_curs_execute(self, operation, parameters, async)) {
         Py_INCREF(parameters);
@@ -1130,14 +1232,27 @@
     columnlist[0] = '(';
 
     while ((col = PyIter_Next(coliter)) != NULL) {
-        if (!PyString_Check(col)) {
+        if (!Text_Check(col)) {
             Py_DECREF(col);
             Py_DECREF(coliter);
             PyErr_SetString(PyExc_ValueError,
                 "elements in column list must be strings");
             return -1;
         }
-        PyString_AsStringAndSize(col, &colname, &collen);
+	#if PY_MAJOR_VERSION > 2
+	{
+	    PyObject* col_ascii = PyObject_CallMethod(col, "encode",
+						      "s", "ascii");
+	    if (!col_ascii) {
+		Py_DECREF(col);
+		Py_DECREF(coliter);
+		return -1;
+	    }
+	    Py_DECREF(col);
+	    col = col_ascii;
+	}
+	#endif
+        Bytes_AsStringAndSize(col, &colname, &collen);
         if (offset + collen > DEFAULT_COPYBUFF - 2) {
             Py_DECREF(col);
             Py_DECREF(coliter);
@@ -1355,9 +1470,15 @@
     self->copysize = bufsize;
     self->copyfile = file;
 
-    /* At this point, the SQL statement must be str, not unicode */
-    if (pq_execute(self, PyString_AS_STRING(sql), 0) != 1) { goto fail; }
+    if (PyUnicode_Check(sql)) {
+	PyObject *sql_ascii = PyObject_CallMethod(sql, "encode", "s", "ascii");
+	if (!sql_ascii) goto fail;
+	Py_DECREF(sql);
+	sql = sql_ascii;
+    }
 
+    if (pq_execute(self, Bytes_AS_STRING(sql), 0) != 1) { goto fail; }
+
     res = Py_None;
     Py_INCREF(res);
     goto cleanup;
@@ -1530,29 +1651,29 @@
 
 static struct PyMemberDef cursorObject_members[] = {
     /* DBAPI-2.0 basics */
-    {"rowcount", T_LONG, OFFSETOF(rowcount), RO,
+    {"rowcount", T_LONG, OFFSETOF(rowcount), READONLY,
         "Number of rows read from the backend in the last command."},
     {"arraysize", T_LONG, OFFSETOF(arraysize), 0,
         "Number of records `fetchmany()` must fetch if not explicitely " \
         "specified."},
-    {"description", T_OBJECT, OFFSETOF(description), RO,
+    {"description", T_OBJECT, OFFSETOF(description), READONLY,
         "Cursor description as defined in DBAPI-2.0."},
-    {"lastrowid", T_LONG, OFFSETOF(lastoid), RO,
+    {"lastrowid", T_LONG, OFFSETOF(lastoid), READONLY,
         "The ``oid`` of the last row inserted by the cursor."},
     /* DBAPI-2.0 extensions */
-    {"rownumber", T_LONG, OFFSETOF(row), RO,
+    {"rownumber", T_LONG, OFFSETOF(row), READONLY,
         "The current row position."},
-    {"connection", T_OBJECT, OFFSETOF(conn), RO,
+    {"connection", T_OBJECT, OFFSETOF(conn), READONLY,
         "The connection where the cursor comes from."},
 #ifdef PSYCOPG_EXTENSIONS
-    {"name", T_STRING, OFFSETOF(name), RO},
-    {"statusmessage", T_OBJECT, OFFSETOF(pgstatus), RO,
+    {"name", T_STRING, OFFSETOF(name), READONLY},
+    {"statusmessage", T_OBJECT, OFFSETOF(pgstatus), READONLY,
         "The return message of the last command."},
-    {"query", T_OBJECT, OFFSETOF(query), RO,
+    {"query", T_OBJECT, OFFSETOF(query), READONLY,
         "The last query text sent to the backend."},
     {"row_factory", T_OBJECT, OFFSETOF(tuple_factory), 0},
     {"tzinfo_factory", T_OBJECT, OFFSETOF(tzinfo_factory), 0},
-    {"typecaster", T_OBJECT, OFFSETOF(caster), RO},
+    {"typecaster", T_OBJECT, OFFSETOF(caster), READONLY},
     {"string_types", T_OBJECT, OFFSETOF(string_types), 0},
     {"binary_types", T_OBJECT, OFFSETOF(binary_types), 0},
 #endif
@@ -1690,9 +1811,11 @@
 #define cursorType_doc \
 "A database cursor."
 
+#if PY_MAJOR_VERSION > 2
+#define Py_TPFLAGS_HAVE_ITER 0
+#endif
 PyTypeObject cursorType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.cursor",
     sizeof(cursorObject),
     0,
Index: psycopg/adapter_binary.c
===================================================================
--- psycopg/adapter_binary.c	(Revision 956)
+++ psycopg/adapter_binary.c	(Arbeitskopie)
@@ -22,7 +22,9 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <structmember.h>
+#if PY_MAJOR_VERSION < 3
 #include <stringobject.h>
+#endif
 
 #include <libpq-fe.h>
 #include <string.h>
@@ -139,7 +141,13 @@
     size_t len = 0;
 
     /* if we got a plain string or a buffer we escape it and save the buffer */
-    if (PyString_Check(self->wrapped) || PyBuffer_Check(self->wrapped)) {
+    if (Bytes_Check(self->wrapped) 
+	#if PY_MAJOR_VERSION < 3
+	|| PyBuffer_Check(self->wrapped)
+	#else
+	|| PyMemoryView_Check(self->wrapped)
+	#endif
+	) {
         /* escape and build quoted buffer */
         if (PyObject_AsReadBuffer(self->wrapped, (const void **)&buffer,
                                   &buffer_len) < 0)
@@ -157,7 +165,7 @@
                 (self->conn && ((connectionObject*)self->conn)->equote)
                     ? "E'%s'" : "'%s'" , to);
         else
-            self->buffer = PyString_FromString("''");
+            self->buffer = Text_FromUTF8("''");
 
         PQfreemem(to);
     }
@@ -229,8 +237,8 @@
 /* object member list */
 
 static struct PyMemberDef binaryObject_members[] = {
-    {"adapted", T_OBJECT, offsetof(binaryObject, wrapped), RO},
-    {"buffer", T_OBJECT, offsetof(binaryObject, buffer), RO},
+    {"adapted", T_OBJECT, offsetof(binaryObject, wrapped), READONLY},
+    {"buffer", T_OBJECT, offsetof(binaryObject, buffer), READONLY},
     {NULL}
 };
 
@@ -318,8 +326,7 @@
 "Binary(buffer) -> new binary object"
 
 PyTypeObject binaryType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.Binary",
     sizeof(binaryObject),
     0,
Index: psycopg/python.h
===================================================================
--- psycopg/python.h	(Revision 956)
+++ psycopg/python.h	(Arbeitskopie)
@@ -41,4 +41,48 @@
 #define freefunc destructor
 #endif
 
+/* Macros defined in Python 2.6 */
+#ifndef Py_REFCNT
+#define Py_REFCNT(ob)           (((PyObject*)(ob))->ob_refcnt)
+#define Py_TYPE(ob)             (((PyObject*)(ob))->ob_type)
+#define Py_SIZE(ob)             (((PyVarObject*)(ob))->ob_size)
+#define PyVarObject_HEAD_INIT(x,n) PyObject_HEAD_INIT(x) n,
+#endif
+
+/* Abstract from text type. Only supported for ASCII and UTF-8 */
+#if PY_MAJOR_VERSION < 3
+#define Text_Check(s) PyString_Check(s)
+#define Text_FromUTF8(s) PyString_FromString(s)
+#define Text_FromUTF8AndSize(s,n) PyString_FromStringAndSize(s,n)
+#else
+#define Text_Check(s) PyUnicode_Check(s)
+#define Text_FromUTF8(s) PyUnicode_FromString(s)
+#define Text_FromUTF8AndSize(s,n) PyUnicode_FromStringAndSize(s,n)
+#endif
+
+#if PY_MAJOR_VERSION > 2
+#define PyInt_FromLong         PyLong_FromLong
+#define PyString_FromFormat    PyUnicode_FromFormat
+#endif
+
+#if PY_MAJOR_VERSION < 3
+#define BytesType PyString_Type
+#define Bytes_Check PyString_Check
+#define Bytes_AS_STRING PyString_AS_STRING
+#define Bytes_GET_SIZE PyString_GET_SIZE
+#define Bytes_Size PyString_Size
+#define Bytes_AsString PyString_AsString
+#define Bytes_AsStringAndSize PyString_AsStringAndSize
+#define Bytes_FromStringAndSize PyString_FromStringAndSize
+#else
+#define BytesType PyBytes_Type
+#define Bytes_Check PyBytes_Check
+#define Bytes_AS_STRING PyBytes_AS_STRING
+#define Bytes_GET_SIZE PyBytes_GET_SIZE
+#define Bytes_Size PyBytes_Size
+#define Bytes_AsString PyBytes_AsString
+#define Bytes_AsStringAndSize PyBytes_AsStringAndSize
+#define Bytes_FromStringAndSize PyBytes_FromStringAndSize
+#endif
+
 #endif /* !defined(PSYCOPG_PYTHON_H) */
Index: psycopg/psycopg.h
===================================================================
--- psycopg/psycopg.h	(Revision 956)
+++ psycopg/psycopg.h	(Arbeitskopie)
@@ -47,7 +47,7 @@
 /* FORMAT_CODE_PY_SSIZE_T is for Py_ssize_t: */
 #define FORMAT_CODE_PY_SSIZE_T "%" PY_FORMAT_SIZE_T "d"
 
-#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 5
+#if (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION >= 5) || (PY_MAJOR_VERSION > 2)
   #define CONV_CODE_PY_SSIZE_T "n"
 #else
   #define CONV_CODE_PY_SSIZE_T "i"
Index: psycopg/pqpath.c
===================================================================
--- psycopg/pqpath.c	(Revision 956)
+++ psycopg/pqpath.c	(Arbeitskopie)
@@ -527,7 +527,8 @@
         Py_BLOCK_THREADS;
         notify = PyTuple_New(2);
         PyTuple_SET_ITEM(notify, 0, PyInt_FromLong((long)pgn->be_pid));
-        PyTuple_SET_ITEM(notify, 1, PyString_FromString(pgn->relname));
+	/* XXX guaranteed to be ASCII or UTF-8? */
+        PyTuple_SET_ITEM(notify, 1, Text_FromUTF8(pgn->relname));
         PyList_Append(conn->notifies, notify);
         Py_UNBLOCK_THREADS;
         free(pgn);
@@ -742,7 +743,8 @@
 
         /* 1/ fill the other fields */
         PyTuple_SET_ITEM(dtitem, 0,
-                         PyString_FromString(PQfname(curs->pgres, i)));
+			 /* XXX guaranteed to be ASCII/UTF8? */
+                         Text_FromUTF8(PQfname(curs->pgres, i)));
         PyTuple_SET_ITEM(dtitem, 1, type);
 
         /* 2/ display size is the maximum size of this field result tuples. */
@@ -813,14 +815,14 @@
         o = PyObject_CallMethod(curs->copyfile, "read",
             CONV_CODE_PY_SSIZE_T, curs->copysize
           );
-        if (!o || !PyString_Check(o) || (length = PyString_Size(o)) == -1) {
+        if (!o || !Bytes_Check(o) || (length = Bytes_Size(o)) == -1) {
             error = 1;
         }
         if (length == 0 || length > INT_MAX || error == 1) break;
 
         Py_BEGIN_ALLOW_THREADS;
         if (PQputCopyData(curs->conn->pgconn,
-                          PyString_AS_STRING(o),
+                          Bytes_AS_STRING(o),
                           /* Py_ssize_t->int cast was validated above: */
                           (int) length
                          ) == -1) {
@@ -867,8 +869,14 @@
     while (1) {
         o = PyObject_CallMethod(curs->copyfile, "readline", NULL);
         if (o == NULL) return -1;
-        if (o == Py_None || PyString_GET_SIZE(o) == 0) break;
-        if (PQputline(curs->conn->pgconn, PyString_AS_STRING(o)) != 0) {
+	if (Py_TYPE(o) != &BytesType) {
+	    PyErr_Format(PyExc_TypeError, "readline returned %.200s, not %.200s",
+			 Py_TYPE(o)->tp_name, BytesType.tp_name);
+	    Py_DECREF(o);
+	    return -1;
+	}
+        if (o == Py_None || Bytes_GET_SIZE(o) == 0) break;
+        if (PQputline(curs->conn->pgconn, Bytes_AS_STRING(o)) != 0) {
             Py_DECREF(o);
             return -1;
         }
@@ -1061,7 +1069,8 @@
 
     /* backend status message */
     Py_XDECREF(curs->pgstatus);
-    curs->pgstatus = PyString_FromString(PQcmdStatus(curs->pgres));
+    /* XXX guaranteed to be ASCII/UTF8? */
+    curs->pgstatus = Text_FromUTF8(PQcmdStatus(curs->pgres));
 
     switch(pgstatus) {
 
Index: psycopg/adapter_pboolean.c
===================================================================
--- psycopg/adapter_pboolean.c	(Revision 956)
+++ psycopg/adapter_pboolean.c	(Arbeitskopie)
@@ -22,7 +22,9 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <structmember.h>
+#if PY_MAJOR_VERSION < 3
 #include <stringobject.h>
+#endif
 #include <string.h>
 
 #define PSYCOPG_MODULE
@@ -40,17 +42,17 @@
 {
 #ifdef PSYCOPG_NEW_BOOLEAN
     if (PyObject_IsTrue(self->wrapped)) {
-        return PyString_FromString("true");
+        return Text_FromUTF8("true");
     }
     else {
-        return PyString_FromString("false");
+        return Text_FromUTF8("false");
     }
 #else
     if (PyObject_IsTrue(self->wrapped)) {
-        return PyString_FromString("'t'");
+        return Text_FromUTF8("'t'");
     }
     else {
-        return PyString_FromString("'f'");
+        return Text_FromUTF8("'f'");
     }
 #endif
 }
@@ -83,7 +85,7 @@
 /* object member list */
 
 static struct PyMemberDef pbooleanObject_members[] = {
-    {"adapted", T_OBJECT, offsetof(pbooleanObject, wrapped), RO},
+    {"adapted", T_OBJECT, offsetof(pbooleanObject, wrapped), READONLY},
     {NULL}
 };
 
@@ -168,8 +170,7 @@
 "Boolean(str) -> new Boolean adapter object"
 
 PyTypeObject pbooleanType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.Boolean",
     sizeof(pbooleanObject),
     0,
Index: psycopg/connection_int.c
===================================================================
--- psycopg/connection_int.c	(Revision 956)
+++ psycopg/connection_int.c	(Arbeitskopie)
@@ -20,7 +20,7 @@
  */
 
 #define PY_SSIZE_T_CLEAN
-#include <Python.h>
+#include <psycopg/python.h>
 #include <string.h>
 
 #define PSYCOPG_MODULE
@@ -46,7 +46,8 @@
     if (self->protocol < 3 && strncmp(message, "ERROR", 5) == 0)
         pq_set_critical(self, message);
     else {
-        PyObject *msg = PyString_FromString(message);
+	/* XXX is this guaranteed to be ASCII/UTF-8? */
+        PyObject *msg = Text_FromUTF8(message);
 
         PyList_Append(self->notice_list, msg);
         Py_DECREF(msg);
Index: psycopg/adapter_list.c
===================================================================
--- psycopg/adapter_list.c	(Revision 956)
+++ psycopg/adapter_list.c	(Arbeitskopie)
@@ -22,7 +22,9 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <structmember.h>
+#if PY_MAJOR_VERSION < 3
 #include <stringobject.h>
+#endif
 
 #define PSYCOPG_MODULE
 #include "psycopg/config.h"
@@ -47,7 +49,7 @@
 
     /* empty arrays are converted to NULLs (still searching for a way to
        insert an empty array in postgresql */
-    if (len == 0) return PyString_FromString("'{}'");
+    if (len == 0) return Text_FromUTF8("'{}'");
 
     tmp = PyTuple_New(len);
 
@@ -55,7 +57,7 @@
         PyObject *quoted;
     PyObject *wrapped = PyList_GET_ITEM(self->wrapped, i);
     if (wrapped == Py_None)
-        quoted = PyString_FromString("NULL");
+        quoted = Text_FromUTF8("NULL");
     else
         quoted = microprotocol_getquoted(wrapped,
                                    (connectionObject*)self->connection);
@@ -69,11 +71,15 @@
 
     /* now that we have a tuple of adapted objects we just need to join them
        and put "ARRAY[] around the result */
-    str = PyString_FromString(", ");
+    str = Text_FromUTF8(", ");
     joined = PyObject_CallMethod(str, "join", "(O)", tmp);
     if (joined == NULL) goto error;
-
+    
+    #if PY_MAJOR_VERSION < 3
     res = PyString_FromFormat("ARRAY[%s]", PyString_AsString(joined));
+    #else
+    res = PyUnicode_FromFormat("ARRAY[%U]", joined);
+    #endif
 
  error:
     Py_XDECREF(tmp);
@@ -137,7 +143,7 @@
 /* object member list */
 
 static struct PyMemberDef listObject_members[] = {
-    {"adapted", T_OBJECT, offsetof(listObject, wrapped), RO},
+    {"adapted", T_OBJECT, offsetof(listObject, wrapped), READONLY},
     {NULL}
 };
 
@@ -230,8 +236,7 @@
 "List(list) -> new list wrapper object"
 
 PyTypeObject listType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.List",
     sizeof(listObject),
     0,
Index: psycopg/adapter_qstring.c
===================================================================
--- psycopg/adapter_qstring.c	(Revision 956)
+++ psycopg/adapter_qstring.c	(Arbeitskopie)
@@ -22,7 +22,9 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <structmember.h>
+#if PY_MAJOR_VERSION < 3
 #include <stringobject.h>
+#endif
 
 #include <libpq-fe.h>
 #include <string.h>
@@ -110,10 +112,14 @@
         /* note that enc is a borrowed reference */
 
         if (enc) {
+	    #if PY_MAJOR_VERSION < 3
             const char *s = PyString_AsString(enc);
             Dprintf("qstring_quote: encoding unicode object to %s", s);
             str = PyUnicode_AsEncodedString(self->wrapped, s, NULL);
             Dprintf("qstring_quote: got encoded object at %p", str);
+	    #else
+	    str = PyObject_CallMethod(self->wrapped, "encode", "O", enc);
+	    #endif
             if (str == NULL) return NULL;
         }
         else {
@@ -124,6 +130,7 @@
         }
     }
 
+#if PY_MAJOR_VERSION < 3
     /* if the wrapped object is a simple string, we don't know how to
        (re)encode it, so we pass it as-is */
     else if (PyString_Check(self->wrapped)) {
@@ -131,6 +138,7 @@
         /* INCREF to make it ref-wise identical to unicode one */
         Py_INCREF(str);
     }
+#endif
 
     /* if the wrapped object is not a string, this is an error */
     else {
@@ -140,7 +148,7 @@
     }
 
     /* encode the string into buffer */
-    PyString_AsStringAndSize(str, &s, &len);
+    Bytes_AsStringAndSize(str, &s, &len);
 
     buffer = (char *)PyMem_Malloc((len*2+4) * sizeof(char));
     if (buffer == NULL) {
@@ -174,7 +182,8 @@
         buffer[equote] = '\'' ; buffer[len+equote+1] = '\'';
     }
 
-    self->buffer = PyString_FromStringAndSize(buffer, len+equote+2);
+    /* XXX need to decode in connection's encoding in 3.0 */
+    self->buffer = Text_FromUTF8AndSize(buffer, len+equote+2);
     PyMem_Free(buffer);
     Py_DECREF(str);
 
@@ -247,9 +256,9 @@
 /* object member list */
 
 static struct PyMemberDef qstringObject_members[] = {
-    {"adapted", T_OBJECT, offsetof(qstringObject, wrapped), RO},
-    {"buffer", T_OBJECT, offsetof(qstringObject, buffer), RO},
-    {"encoding", T_STRING, offsetof(qstringObject, encoding), RO},
+    {"adapted", T_OBJECT, offsetof(qstringObject, wrapped), READONLY},
+    {"buffer", T_OBJECT, offsetof(qstringObject, buffer), READONLY},
+    {"encoding", T_STRING, offsetof(qstringObject, encoding), READONLY},
     {NULL}
 };
 
@@ -346,8 +355,7 @@
 "QuotedString(str, enc) -> new quoted object with 'enc' encoding"
 
 PyTypeObject qstringType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.QuotedString",
     sizeof(qstringObject),
     0,
Index: psycopg/psycopgmodule.c
===================================================================
--- psycopg/psycopgmodule.c	(Revision 956)
+++ psycopg/psycopgmodule.c	(Arbeitskopie)
@@ -124,6 +124,7 @@
         return NULL;
     }
 
+#if PY_MAJOR_VERSION < 3
     if (pyport && PyString_Check(pyport)) {
       PyObject *pyint = PyInt_FromString(PyString_AsString(pyport), NULL, 10);
       if (!pyint) goto fail;
@@ -135,6 +136,22 @@
     else if (pyport && PyInt_Check(pyport)) {
       iport = PyInt_AsLong(pyport);
     }
+#else
+    if (pyport && PyUnicode_Check(pyport)) {
+	PyObject *pyint = PyObject_CallFunction((PyObject*)&PyLong_Type, 
+						"Oi", pyport, 10);
+      if (!pyint) goto fail;
+      iport = PyLong_AsLong(pyint);
+      Py_DECREF(pyint);
+      if (iport == -1 && PyErr_Occurred())
+	  goto fail;
+    }
+    else if (pyport && PyLong_Check(pyport)) {
+      iport = PyLong_AsLong(pyport);
+      if (iport == -1 && PyErr_Occurred())
+	  goto fail;
+    }
+#endif
     else if (pyport != NULL) {
       PyErr_SetString(PyExc_TypeError, "port must be a string or int");
       goto fail;
@@ -244,10 +261,10 @@
     }
 
     if (obj != NULL) {
-        if (obj->ob_type == &cursorType) {
+	if (Py_TYPE(obj) == &cursorType) {
             _psyco_register_type_set(&(((cursorObject*)obj)->string_types), type);
         }
-        else if (obj->ob_type == &connectionType) {
+        else if (Py_TYPE(obj) == &connectionType) {
             typecast_add(type, ((connectionObject*)obj)->string_types, 0);
         }
         else {
@@ -273,12 +290,22 @@
     PyObject *call;
 
     microprotocols_add(&PyFloat_Type, NULL, (PyObject*)&asisType);
+#if PY_MAJOR_VERSION < 3
     microprotocols_add(&PyInt_Type, NULL, (PyObject*)&asisType);
+#endif
     microprotocols_add(&PyLong_Type, NULL, (PyObject*)&asisType);
 
+#if PY_MAJOR_VERSION < 3
     microprotocols_add(&PyString_Type, NULL, (PyObject*)&qstringType);
+#endif
     microprotocols_add(&PyUnicode_Type, NULL, (PyObject*)&qstringType);
+#if PY_MAJOR_VERSION < 3
     microprotocols_add(&PyBuffer_Type, NULL, (PyObject*)&binaryType);
+#else
+    microprotocols_add(&PyBytes_Type, NULL, (PyObject*)&binaryType);
+    microprotocols_add(&PyByteArray_Type, NULL, (PyObject*)&binaryType);
+    microprotocols_add(&PyMemoryView_Type, NULL, (PyObject*)&binaryType);
+#endif
     microprotocols_add(&PyList_Type, NULL, (PyObject*)&listType);
 
 #ifdef HAVE_MXDATETIME
@@ -393,7 +420,7 @@
     encodingPair *enc;
 
     for (enc = encodings; enc->pgenc != NULL; enc++) {
-        PyObject *value = PyString_FromString(enc->pyenc);
+        PyObject *value = Text_FromUTF8(enc->pyenc);
         PyDict_SetItemString(dict, enc->pgenc, value);
         Py_DECREF(value);
     }
@@ -458,12 +485,18 @@
         dict = PyDict_New();
 
         if (exctable[i].docstr) {
-            str = PyString_FromString(exctable[i].docstr);
+            str = Text_FromUTF8(exctable[i].docstr);
             PyDict_SetItemString(dict, "__doc__", str);
         }
 
-        if (exctable[i].base == 0)
+        if (exctable[i].base == 0) {
+	    #if PY_MAJOR_VERSION < 3
             base = PyExc_StandardError;
+	    #else
+	    /* StandardError is gone in 3.0 */
+	    base = NULL;
+	    #endif
+	}
         else
             base = *exctable[i].base;
 
@@ -532,13 +565,16 @@
 
     if (err) {
         if (pgerror) {
-            t = PyString_FromString(pgerror);
+	    /* XXX is this always ASCII? If not, it needs
+	       to be decoded properly for Python 3. */
+            t = Text_FromUTF8(pgerror);
             PyObject_SetAttrString(err, "pgerror", t);
             Py_DECREF(t);
         }
 
         if (pgcode) {
-            t = PyString_FromString(pgcode);
+	    /* XXX likewise */
+            t = Text_FromUTF8(pgcode);
             PyObject_SetAttrString(err, "pgcode", t);
             Py_DECREF(t);
         }
@@ -683,8 +719,22 @@
     {NULL, NULL, 0, NULL}        /* Sentinel */
 };
 
-PyMODINIT_FUNC
-init_psycopg(void)
+#if PY_MAJOR_VERSION > 2
+static struct PyModuleDef psycopgmodule = {
+	PyModuleDef_HEAD_INIT,
+	"_psycopg",
+	NULL,
+	-1,
+	psycopgMethods,
+	NULL,
+	NULL,
+	NULL,
+	NULL
+};
+#endif
+
+static PyObject *
+_init(void)
 {
     static void *PSYCOPG_API[PSYCOPG_API_pointers];
 
@@ -699,39 +749,39 @@
     Dprintf("initpsycopg: initializing psycopg %s", PSYCOPG_VERSION);
 
     /* initialize all the new types and then the module */
-    connectionType.ob_type = &PyType_Type;
-    cursorType.ob_type     = &PyType_Type;
-    typecastType.ob_type   = &PyType_Type;
-    qstringType.ob_type    = &PyType_Type;
-    binaryType.ob_type     = &PyType_Type;
-    isqlquoteType.ob_type  = &PyType_Type;
-    asisType.ob_type       = &PyType_Type;
-    listType.ob_type       = &PyType_Type;
-    chunkType.ob_type      = &PyType_Type;
+    Py_TYPE(&connectionType) = &PyType_Type;
+    Py_TYPE(&cursorType)     = &PyType_Type;
+    Py_TYPE(&typecastType)   = &PyType_Type;
+    Py_TYPE(&qstringType)    = &PyType_Type;
+    Py_TYPE(&binaryType)     = &PyType_Type;
+    Py_TYPE(&isqlquoteType)  = &PyType_Type;
+    Py_TYPE(&asisType)       = &PyType_Type;
+    Py_TYPE(&listType)       = &PyType_Type;
+    Py_TYPE(&chunkType)      = &PyType_Type;
 
-    if (PyType_Ready(&connectionType) == -1) return;
-    if (PyType_Ready(&cursorType) == -1) return;
-    if (PyType_Ready(&typecastType) == -1) return;
-    if (PyType_Ready(&qstringType) == -1) return;
-    if (PyType_Ready(&binaryType) == -1) return;
-    if (PyType_Ready(&isqlquoteType) == -1) return;
-    if (PyType_Ready(&asisType) == -1) return;
-    if (PyType_Ready(&listType) == -1) return;
-    if (PyType_Ready(&chunkType) == -1) return;
+    if (PyType_Ready(&connectionType) == -1) return NULL;
+    if (PyType_Ready(&cursorType) == -1) return NULL;
+    if (PyType_Ready(&typecastType) == -1) return NULL;
+    if (PyType_Ready(&qstringType) == -1) return NULL;
+    if (PyType_Ready(&binaryType) == -1) return NULL;
+    if (PyType_Ready(&isqlquoteType) == -1) return NULL;
+    if (PyType_Ready(&asisType) == -1) return NULL;
+    if (PyType_Ready(&listType) == -1) return NULL;
+    if (PyType_Ready(&chunkType) == -1) return NULL;
 
 #ifdef HAVE_PYBOOL
-    pbooleanType.ob_type   = &PyType_Type;
-    if (PyType_Ready(&pbooleanType) == -1) return;
+    Py_TYPE(&pbooleanType)   = &PyType_Type;
+    if (PyType_Ready(&pbooleanType) == -1) return NULL;
 #endif
 
     /* import mx.DateTime module, if necessary */
 #ifdef HAVE_MXDATETIME
-    mxdatetimeType.ob_type = &PyType_Type;
-    if (PyType_Ready(&mxdatetimeType) == -1) return;
+    Py_TYPE(&mxdatetimeType) = &PyType_Type;
+    if (PyType_Ready(&mxdatetimeType) == -1) return NULL;
     if (mxDateTime_ImportModuleAndAPI() != 0) {
         Dprintf("initpsycopg: why marc hide mx.DateTime again?!");
         PyErr_SetString(PyExc_ImportError, "can't import mx.DateTime module");
-        return;
+        return NULL;
     }
     mxDateTimeP = &mxDateTime;
 #endif
@@ -742,10 +792,10 @@
     if (pyDateTimeModuleP == NULL) {
         Dprintf("initpsycopg: can't import datetime module");
         PyErr_SetString(PyExc_ImportError, "can't import datetime module");
-        return;
+        return NULL;
     }
-    pydatetimeType.ob_type = &PyType_Type;
-    if (PyType_Ready(&pydatetimeType) == -1) return;
+    Py_TYPE(&pydatetimeType) = &PyType_Type;
+    if (PyType_Ready(&pydatetimeType) == -1) return NULL;
 
     /* now we define the datetime types, this is crazy because python should
        be doing that, not us! */
@@ -760,7 +810,7 @@
     if (pyPsycopgTzModule == NULL) {
         Dprintf("initpsycopg: can't import psycopg2.tz module");
         PyErr_SetString(PyExc_ImportError, "can't import psycopg2.tz module");
-        return;
+        return NULL;
     }
     pyPsycopgTzLOCAL =
         PyObject_GetAttrString(pyPsycopgTzModule, "LOCAL");
@@ -768,7 +818,11 @@
         PyObject_GetAttrString(pyPsycopgTzModule, "FixedOffsetTimezone");
 
     /* initialize the module and grab module's dictionary */
+#if PY_MAJOR_VERSION < 3
     module = Py_InitModule("_psycopg", psycopgMethods);
+#else
+    module = PyModule_Create(&psycopgmodule);
+#endif
     dict = PyModule_GetDict(module);
 
     /* initialize all the module's exported functions */
@@ -786,9 +840,9 @@
     /* set some module's parameters */
     PyModule_AddStringConstant(module, "__version__", PSYCOPG_VERSION);
     PyModule_AddStringConstant(module, "__doc__", "psycopg PostgreSQL driver");
-    PyModule_AddObject(module, "apilevel", PyString_FromString(APILEVEL));
+    PyModule_AddObject(module, "apilevel", Text_FromUTF8(APILEVEL));
     PyModule_AddObject(module, "threadsafety", PyInt_FromLong(THREADSAFETY));
-    PyModule_AddObject(module, "paramstyle", PyString_FromString(PARAMSTYLE));
+    PyModule_AddObject(module, "paramstyle", Text_FromUTF8(PARAMSTYLE));
 
     /* put new types in module dictionary */
     PyModule_AddObject(module, "connection", (PyObject*)&connectionType);
@@ -829,4 +883,19 @@
 #endif
 
     Dprintf("initpsycopg: module initialization complete");
+    return module;
 }
+
+#if PY_MAJOR_VERSION < 3
+PyMODINIT_FUNC
+init_psycopg(void)
+{
+    _init();
+}
+#else
+PyMODINIT_FUNC
+PyInit__psycopg(void)
+{
+    return _init();
+}
+#endif
Index: psycopg/adapter_datetime.c
===================================================================
--- psycopg/adapter_datetime.c	(Revision 956)
+++ psycopg/adapter_datetime.c	(Arbeitskopie)
@@ -22,7 +22,9 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 #include <structmember.h>
+#if PY_MAJOR_VERSION < 3
 #include <stringobject.h>
+#endif
 #include <datetime.h>
 
 #include <time.h>
@@ -56,7 +58,11 @@
         PyObject *res = NULL;
         PyObject *iso = PyObject_CallMethod(self->wrapped, "isoformat", NULL);
         if (iso) {
+	    #if PY_MAJOR_VERSION < 3
             res = PyString_FromFormat("'%s'", PyString_AsString(iso));
+	    #else
+	    res = PyUnicode_FromFormat("'%U'", iso);
+	    #endif
             Py_DECREF(iso);
         }
         return res;
@@ -107,8 +113,8 @@
 /* object member list */
 
 static struct PyMemberDef pydatetimeObject_members[] = {
-    {"adapted", T_OBJECT, offsetof(pydatetimeObject, wrapped), RO},
-    {"type", T_INT, offsetof(pydatetimeObject, type), RO},
+    {"adapted", T_OBJECT, offsetof(pydatetimeObject, wrapped), READONLY},
+    {"type", T_INT, offsetof(pydatetimeObject, type), READONLY},
     {NULL}
 };
 
@@ -190,8 +196,7 @@
 "datetime(datetime, type) -> new datetime wrapper object"
 
 PyTypeObject pydatetimeType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.datetime",
     sizeof(pydatetimeObject),
     0,
Index: psycopg/typecast.c
===================================================================
--- psycopg/typecast.c	(Revision 956)
+++ psycopg/typecast.c	(Arbeitskopie)
@@ -300,7 +300,13 @@
     len = PyTuple_Size(type->values);
     for (i = 0; i < len; i++) {
         val = PyTuple_GetItem(type->values, i);
-        Dprintf("typecast_add:     adding val: %ld", PyInt_AsLong(val));
+        Dprintf("typecast_add:     adding val: %ld", 
+		#if PY_MAJOR_VERSION < 3
+		PyInt_AsLong(val)
+		#else
+		PyLong_AsLong(val)
+		#endif
+		);
         PyDict_SetItem(dict, val, obj);
     }
 
@@ -314,6 +320,10 @@
 
 #define OFFSETOF(x) offsetof(typecastObject, x)
 
+/* will undef after the function */
+#if PY_MAJOR_VERSION > 2
+#define PyInt_AsLong PyLong_AsLong
+#endif
 static int
 typecast_cmp(PyObject *obj1, PyObject* obj2)
 {
@@ -353,6 +363,7 @@
     Py_XDECREF(number);
     return res;
 }
+#undef PyInt_AsLong
 
 static PyObject*
 typecast_richcompare(PyObject *obj1, PyObject* obj2, int opid)
@@ -372,8 +383,8 @@
 }
 
 static struct PyMemberDef typecastObject_members[] = {
-    {"name", T_OBJECT, OFFSETOF(name), RO},
-    {"values", T_OBJECT, OFFSETOF(values), RO},
+    {"name", T_OBJECT, OFFSETOF(name), READONLY},
+    {"values", T_OBJECT, OFFSETOF(values), READONLY},
     {NULL}
 };
 
@@ -392,20 +403,26 @@
 static PyObject *
 typecast_call(PyObject *obj, PyObject *args, PyObject *kwargs)
 {
-    PyObject *string, *cursor;
+    char *string;
+    Py_ssize_t length;
+    PyObject *cursor;
 
-    if (!PyArg_ParseTuple(args, "OO", &string, &cursor)) {
+    /* Can pass either string or None for the string argument. */
+    /* XXX original code had "OO", and "relied" on setting an
+       PyString_AsString returning NULL, and an exception which
+       was ignored. */
+    if (!PyArg_ParseTuple(args, "z#O", &string, &length, &cursor)) {
         return NULL;
     }
 
-    return typecast_cast(obj,
-                         PyString_AsString(string), PyString_Size(string),
-                         cursor);
+    return typecast_cast(obj, string, length, cursor);
 }
 
+#if PY_MAJOR_VERSION > 2
+#define Py_TPFLAGS_HAVE_RICHCOMPARE 0
+#endif
 PyTypeObject typecastType = {
-    PyObject_HEAD_INIT(NULL)
-    0,
+    PyVarObject_HEAD_INIT(NULL, 0)
     "psycopg2._psycopg.type",
     sizeof(typecastObject),
     0,
@@ -512,7 +529,11 @@
 
     if (!PyArg_ParseTupleAndKeywords(args, keywds, "O!|O!OO", kwlist,
                                      &PyTuple_Type, &v,
+				     #if PY_MAJOR_VERSION < 3
                                      &PyString_Type, &name,
+				     #else
+				     &PyUnicode_Type, &name,
+				     #endif
                                      &cast, &base)) {
         return NULL;
     }
@@ -537,7 +558,7 @@
         }
     }
 
-    name = PyString_FromString(type->name);
+    name = Text_FromUTF8(type->name);
     if (!name) goto end;
 
     while (type->values[len] != 0) len++;
Index: psycopg/typecast_basic.c
===================================================================
--- psycopg/typecast_basic.c	(Revision 956)
+++ psycopg/typecast_basic.c	(Arbeitskopie)
@@ -31,7 +31,11 @@
         strncpy(buffer, s, (size_t) len); buffer[len] = '\0';
         s = buffer;
     }
+    #if PY_MAJOR_VERSION < 3
     return PyInt_FromString((char *)s, NULL, 0);
+    #else
+    return PyLong_FromString((char *)s, NULL, 0);
+    #endif
 }
 
 /** LONGINTEGER - cast long integers (8 bytes) to python long **/
@@ -55,22 +59,31 @@
 typecast_FLOAT_cast(const char *s, Py_ssize_t len, PyObject *curs)
 {
     PyObject *str = NULL, *flo = NULL;
-    char *pend;
 
     if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
+    #if PY_MAJOR_VERSION < 3
     str = PyString_FromStringAndSize(s, len);
-    flo = PyFloat_FromString(str, &pend);
+    flo = PyFloat_FromString(str, NULL);
+    #else
+    str = PyUnicode_FromStringAndSize(s, len);
+    flo = PyFloat_FromString(str);
+    #endif
     Py_DECREF(str);
     return flo;
 }
 
 /** STRING - cast strings of any type to python string **/
 
+static PyObject *typecast_UNICODE_cast(const char *, Py_ssize_t, PyObject *);
 static PyObject *
 typecast_STRING_cast(const char *s, Py_ssize_t len, PyObject *curs)
 {
+    #if PY_MAJOR_VERSION < 3
     if (s == NULL) {Py_INCREF(Py_None); return Py_None;}
     return PyString_FromStringAndSize(s, len);
+    #else
+    return typecast_UNICODE_cast(s, len, curs);
+    #endif
 }
 
 /** UNICODE - cast strings of any type to a python unicode object **/
@@ -85,7 +98,15 @@
     enc = PyDict_GetItemString(psycoEncodings,
                                ((cursorObject*)curs)->conn->encoding);
     if (enc) {
+	#if PY_MAJOR_VERSION < 3
         return PyUnicode_Decode(s, len, PyString_AsString(enc), NULL);
+	#else
+	/* In Python 3.0, there is no official way to get the defenc
+	   string. So as we need to create an object, anyway, we can
+	   just as well create a bytes object first. */
+	return PyObject_CallFunction((PyObject*)&PyUnicode_Type,
+				     "y#O", s, len, enc);
+	#endif
     }
     else {
        PyErr_Format(InterfaceError,
Index: setup.py
===================================================================
--- setup.py	(Revision 956)
+++ setup.py	(Arbeitskopie)
@@ -46,13 +46,32 @@
 import os
 import os.path
 import sys
-import popen2
-import ConfigParser
+try:
+    from popen2 import popen3
+except ImportError:
+    # 3.0: popen2 is gone
+    import subprocess
+    def popen3(command):
+        p = subprocess.Popen(command, shell = True,
+                             stdout = subprocess.PIPE,
+                             stdin = subprocess.PIPE,
+                             stderr = subprocess.PIPE)
+        # XXX this has a fourth result, just to hold onto p
+        return (p.stdout, p.stdin, p.stderr, p)
+                             
+try:
+    import ConfigParser
+except ImportError:
+    import configparser as ConfigParser # 3.0
 from distutils.core import setup, Extension
 from distutils.errors import DistutilsFileError
 from distutils.command.build_ext import build_ext
 from distutils.sysconfig import get_python_inc
 from distutils.ccompiler import get_default_compiler
+try:
+    from distutils.command.build_py import build_py_2to3 as build_py
+except ImportError:
+    from distutils.command.build_py import build_py
 
 PSYCOPG_VERSION = '2.0.7'
 version_flags   = []
@@ -66,10 +85,12 @@
     DistributionMetadata.download_url = None
 
 def get_pg_config(kind, pg_config="pg_config"):
-    p = popen2.popen3(pg_config + " --" + kind)
+    p = popen3(pg_config + " --" + kind)
     r = p[0].readline().strip()
     if not r:
         raise Warning(p[2].readline())
+    if not isinstance(r, str):
+        r = r.decode('ascii')
     return r
 
 class psycopg_build_ext(build_ext):
@@ -214,7 +235,9 @@
             define_macros.append(("PG_MAJOR_VERSION", pgmajor))
             define_macros.append(("PG_MINOR_VERSION", pgminor))
             define_macros.append(("PG_PATCH_VERSION", pgpatch))
-        except Warning, w:
+        except Warning:
+            # 2.x and 3.x have incompatible syntax, work-around
+            w = sys.exc_info()
             if self.pg_config == self.DEFAULT_PG_CONFIG:
                 sys.stderr.write("Warning: %s" % str(w))
             else:
@@ -314,7 +337,7 @@
 define_macros.append(('PY_MINOR_VERSION', str(sys.version_info[1])))
 
 # some macros related to python versions and features
-if sys.version_info[0] >= 2 and sys.version_info[1] >= 3:
+if sys.version_info >= (2,3):
     define_macros.append(('HAVE_PYBOOL','1'))
 
 # gather information to build the extension module
@@ -329,13 +352,27 @@
     'adapter_qstring.c', 'adapter_pboolean.c', 'adapter_binary.c',
     'adapter_asis.c', 'adapter_list.c']
 
+depends = [
+    # header files
+    'adapter_asis.h', 'adapter_list.h', 'adapter_qstring.h',
+    'cursor.h', 'pgtypes.h', 'psycopg.h', 'typecast.h',
+    'adapter_binary.h', 'adapter_mxdatetime.h', 'config.h',
+    'microprotocols.h', 'pgversion.h', 'python.h', 'adapter_datetime.h',
+    'adapter_pboolean.h', 'connection.h', 'microprotocols_proto.h',
+    'pqpath.h', 'typecast_binary.h',
+    # source files that are included
+    'typecast_array.c', 'typecast_basic.c', 'typecast_binary.c',
+    'typecast_builtins.c', 'typecast_datetime.c', 'typecast_mxdatetime.c'
+    ]
+
 parser = ConfigParser.ConfigParser()
 parser.read('setup.cfg')
 
 # Choose if to use Decimal type
 use_decimal = int(parser.get('build_ext', 'use_decimal'))
-if sys.version_info[0] >= 2 and (
-    sys.version_info[1] >= 4 or (sys.version_info[1] == 3 and use_decimal)):
+if sys.version_info[0] == 2 and (
+    sys.version_info[1] >= 4 or (sys.version_info[1] == 3 and use_decimal)) \
+    or sys.version_info[0] > 2:
     define_macros.append(('HAVE_DECIMAL','1'))
     version_flags.append('dec')
 
@@ -403,12 +440,15 @@
 
 # build the extension
 
-sources = map(lambda x: os.path.join('psycopg', x), sources)
+sources = list(map(lambda x: os.path.join('psycopg', x), sources))
+depends = list(map(lambda x: os.path.join('psycopg', x), depends))
 
 ext.append(Extension("psycopg2._psycopg", sources,
                      define_macros=define_macros,
                      include_dirs=include_dirs,
-                     undef_macros=[]))
+                     undef_macros=[],
+                     depends=depends,
+                     ))
 setup(name="psycopg2",
       version=PSYCOPG_VERSION,
       maintainer="Federico Di Gregorio",
@@ -425,6 +465,7 @@
       data_files=data_files,
       package_dir={'psycopg2':'lib'},
       packages=['psycopg2'],
-      cmdclass={ 'build_ext': psycopg_build_ext },
+      cmdclass={ 'build_ext': psycopg_build_ext,
+                 'build_py' : build_py},
       ext_modules=ext)
 
Index: tests/test_quote.py
===================================================================
--- tests/test_quote.py	(Revision 956)
+++ tests/test_quote.py	(Arbeitskopie)
@@ -4,7 +4,13 @@
 
 import psycopg2
 import psycopg2.extensions
-import tests
+import sys
+if sys.version_info < (3,):
+    import tests
+    from tests import list2bytes, str2bytes, asbytes
+else:
+    import py3tests as tests
+    from py3tests import list2bytes, str2bytes, asbytes
 
 class QuotingTestCase(unittest.TestCase):
     r"""Checks the correct quoting of strings and binary objects.
@@ -44,14 +50,14 @@
         self.assert_(not self.conn.notices)
 
     def test_binary(self):
-        data = """some data with \000\013 binary
+        data = str2bytes("""some data with \000\013 binary
         stuff into, 'quotes' and \\ a backslash too.
-        """
-        data += "".join(map(chr, range(256)))
+        """)
+        data += list2bytes(range(256))
 
         curs = self.conn.cursor()
         curs.execute("SELECT %s::bytea;", (psycopg2.Binary(data),))
-        res = str(curs.fetchone()[0])
+        res = asbytes(curs.fetchone()[0])
 
         self.assertEqual(res, data)
         self.assert_(not self.conn.notices)
Index: tests/test_connection.py
===================================================================
--- tests/test_connection.py	(Revision 956)
+++ tests/test_connection.py	(Arbeitskopie)
@@ -2,7 +2,11 @@
 import unittest
 
 import psycopg2
-import tests
+import sys
+if sys.version_info < (3,):
+    import tests
+else:
+    import py3tests as tests
 
 
 class ConnectionTests(unittest.TestCase):
Index: tests/__init__.py
===================================================================
--- tests/__init__.py	(Revision 956)
+++ tests/__init__.py	(Arbeitskopie)
@@ -1,4 +1,5 @@
 #!/usr/bin/env python
+import sys
 import os
 import unittest
 
@@ -16,6 +17,17 @@
 if dbuser is not None:
     dsn += ' user=%s' % dbuser
 
+if sys.version_info < (3,):
+    def list2bytes(l):
+        return ''.join(map(chr, l))
+    str2bytes = str
+    asbytes = str
+else:
+    list2bytes = bytes
+    def str2bytes(s):
+        return s.encode('ascii')
+    asbytes = bytes
+
 import bugX000
 import extras_dictcursor
 import test_dates
Index: tests/test_dates.py
===================================================================
--- tests/test_dates.py	(Revision 956)
+++ tests/test_dates.py	(Arbeitskopie)
@@ -3,8 +3,13 @@
 import unittest
 
 import psycopg2
-import tests
 
+# XXX if relative imports were available, we would say "from . import dsn"
+import sys
+if sys.version_info < (3,):
+    import tests
+else:
+    import py3tests as tests
 
 class CommonDatetimeTestsMixin:
 
@@ -142,6 +147,7 @@
                                         microseconds=123456)])
         seconds = math.floor(value)
         self.assertEqual(seconds, 3674096)
+        # XXX gives 123455
         self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
 
     def test_adapt_megative_timedelta(self):
@@ -151,6 +157,7 @@
                                         microseconds=123456)])
         seconds = math.floor(value)
         self.assertEqual(seconds, -3583504)
+        # XXX gives 123455
         self.assertEqual(int(round((value - seconds) * 1000000)), 123456)
 
 
Index: tests/test_transaction.py
===================================================================
--- tests/test_transaction.py	(Revision 956)
+++ tests/test_transaction.py	(Arbeitskopie)
@@ -5,7 +5,11 @@
 import psycopg2
 from psycopg2.extensions import (
     ISOLATION_LEVEL_SERIALIZABLE, STATUS_BEGIN, STATUS_READY)
-import tests
+import sys
+if sys.version_info < (3,):
+    import tests
+else:
+    import py3tests as tests
 
 
 class TransactionTests(unittest.TestCase):
Index: tests/types_basic.py
===================================================================
--- tests/types_basic.py	(Revision 956)
+++ tests/types_basic.py	(Arbeitskopie)
@@ -21,9 +21,14 @@
 import unittest
 
 import psycopg2
-import tests
+import sys
+if sys.version_info < (3,):
+    import tests
+    from tests import list2bytes, str2bytes, asbytes
+else:
+    import py3tests as tests
+    from py3tests import list2bytes, str2bytes, asbytes
 
-
 class TypesBasicTests(unittest.TestCase):
     """Test presence of mandatory attributes and methods."""
 
@@ -51,7 +56,7 @@
         s = self.execute("SELECT %s AS foo", (1971L,))
         self.failUnless(s == 1971L, "wrong integer quoting: " + str(s))
         # Python 2.4 defaults to Decimal?
-        if sys.version_info[0] >= 2 and sys.version_info[1] >= 4:
+        if sys.version_info >= (2,4):
             s = self.execute("SELECT %s AS foo", (19.10,))
             self.failUnless(s - decimal.Decimal("19.10") == 0,
                             "wrong decimal quoting: " + str(s))
@@ -61,23 +66,23 @@
                             "wrong float quoting: " + str(s))
 
     def testBinary(self):
-        s = ''.join([chr(x) for x in range(256)])
+        s = list2bytes(range(256))
         b = psycopg2.Binary(s)
         buf = self.execute("SELECT %s::bytea AS foo", (b,))
-        self.failUnless(str(buf) == s, "wrong binary quoting")
+        self.failUnless(asbytes(buf) == s, "wrong binary quoting")
 
     def testBinaryEmptyString(self):
         # test to make sure an empty Binary is converted to an empty string
-        b = psycopg2.Binary('')
+        b = psycopg2.Binary(str2bytes(''))
         self.assertEqual(str(b), "''")
 
     def testBinaryRoundTrip(self):
         # test to make sure buffers returned by psycopg2 are
         # understood by execute:
-        s = ''.join([chr(x) for x in range(256)])
+        s = list2bytes(range(256))
         buf = self.execute("SELECT %s::bytea AS foo", (psycopg2.Binary(s),))
         buf2 = self.execute("SELECT %s::bytea AS foo", (buf,))
-        self.failUnless(str(buf2) == s, "wrong binary quoting")
+        self.failUnless(asbytes(buf2) == s, "wrong binary quoting")
 
     def testArray(self):
         s = self.execute("SELECT %s AS foo", ([[1,2],[3,4]],))
Index: tests/test_psycopg2_dbapi20.py
===================================================================
--- tests/test_psycopg2_dbapi20.py	(Revision 956)
+++ tests/test_psycopg2_dbapi20.py	(Arbeitskopie)
@@ -2,9 +2,12 @@
 import dbapi20
 import unittest
 import psycopg2
-import popen2
 
-import tests
+import sys
+if sys.version_info < (3,):
+    import tests
+else:
+    import py3tests as tests
 
 class Psycopg2TestCase(dbapi20.DatabaseAPI20Test):
     driver = psycopg2
Index: tests/extras_dictcursor.py
===================================================================
--- tests/extras_dictcursor.py	(Revision 956)
+++ tests/extras_dictcursor.py	(Arbeitskopie)
@@ -17,9 +17,13 @@
 import psycopg2.extras
 import unittest
 
-import tests
+# XXX if relative imports were available, we would say "from . import dsn"
+import sys
+if sys.version_info < (3,):
+    import tests
+else:
+    import py3tests as tests
 
-
 class ExtrasDictCursorTests(unittest.TestCase):
     """Test if DictCursor extension class works."""
 
Index: lib/__init__.py
===================================================================
--- lib/__init__.py	(Revision 956)
+++ lib/__init__.py	(Arbeitskopie)
@@ -38,14 +38,14 @@
 # embedded Python or something even more devious.)
 
 import sys, warnings
-if sys.version_info[0] >= 2 and sys.version_info[1] >= 3:
+if sys.version_info >= (2, 3):
     try:
         import datetime as _psycopg_needs_datetime
     except:
         warnings.warn(
             "can't import datetime module probably needed by _psycopg",
             RuntimeWarning)
-if sys.version_info[0] >= 2 and sys.version_info[1] >= 4:
+if sys.version_info >= (2, 4):
     try:
         import decimal as _psycopg_needs_decimal
     except:
@@ -57,16 +57,16 @@
 
 # Import the DBAPI-2.0 stuff into top-level module.
 
-from _psycopg import BINARY, NUMBER, STRING, DATETIME, ROWID
+from psycopg2._psycopg import BINARY, NUMBER, STRING, DATETIME, ROWID
 
-from _psycopg import Binary, Date, Time, Timestamp
-from _psycopg import DateFromTicks, TimeFromTicks, TimestampFromTicks
+from psycopg2._psycopg import Binary, Date, Time, Timestamp
+from psycopg2._psycopg import DateFromTicks, TimeFromTicks, TimestampFromTicks
 
-from _psycopg import Error, Warning, DataError, DatabaseError, ProgrammingError
-from _psycopg import IntegrityError, InterfaceError, InternalError
-from _psycopg import NotSupportedError, OperationalError
+from psycopg2._psycopg import Error, Warning, DataError, DatabaseError, ProgrammingError
+from psycopg2._psycopg import IntegrityError, InterfaceError, InternalError
+from psycopg2._psycopg import NotSupportedError, OperationalError
 
-from _psycopg import connect, apilevel, threadsafety, paramstyle
-from _psycopg import __version__
+from psycopg2._psycopg import connect, apilevel, threadsafety, paramstyle
+from psycopg2._psycopg import __version__
 
 __all__ = [ k for k in locals().keys() if not k.startswith('_') ]
Index: lib/extensions.py
===================================================================
--- lib/extensions.py	(Revision 956)
+++ lib/extensions.py	(Arbeitskopie)
@@ -23,26 +23,26 @@
 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 # for more details.
 
-from _psycopg import UNICODE, INTEGER, LONGINTEGER, BOOLEAN, FLOAT
-from _psycopg import TIME, DATE, INTERVAL
+from psycopg2._psycopg import UNICODE, INTEGER, LONGINTEGER, BOOLEAN, FLOAT
+from psycopg2._psycopg import TIME, DATE, INTERVAL
 
-from _psycopg import Boolean, QuotedString, AsIs
+from psycopg2._psycopg import Boolean, QuotedString, AsIs
 try:
-    from _psycopg import DateFromMx, TimeFromMx, TimestampFromMx
-    from _psycopg import IntervalFromMx
+    from psycopg2._psycopg import DateFromMx, TimeFromMx, TimestampFromMx
+    from psycopg2._psycopg import IntervalFromMx
 except:
     pass
 try:
-    from _psycopg import DateFromPy, TimeFromPy, TimestampFromPy
-    from _psycopg import IntervalFromPy
+    from psycopg2._psycopg import DateFromPy, TimeFromPy, TimestampFromPy
+    from psycopg2._psycopg import IntervalFromPy
 except:
     pass
 
-from _psycopg import adapt, adapters, encodings, connection, cursor
-from _psycopg import string_types, binary_types, new_type, register_type
-from _psycopg import ISQLQuote
+from psycopg2._psycopg import adapt, adapters, encodings, connection, cursor
+from psycopg2._psycopg import string_types, binary_types, new_type, register_type
+from psycopg2._psycopg import ISQLQuote
 
-from _psycopg import QueryCanceledError, TransactionRollbackError
+from psycopg2._psycopg import QueryCanceledError, TransactionRollbackError
 
 """Isolation level values."""
 ISOLATION_LEVEL_AUTOCOMMIT     = 0
Index: lib/extras.py
===================================================================
--- lib/extras.py	(Revision 956)
+++ lib/extras.py	(Arbeitskopie)
@@ -73,7 +73,7 @@
         if name is None:
             return _connection.cursor(self, cursor_factory=DictCursor)
         else:
-	    return _connection.cursor(self, name, cursor_factory=DictCursor)
+            return _connection.cursor(self, name, cursor_factory=DictCursor)
 
 class DictCursor(DictCursorBase):
     """A cursor that keeps a list of column name -> index mappings."""
@@ -142,7 +142,7 @@
         if name is None:
             return _connection.cursor(self, cursor_factory=RealDictCursor)
         else:
-	    return _connection.cursor(self, name, cursor_factory=RealDictCursor)
+            return _connection.cursor(self, name, cursor_factory=RealDictCursor)
 
 class RealDictCursor(DictCursorBase):
     """A cursor that uses a real dict as the base type for rows.
@@ -223,10 +223,10 @@
             
     def cursor(self, name=None):
         self._check()
-	if name is None:
+        if name is None:
             return _connection.cursor(self, cursor_factory=LoggingCursor)
         else:
-	    return _connection.cursor(self, name, cursor_factory=LoggingCursor)
+            return _connection.cursor(self, name, cursor_factory=LoggingCursor)
 
 class LoggingCursor(_cursor):
     """A cursor that logs queries using its connection logging facilities."""
@@ -265,10 +265,10 @@
 
     def cursor(self, name=None):
         self._check()
-	if name is None:
+        if name is None:
             return _connection.cursor(self, cursor_factory=MinTimeLoggingCursor)
         else:
-	    return _connection.cursor(self, name, cursor_factory=MinTimeLoggingCursor)
+            return _connection.cursor(self, name, cursor_factory=MinTimeLoggingCursor)
     
 class MinTimeLoggingCursor(LoggingCursor):
     """The cursor sub-class companion to MinTimeLoggingConnection."""
Index: runtests.py
===================================================================
--- runtests.py	(Revision 956)
+++ runtests.py	(Arbeitskopie)
@@ -16,7 +16,24 @@
     sys.path.insert(0, platlib)
 
 import psycopg2
-import tests
+if sys.version_info < (3,):
+    import tests
+else:
+    from distutils.file_util import copy_file
+    import glob
+    from lib2to3.refactor import RefactoringTool, get_fixers_from_package
+    if not os.path.isdir("py3tests"):
+        os.mkdir("py3tests")
+    new = []
+    for f in glob.glob("tests/*.py"):
+        f, copied = copy_file(f, "py3tests", preserve_times=0, update=1)
+        if copied:
+            new.append(f)
+    fixers = get_fixers_from_package('lib2to3.fixes')
+    r = RefactoringTool(fixers)
+    r.refactor(new, write=True)
+    import py3tests as tests
+    
 
 def test_suite():
     return tests.test_suite()
