summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Gilbert <floppym@gentoo.org>2013-02-06 03:01:48 +0000
committerMike Gilbert <floppym@gentoo.org>2013-02-06 03:01:48 +0000
commitaec0ee4766fb5e3bc7d119b125dbf52d8c4933d4 (patch)
tree66a2f475c61e72ca4e0bb0fe34272941b8ce7df6 /dev-python/pycurl
parentFix recursive make errors by adding MAKEOPTS="-j1" (diff)
downloadgentoo-2-aec0ee4766fb5e3bc7d119b125dbf52d8c4933d4.tar.gz
gentoo-2-aec0ee4766fb5e3bc7d119b125dbf52d8c4933d4.tar.bz2
gentoo-2-aec0ee4766fb5e3bc7d119b125dbf52d8c4933d4.zip
Add support for Python 3.
(Portage version: 2.2.0_alpha161/cvs/Linux x86_64, signed Manifest commit with key 0BBEEA1FEA4843A4)
Diffstat (limited to 'dev-python/pycurl')
-rw-r--r--dev-python/pycurl/ChangeLog8
-rw-r--r--dev-python/pycurl/files/pycurl-7.19.0-python3.patch1254
-rw-r--r--dev-python/pycurl/pycurl-7.19.0-r3.ebuild58
3 files changed, 1319 insertions, 1 deletions
diff --git a/dev-python/pycurl/ChangeLog b/dev-python/pycurl/ChangeLog
index 38602f55bce9..cb0ce08fd5c1 100644
--- a/dev-python/pycurl/ChangeLog
+++ b/dev-python/pycurl/ChangeLog
@@ -1,6 +1,12 @@
# ChangeLog for dev-python/pycurl
# Copyright 1999-2013 Gentoo Foundation; Distributed under the GPL v2
-# $Header: /var/cvsroot/gentoo-x86/dev-python/pycurl/ChangeLog,v 1.79 2013/02/05 22:37:49 mgorny Exp $
+# $Header: /var/cvsroot/gentoo-x86/dev-python/pycurl/ChangeLog,v 1.80 2013/02/06 03:01:47 floppym Exp $
+
+*pycurl-7.19.0-r3 (06 Feb 2013)
+
+ 06 Feb 2013; Mike Gilbert <floppym@gentoo.org>
+ +files/pycurl-7.19.0-python3.patch, +pycurl-7.19.0-r3.ebuild:
+ Add support for Python 3.
*pycurl-7.19.0-r2 (05 Feb 2013)
diff --git a/dev-python/pycurl/files/pycurl-7.19.0-python3.patch b/dev-python/pycurl/files/pycurl-7.19.0-python3.patch
new file mode 100644
index 000000000000..102cbc75fd72
--- /dev/null
+++ b/dev-python/pycurl/files/pycurl-7.19.0-python3.patch
@@ -0,0 +1,1254 @@
+Add support for Python 3.
+Based on patch from ubuntu.
+Modifed to work with Python 2.5 by Mike Gilbert (floppym).
+
+Description: Add support for Python 3
+Origin: http://sourceforge.net/tracker/?func=detail&aid=3188495&group_id=28236&atid=392779
+Author: Markus Koetter
+Author: Michael Terry <michael.terry@canonical.com>
+
+diff --git a/examples/basicfirst.py b/examples/basicfirst.py
+index 4e49465..6b658fc 100644
+--- a/examples/basicfirst.py
++++ b/examples/basicfirst.py
+@@ -13,13 +13,17 @@ class Test:
+ def body_callback(self, buf):
+ self.contents = self.contents + buf
+
+-print >>sys.stderr, 'Testing', pycurl.version
++print('Testing', pycurl.version, file=sys.stderr)
+
+-t = Test()
+-c = pycurl.Curl()
+-c.setopt(c.URL, 'http://curl.haxx.se/dev/')
+-c.setopt(c.WRITEFUNCTION, t.body_callback)
+-c.perform()
+-c.close()
++try:
++ t = Test()
++ c = pycurl.Curl()
++ c.setopt(c.URL, sys.argv[1])
++ c.setopt(c.WRITEFUNCTION, t.body_callback)
++ c.perform()
++ c.close()
++# print(t)
++ print(t.contents)
++except Exception as e:
++ print(e)
+
+-print t.contents
+diff --git a/examples/retriever-multi.py b/examples/retriever-multi.py
+index 0b4b417..fbf7515 100644
+--- a/examples/retriever-multi.py
++++ b/examples/retriever-multi.py
+@@ -10,6 +10,7 @@
+
+ import sys
+ import pycurl
++import time
+
+ # We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
+ # the libcurl tutorial for more info.
+@@ -31,7 +32,7 @@ try:
+ if len(sys.argv) >= 3:
+ num_conn = int(sys.argv[2])
+ except:
+- print "Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0]
++ print("Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0])
+ raise SystemExit
+
+
+@@ -50,8 +51,8 @@ assert queue, "no URLs given"
+ num_urls = len(queue)
+ num_conn = min(num_conn, num_urls)
+ assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
+-print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
+-print "----- Getting", num_urls, "URLs using", num_conn, "connections -----"
++print("PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM))
++print("----- Getting", num_urls, "URLs using", num_conn, "connections -----")
+
+
+ # Pre-allocate a list of curl objects
+@@ -79,6 +80,9 @@ while num_processed < num_urls:
+ c.fp = open(filename, "wb")
+ c.setopt(pycurl.URL, url)
+ c.setopt(pycurl.WRITEDATA, c.fp)
++# print(c.fp)
++# c.fp.close()
++# c.fp = None
+ m.add_handle(c)
+ # store some info
+ c.filename = filename
+@@ -92,16 +96,17 @@ while num_processed < num_urls:
+ while 1:
+ num_q, ok_list, err_list = m.info_read()
+ for c in ok_list:
++ c.fp.flush()
+ c.fp.close()
+ c.fp = None
+ m.remove_handle(c)
+- print "Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL)
++ print("Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL))
+ freelist.append(c)
+ for c, errno, errmsg in err_list:
+ c.fp.close()
+ c.fp = None
+ m.remove_handle(c)
+- print "Failed: ", c.filename, c.url, errno, errmsg
++ print("Failed: ", c.filename, c.url, errno, errmsg)
+ freelist.append(c)
+ num_processed = num_processed + len(ok_list) + len(err_list)
+ if num_q == 0:
+@@ -120,3 +125,4 @@ for c in m.handles:
+ c.close()
+ m.close()
+
++#time.sleep(30)
+diff --git a/python/curl/__init__.py b/python/curl/__init__.py
+index b002618..22762c4 100644
+--- a/python/curl/__init__.py
++++ b/python/curl/__init__.py
+@@ -6,11 +6,11 @@
+ #
+ # By Eric S. Raymond, April 2003.
+
+-import os, sys, urllib, exceptions, mimetools, pycurl
++import os, sys, pycurl
+ try:
+- from cStringIO import StringIO
++ from urllib.parse import urlencode
+ except ImportError:
+- from StringIO import StringIO
++ from urllib import urlencode
+
+ try:
+ import signal
+@@ -63,7 +63,7 @@ class Curl:
+
+ def set_option(self, *args):
+ "Set an option on the retrieval."
+- apply(self.handle.setopt, args)
++ self.handle.setopt(*args)
+
+ def set_verbosity(self, level):
+ "Set verbosity to 1 to see transactions."
+@@ -83,14 +83,14 @@ class Curl:
+ def get(self, url="", params=None):
+ "Ship a GET request for a specified URL, capture the response."
+ if params:
+- url += "?" + urllib.urlencode(params)
++ url += "?" + urlencode(params)
+ self.set_option(pycurl.HTTPGET, 1)
+ return self.__request(url)
+
+ def post(self, cgi, params):
+ "Ship a POST request to a specified CGI, capture the response."
+ self.set_option(pycurl.POST, 1)
+- self.set_option(pycurl.POSTFIELDS, urllib.urlencode(params))
++ self.set_option(pycurl.POSTFIELDS, urlencode(params))
+ return self.__request(cgi)
+
+ def body(self):
+@@ -103,7 +103,7 @@ class Curl:
+
+ def get_info(self, *args):
+ "Get information about retrieval."
+- return apply(self.handle.getinfo, args)
++ return self.handle.getinfo(*args)
+
+ def info(self):
+ "Return a dictionary with all info on the last response."
+@@ -164,10 +164,10 @@ if __name__ == "__main__":
+ url = sys.argv[1]
+ c = Curl()
+ c.get(url)
+- print c.body()
+- print '='*74 + '\n'
++ print(c.body())
++ print('='*74 + '\n')
+ import pprint
+ pprint.pprint(c.info())
+- print c.get_info(pycurl.OS_ERRNO)
+- print c.info()['os-errno']
++ print(c.get_info(pycurl.OS_ERRNO))
++ print(c.info()['os-errno'])
+ c.close()
+diff --git a/setup.py b/setup.py
+index 172f280..1e6b21f 100644
+--- a/setup.py
++++ b/setup.py
+@@ -31,7 +31,7 @@ def scan_argv(s, default):
+ i = 1
+ while i < len(sys.argv):
+ arg = sys.argv[i]
+- if string.find(arg, s) == 0:
++ if str.find(arg, s) == 0:
+ p = arg[len(s):]
+ assert p, arg
+ del sys.argv[i]
+@@ -46,8 +46,8 @@ def add_libdirs(envvar, sep, fatal=0):
+ v = os.environ.get(envvar)
+ if not v:
+ return
+- for dir in string.split(v, sep):
+- dir = string.strip(dir)
++ for dir in str.split(v, sep):
++ dir = str.strip(dir)
+ if not dir:
+ continue
+ dir = os.path.normpath(dir)
+@@ -55,7 +55,7 @@ def add_libdirs(envvar, sep, fatal=0):
+ if not dir in library_dirs:
+ library_dirs.append(dir)
+ elif fatal:
+- print "FATAL: bad directory %s in environment variable %s" % (dir, envvar)
++ print("FATAL: bad directory %s in environment variable %s" % (dir, envvar))
+ sys.exit(1)
+
+
+@@ -65,13 +65,13 @@ if sys.platform == "win32":
+ # and thus unlikely to match your installation.
+ CURL_DIR = r"c:\src\build\pycurl\curl-7.16.2.1"
+ CURL_DIR = scan_argv("--curl-dir=", CURL_DIR)
+- print "Using curl directory:", CURL_DIR
++ print("Using curl directory:", CURL_DIR)
+ assert os.path.isdir(CURL_DIR), "please check CURL_DIR in setup.py"
+ include_dirs.append(os.path.join(CURL_DIR, "include"))
+ extra_objects.append(os.path.join(CURL_DIR, "lib", "libcurl.lib"))
+ extra_link_args.extend(["gdi32.lib", "wldap32.lib", "winmm.lib", "ws2_32.lib",])
+ add_libdirs("LIB", ";")
+- if string.find(sys.version, "MSC") >= 0:
++ if str.find(sys.version, "MSC") >= 0:
+ extra_compile_args.append("-O2")
+ extra_compile_args.append("-GF") # enable read-only string pooling
+ extra_compile_args.append("-WX") # treat warnings as errors
+@@ -85,10 +85,10 @@ else:
+ CURL_CONFIG = scan_argv("--curl-config=", CURL_CONFIG)
+ d = os.popen("'%s' --version" % CURL_CONFIG).read()
+ if d:
+- d = string.strip(d)
++ d = str.strip(d)
+ if not d:
+- raise Exception, ("`%s' not found -- please install the libcurl development files" % CURL_CONFIG)
+- print "Using %s (%s)" % (CURL_CONFIG, d)
++ raise Exception("`%s' not found -- please install the libcurl development files" % CURL_CONFIG)
++ print("Using %s (%s)" % (CURL_CONFIG, d))
+ for e in split_quoted(os.popen("'%s' --cflags" % CURL_CONFIG).read()):
+ if e[:2] == "-I":
+ # do not add /usr/include
+@@ -209,4 +209,4 @@ if __name__ == "__main__":
+ for o in ext.extra_objects:
+ assert os.path.isfile(o), o
+ # We can live with the deprecationwarning for a while
+- apply(setup, (), setup_args)
++ setup(*(), **setup_args)
+diff --git a/src/pycurl.c b/src/pycurl.c
+index 8b7245d..dc9a90c 100644
+--- a/src/pycurl.c
++++ b/src/pycurl.c
+@@ -97,6 +97,17 @@ static void pycurl_ssl_init(void);
+ static void pycurl_ssl_cleanup(void);
+ #endif
+
++#if PY_MAJOR_VERSION >= 3
++ #define PyInt_Type PyLong_Type
++ #define PyInt_Check(op) PyLong_Check(op)
++ #define PyInt_FromLong PyLong_FromLong
++ #define PyInt_AsLong PyLong_AsLong
++#endif
++
++#ifndef Py_TYPE
++ #define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
++#endif
++
+ /* Calculate the number of OBJECTPOINT options we need to store */
+ #define OPTIONS_SIZE ((int)CURLOPT_LASTENTRY % 10000)
+ #define MOPTIONS_SIZE ((int)CURLMOPT_LASTENTRY % 10000)
+@@ -161,6 +172,7 @@ typedef struct {
+ PyObject *opensocket_cb;
+ /* file objects */
+ PyObject *readdata_fp;
++ PyObject *writedata;
+ PyObject *writedata_fp;
+ PyObject *writeheader_fp;
+ /* misc */
+@@ -202,16 +214,50 @@ typedef struct {
+ # define PY_LONG_LONG LONG_LONG
+ #endif
+
++int PyUnicode_AsStringAndSize(PyObject *obj, char **buffer, Py_ssize_t *length)
++{
++ Py_ssize_t pysize = PyUnicode_GetSize(obj);
++ wchar_t * str = (wchar_t *) malloc((pysize + 1) * sizeof(wchar_t));
++#if PY_MAJOR_VERSION >= 3
++ PyUnicode_AsWideChar(obj, str, pysize);
++#else
++ PyUnicode_AsWideChar((PyUnicodeObject *) obj, str, pysize);
++#endif
++ str[pysize] = '\0';
++
++// measure size
++ size_t csize = wcstombs(0, str, 0);
++ if( csize == (size_t) -1 )
++ {
++ free(str);
++ return -1;
++ }
++
++ char *cstr = (char *) malloc(csize + 1);
++
++// convert
++ wcstombs(cstr, str, csize + 1);
++ *buffer = cstr;
++ if( length )
++ *length = csize;
++ free(str);
++ return 0;
++}
++
++
+ /* Like PyString_AsString(), but set an exception if the string contains
+ * embedded NULs. Actually PyString_AsStringAndSize() already does that for
+ * us if the `len' parameter is NULL - see Objects/stringobject.c.
+ */
+-
+ static char *PyString_AsString_NoNUL(PyObject *obj)
+ {
+ char *s = NULL;
+ Py_ssize_t r;
++#if PY_MAJOR_VERSION >= 3
++ r = PyUnicode_AsStringAndSize(obj, &s, NULL);
++#else
+ r = PyString_AsStringAndSize(obj, &s, NULL);
++#endif
+ if (r != 0)
+ return NULL; /* exception already set */
+ assert(s != NULL);
+@@ -236,7 +282,11 @@ static PyObject *convert_slist(struct curl_slist *slist, int free_flags)
+ if (slist->data == NULL) {
+ v = Py_None; Py_INCREF(v);
+ } else {
++#if PY_MAJOR_VERSION >= 3
++ v = PyUnicode_FromString(slist->data);
++#else
+ v = PyString_FromString(slist->data);
++#endif
+ }
+ if (v == NULL || PyList_Append(ret, v) != 0) {
+ Py_XDECREF(v);
+@@ -272,7 +322,7 @@ get_thread_state(const CurlObject *self)
+ */
+ if (self == NULL)
+ return NULL;
+- assert(self->ob_type == p_Curl_Type);
++ assert(Py_TYPE(self) == p_Curl_Type);
+ if (self->state != NULL)
+ {
+ /* inside perform() */
+@@ -302,7 +352,7 @@ get_thread_state_multi(const CurlMultiObject *self)
+ */
+ if (self == NULL)
+ return NULL;
+- assert(self->ob_type == p_CurlMulti_Type);
++ assert(Py_TYPE(self) == p_CurlMulti_Type);
+ if (self->state != NULL)
+ {
+ /* inside multi_perform() */
+@@ -318,7 +368,7 @@ static void
+ assert_share_state(const CurlShareObject *self)
+ {
+ assert(self != NULL);
+- assert(self->ob_type == p_CurlShare_Type);
++ assert(Py_TYPE(self) == p_CurlShare_Type);
+ assert(self->lock != NULL);
+ }
+
+@@ -328,7 +378,7 @@ static void
+ assert_curl_state(const CurlObject *self)
+ {
+ assert(self != NULL);
+- assert(self->ob_type == p_Curl_Type);
++ assert(Py_TYPE(self) == p_Curl_Type);
+ (void) get_thread_state(self);
+ }
+
+@@ -338,7 +388,7 @@ static void
+ assert_multi_state(const CurlMultiObject *self)
+ {
+ assert(self != NULL);
+- assert(self->ob_type == p_CurlMulti_Type);
++ assert(Py_TYPE(self) == p_CurlMulti_Type);
+ if (self->state != NULL) {
+ assert(self->multi_handle != NULL);
+ }
+@@ -676,7 +726,8 @@ do_curlshare_setopt(CurlShareObject *self, PyObject *args)
+
+ /* Handle the case of integer arguments */
+ if (PyInt_Check(obj)) {
+- long d = PyInt_AsLong(obj);
++ long d = PyLong_AsLong(obj);
++
+ if (d != CURL_LOCK_DATA_COOKIE && d != CURL_LOCK_DATA_DNS) {
+ goto error;
+ }
+@@ -750,6 +801,7 @@ util_curl_new(void)
+ return self;
+ }
+
++size_t default_write_callback(char *ptr, size_t size, size_t nmemb, void *stream);
+
+ /* constructor - this is a module-level function returning a new instance */
+ static CurlObject *
+@@ -809,11 +861,22 @@ do_curl_new(PyObject *dummy)
+ }
+ self->options[ OPT_INDEX(CURLOPT_USERAGENT) ] = s; s = NULL;
+
++#if PY_MAJOR_VERSION >= 3
++ res = curl_easy_setopt(self->handle, CURLOPT_WRITEFUNCTION, default_write_callback);
++ if (res != CURLE_OK) {
++ goto error;
++ }
++ res = curl_easy_setopt(self->handle, CURLOPT_WRITEDATA, self);
++ if (res != CURLE_OK) {
++ goto error;
++ }
++#endif
++
+ /* Success - return new object */
+ return self;
+
+ error:
+- Py_DECREF(self); /* this also closes self->handle */
++ Py_XDECREF(self); /* this also closes self->handle */
+ PyErr_SetString(ErrorObject, "initializing curl failed");
+ return NULL;
+ }
+@@ -880,7 +943,7 @@ util_curl_close(CurlObject *self)
+ /* Zero handle and thread-state to disallow any operations to be run
+ * from now on */
+ assert(self != NULL);
+- assert(self->ob_type == p_Curl_Type);
++ assert(Py_TYPE(self) == p_Curl_Type);
+ handle = self->handle;
+ self->handle = NULL;
+ if (handle == NULL) {
+@@ -965,7 +1028,12 @@ do_curl_errstr(CurlObject *self)
+ return NULL;
+ }
+ self->error[sizeof(self->error) - 1] = 0;
++
++#if PY_MAJOR_VERSION >= 3
++ return PyUnicode_FromString(self->error);
++#else
+ return PyString_FromString(self->error);
++#endif
+ }
+
+
+@@ -1125,6 +1193,52 @@ write_callback(char *ptr, size_t size, size_t nmemb, void *stream)
+ return util_write_callback(0, ptr, size, nmemb, stream);
+ }
+
++
++size_t
++default_write_callback(char *ptr, size_t size, size_t nmemb, void *stream)
++{
++ CurlObject *obj = (CurlObject *)stream;
++ PyThreadState *tmp_state;
++ CurlObject *self = (CurlObject *)stream;
++
++ /* acquire thread */
++ int ret = 0;
++ tmp_state = get_thread_state(self);
++ if (tmp_state == NULL)
++ return ret;
++ PyEval_AcquireThread(tmp_state);
++
++ if(obj->writedata_fp != NULL)
++ {
++ /**
++ * I'd prefer this code, but
++ * PyFile_WriteObject converts the object to str or repr, which are of type str
++ * and the write() fn expects bytes or buffer ...
++ */
++/*
++ PyObject *w = PyBytes_FromStringAndSize(ptr, size*nmemb);
++ printf("writedata_fp %p w %p s %i\n", obj->writedata_fp, w, PyBytes_GET_SIZE(w));
++ Py_INCREF(w);
++ if( PyFile_WriteObject(w, obj->writedata_fp, Py_PRINT_RAW) != 0 )
++ {
++ PyErr_Print();
++ ret = -1;
++ }
++
++ Py_DECREF(w);
++*/
++ int fd = PyObject_AsFileDescriptor(((CurlObject *)stream)->writedata_fp);
++ ret = write(fd, ptr, size*nmemb);
++ }else
++ {
++ fwrite(ptr, size, nmemb, stdout);
++ }
++
++ PyEval_ReleaseThread(tmp_state);
++ return ret;
++}
++
++
+ static size_t
+ header_callback(char *ptr, size_t size, size_t nmemb, void *stream)
+ {
+@@ -1166,6 +1280,7 @@ opensocket_callback(void *clientp, curlsocktype purpose,
+ ret = CURL_SOCKET_BAD;
+ goto verbose_error;
+ }
++
+ // normal operation:
+ if (PyInt_Check(fileno_result)) {
+ ret = dup(PyInt_AsLong(fileno_result));
+@@ -1227,11 +1342,19 @@ read_callback(char *ptr, size_t size, size_t nmemb, void *stream)
+ goto verbose_error;
+
+ /* handle result */
++#if PY_MAJOR_VERSION >= 3
++ if (PyBytes_Check(result)) {
++#else
+ if (PyString_Check(result)) {
++#endif
+ char *buf = NULL;
+ Py_ssize_t obj_size = -1;
+ Py_ssize_t r;
++#if PY_MAJOR_VERSION >= 3
++ r = PyBytes_AsStringAndSize(result, &buf, &obj_size);
++#else
+ r = PyString_AsStringAndSize(result, &buf, &obj_size);
++#endif
+ if (r != 0 || obj_size < 0 || obj_size > total_size) {
+ PyErr_Format(ErrorObject, "invalid return value for read callback %ld %ld", (long)obj_size, (long)total_size);
+ goto verbose_error;
+@@ -1404,6 +1527,7 @@ ioctl_callback(CURL *curlobj, int cmd, void *stream)
+ if (result == Py_None) {
+ ret = CURLIOE_OK; /* None means success */
+ }
++
+ else if (PyInt_Check(result)) {
+ ret = (int) PyInt_AsLong(result);
+ if (ret >= CURLIOE_LAST || ret < 0) {
+@@ -1587,7 +1711,11 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ #endif
+
+ /* Handle the case of string arguments */
++#if PY_MAJOR_VERSION >= 3
++ if (PyUnicode_Check(obj)) {
++#else
+ if (PyString_Check(obj)) {
++#endif
+ char *str = NULL;
+ Py_ssize_t len = -1;
+ char *buf;
+@@ -1636,8 +1764,13 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ return NULL;
+ break;
+ case CURLOPT_POSTFIELDS:
++#if PY_MAJOR_VERSION >= 3
++ if (PyUnicode_AsStringAndSize(obj, &str, &len) != 0)
++ return NULL;
++#else
+ if (PyString_AsStringAndSize(obj, &str, &len) != 0)
+ return NULL;
++#endif
+ /* automatically set POSTFIELDSIZE */
+ if (len <= INT_MAX) {
+ res = curl_easy_setopt(self->handle, CURLOPT_POSTFIELDSIZE, (long)len);
+@@ -1686,7 +1819,6 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ /* Handle the case of integer arguments */
+ if (PyInt_Check(obj)) {
+ long d = PyInt_AsLong(obj);
+-
+ if (IS_LONG_OPTION(option))
+ res = curl_easy_setopt(self->handle, (CURLoption)option, (long)d);
+ else if (IS_OFF_T_OPTION(option))
+@@ -1727,8 +1859,12 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ #undef IS_OFF_T_OPTION
+
+ /* Handle the case of file objects */
++#if PY_MAJOR_VERSION >= 3
++ extern PyTypeObject PyIOBase_Type;
++ if(PyObject_IsInstance(obj, (PyObject *)&PyIOBase_Type) == 1) {
++#else
+ if (PyFile_Check(obj)) {
+- FILE *fp;
++#endif
+
+ /* Ensure the option specified a file as well as the input */
+ switch (option) {
+@@ -1745,7 +1881,13 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ PyErr_SetString(PyExc_TypeError, "files are not supported for this option");
+ return NULL;
+ }
+-
++#if PY_MAJOR_VERSION >= 3
++// printf("WRITEDATA %p\n",obj);
++// int fd = PyObject_AsFileDescriptor(obj);
++// printf("fd is %i\n", fd);
++// fp = fdopen(fd, "w");
++#else
++ FILE *fp;
+ fp = PyFile_AsFile(obj);
+ if (fp == NULL) {
+ PyErr_SetString(PyExc_TypeError, "second argument must be open file");
+@@ -1755,6 +1897,7 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ if (res != CURLE_OK) {
+ CURLERROR_RETVAL();
+ }
++#endif
+ Py_INCREF(obj);
+
+ switch (option) {
+@@ -1844,14 +1987,27 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ PyErr_SetString(PyExc_TypeError, "tuple must contain two elements (name, value)");
+ return NULL;
+ }
++#if PY_MAJOR_VERSION >= 3
++ if (PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(listitem, 0), &nstr, &nlen) != 0) {
++#else
+ if (PyString_AsStringAndSize(PyTuple_GET_ITEM(listitem, 0), &nstr, &nlen) != 0) {
++#endif
+ curl_formfree(post);
+ PyErr_SetString(PyExc_TypeError, "tuple must contain string as first element");
+ return NULL;
+ }
++#if PY_MAJOR_VERSION >= 3
++ if (PyUnicode_Check(PyTuple_GET_ITEM(listitem, 1))) {
++#else
+ if (PyString_Check(PyTuple_GET_ITEM(listitem, 1))) {
++#endif
+ /* Handle strings as second argument for backwards compatibility */
++
++#if PY_MAJOR_VERSION >= 3
++ PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(listitem, 1), &cstr, &clen);
++#else
+ PyString_AsStringAndSize(PyTuple_GET_ITEM(listitem, 1), &cstr, &clen);
++#endif
+ /* INFO: curl_formadd() internally does memdup() the data, so
+ * embedded NUL characters _are_ allowed here. */
+ res = curl_formadd(&post, &last,
+@@ -1905,7 +2061,11 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ curl_formfree(post);
+ return NULL;
+ }
++#if PY_MAJOR_VERSION >= 3
++ if (!PyUnicode_Check(PyTuple_GET_ITEM(t, j+1))) {
++#else
+ if (!PyString_Check(PyTuple_GET_ITEM(t, j+1))) {
++#endif
+ PyErr_SetString(PyExc_TypeError, "value must be string");
+ PyMem_Free(forms);
+ curl_formfree(post);
+@@ -1923,7 +2083,11 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ curl_formfree(post);
+ return NULL;
+ }
++#if PY_MAJOR_VERSION >= 3
++ PyUnicode_AsStringAndSize(PyTuple_GET_ITEM(t, j+1), &ostr, &olen);
++#else
+ PyString_AsStringAndSize(PyTuple_GET_ITEM(t, j+1), &ostr, &olen);
++#endif
+ forms[k].option = val;
+ forms[k].value = ostr;
+ ++k;
+@@ -1975,7 +2139,11 @@ do_curl_setopt(CurlObject *self, PyObject *args)
+ struct curl_slist *nlist;
+ char *str;
+
++#if PY_MAJOR_VERSION >= 3
++ if (!PyUnicode_Check(listitem)) {
++#else
+ if (!PyString_Check(listitem)) {
++#endif
+ curl_slist_free_all(slist);
+ PyErr_SetString(PyExc_TypeError, "list items must be string objects");
+ return NULL;
+@@ -2190,7 +2358,12 @@ do_curl_getinfo(CurlObject *self, PyObject *args)
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
++#if PY_MAJOR_VERSION >= 3
++ return PyUnicode_FromString(s_res);
++#else
+ return PyString_FromString(s_res);
++#endif
++
+ }
+
+ case CURLINFO_CONNECT_TIME:
+@@ -2849,7 +3022,7 @@ do_multi_info_read(CurlMultiObject *self, PyObject *args)
+ Py_DECREF(ok_list);
+ CURLERROR_MSG("Unable to fetch curl handle from curl object");
+ }
+- assert(co->ob_type == p_Curl_Type);
++ assert(Py_TYPE(co) == p_Curl_Type);
+ if (msg->msg != CURLMSG_DONE) {
+ /* FIXME: what does this mean ??? */
+ }
+@@ -2930,7 +3103,6 @@ do_multi_select(CurlMultiObject *self, PyObject *args)
+ * socket code to report any errors.
+ */
+ }
+-
+ return PyInt_FromLong(n);
+ }
+
+@@ -2995,6 +3167,116 @@ static PyObject *curlobject_constants = NULL;
+ static PyObject *curlmultiobject_constants = NULL;
+ static PyObject *curlshareobject_constants = NULL;
+
++
++#if PY_MAJOR_VERSION >= 3
++static PyObject *
++my_getattro(PyObject *co, PyObject *name, PyObject *dict1, PyObject *dict2, PyMethodDef *m)
++{
++ PyObject *v = NULL;
++ if( v == NULL && dict1 != NULL )
++ v = PyDict_GetItem(dict1, name);
++ if( v == NULL && dict2 != NULL )
++ v = PyDict_GetItem(dict2, name);
++ if( v != NULL )
++ {
++ Py_INCREF(v);
++ return v;
++ }
++ return NULL;
++}
++
++static int
++my_setattro(PyObject **dict, PyObject *name, PyObject *v)
++{
++ if( *dict == NULL )
++ {
++ *dict = PyDict_New();
++ if( *dict == NULL )
++ return -1;
++ }
++ return PyDict_SetItem(*dict, name, v);
++}
++
++PyObject *do_curl_getattro(PyObject *o, PyObject *n)
++{
++ PyObject *v = PyObject_GenericGetAttr(o, n);
++ if( !v && PyErr_ExceptionMatches(PyExc_AttributeError) )
++ {
++ PyErr_Clear();
++ v = my_getattro(o, n, ((CurlObject *)o)->dict,
++ curlobject_constants, curlobject_methods);
++ }
++ return v;
++}
++
++static int
++do_curl_setattro(PyObject *o, PyObject *name, PyObject *v)
++{
++ assert_curl_state((CurlObject *)o);
++ if( v )
++ {
++ return my_setattro(&((CurlObject *)o)->dict, name, v);
++ } else
++ {
++ return PyObject_GenericSetAttr(o, name, 0);
++ }
++}
++
++static PyObject *
++do_multi_getattro(PyObject *o, PyObject *n)
++{
++ assert_multi_state((CurlMultiObject *)o);
++ PyObject *v = PyObject_GenericGetAttr(o, n);
++ if( !v && PyErr_ExceptionMatches(PyExc_AttributeError) )
++ {
++ PyErr_Clear();
++ v = my_getattro(o, n, ((CurlMultiObject *)o)->dict,
++ curlmultiobject_constants, curlmultiobject_methods);
++ }
++ return v;
++}
++
++static int
++do_multi_setattro(PyObject *o, PyObject *n, PyObject *v)
++{
++ assert_multi_state((CurlMultiObject *)o);
++ if( v )
++ {
++ return my_setattro(&((CurlMultiObject *)o)->dict, n, v);
++ } else
++ {
++ return PyObject_GenericSetAttr(o, n, 0);
++ }
++}
++
++static PyObject *
++do_share_getattro(PyObject *o, PyObject *n)
++{
++ assert_share_state((CurlShareObject *)o);
++ PyObject *v = PyObject_GenericGetAttr(o, n);
++ if( !v && PyErr_ExceptionMatches(PyExc_AttributeError) )
++ {
++ PyErr_Clear();
++ v = my_getattro(o, n, ((CurlShareObject *)o)->dict,
++ curlshareobject_constants, curlshareobject_methods);
++ }
++ return v;
++}
++
++static int
++do_share_setattro(PyObject *o, PyObject *n, PyObject *v)
++{
++ assert_share_state((CurlShareObject *)o);
++ if( v )
++ {
++ return my_setattro(&((CurlShareObject *)o)->dict, n, v);
++ } else
++ {
++ return PyObject_GenericSetAttr(o, n, 0);
++ }
++}
++
++#else
+ static int
+ my_setattr(PyObject **dict, char *name, PyObject *v)
+ {
+@@ -3029,6 +3311,7 @@ my_getattr(PyObject *co, char *name, PyObject *dict1, PyObject *dict2, PyMethodD
+ return Py_FindMethod(m, co, name);
+ }
+
++
+ static int
+ do_share_setattr(CurlShareObject *so, char *name, PyObject *v)
+ {
+@@ -3073,10 +3356,53 @@ do_multi_getattr(CurlMultiObject *co, char *name)
+ return my_getattr((PyObject *)co, name, co->dict,
+ curlmultiobject_constants, curlmultiobject_methods);
+ }
++#endif
+
+
+-/* --------------- actual type definitions --------------- */
+
++/* --------------- actual type definitions --------------- */
++#if PY_MAJOR_VERSION >= 3
++static PyTypeObject CurlShare_Type = {
++ PyVarObject_HEAD_INIT(NULL, 0)
++ "pycurl.CurlShare", /* tp_name */
++ sizeof(CurlShareObject), /* tp_basicsize */
++ 0, /* tp_itemsize */
++ (destructor)do_share_dealloc,/* tp_dealloc */
++ 0, /* tp_print */
++ 0, /* tp_getattr */
++ 0, /* tp_setattr */
++ 0, /* tp_reserved */
++ 0, /* tp_repr */
++ 0, /* tp_as_number */
++ 0, /* tp_as_sequence */
++ 0, /* tp_as_mapping */
++ 0, /* tp_hash */
++ 0, /* tp_call */
++ 0, /* tp_str */
++ (getattrofunc)do_share_getattro, /* tp_getattro */
++ (setattrofunc)do_share_setattro, /* tp_setattro */
++ 0, /* tp_as_buffer */
++ Py_TPFLAGS_HAVE_GC, /* tp_flags */
++ 0, /* tp_doc */
++ (traverseproc)do_share_traverse, /* tp_traverse */
++ (inquiry)do_share_clear, /* tp_clear */
++ 0, /* tp_richcompare */
++ 0, /* tp_weaklistoffset */
++ 0, /* tp_iter */
++ 0, /* tp_iternext */
++ curlshareobject_methods, /* tp_methods */
++ 0, /* tp_members */
++ 0, /* tp_getset */
++ 0, /* tp_base */
++ 0, /* tp_dict */
++ 0, /* tp_descr_get */
++ 0, /* tp_descr_set */
++ 0, /* tp_dictoffset */
++ 0, /* tp_init */
++ 0, /* tp_alloc */
++ 0, /* tp_new */
++};
++#else
+ static PyTypeObject CurlShare_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+@@ -3107,7 +3433,50 @@ static PyTypeObject CurlShare_Type = {
+ * safely ignore any compiler warnings about missing initializers.
+ */
+ };
++#endif
+
++#if PY_MAJOR_VERSION >= 3
++static PyTypeObject Curl_Type = {
++ PyVarObject_HEAD_INIT(NULL, 0)
++ "pycurl.Curl", /* tp_name */
++ sizeof(CurlObject), /* tp_basicsize */
++ 0, /* tp_itemsize */
++ (destructor)do_curl_dealloc,/* tp_dealloc */
++ 0, /* tp_print */
++ 0, /* tp_getattr */
++ 0, /* tp_setattr */
++ 0, /* tp_reserved */
++ 0, /* tp_repr */
++ 0, /* tp_as_number */
++ 0, /* tp_as_sequence */
++ 0, /* tp_as_mapping */
++ 0, /* tp_hash */
++ 0, /* tp_call */
++ 0, /* tp_str */
++ (getattrofunc)do_curl_getattro, /* tp_getattro */
++ (setattrofunc)do_curl_setattro, /* tp_setattro */
++ 0, /* tp_as_buffer */
++ Py_TPFLAGS_HAVE_GC, /* tp_flags */
++ 0, /* tp_doc */
++ (traverseproc)do_curl_traverse, /* tp_traverse */
++ (inquiry)do_curl_clear, /* tp_clear */
++ 0, /* tp_richcompare */
++ 0, /* tp_weaklistoffset */
++ 0, /* tp_iter */
++ 0, /* tp_iternext */
++ curlobject_methods, /* tp_methods */
++ 0, /* tp_members */
++ 0, /* tp_getset */
++ 0, /* tp_base */
++ 0, /* tp_dict */
++ 0, /* tp_descr_get */
++ 0, /* tp_descr_set */
++ 0, /* tp_dictoffset */
++ 0, /* tp_init */
++ 0, /* tp_alloc */
++ 0, /* tp_new */
++};
++#else
+ static PyTypeObject Curl_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+@@ -3138,7 +3507,50 @@ static PyTypeObject Curl_Type = {
+ * safely ignore any compiler warnings about missing initializers.
+ */
+ };
++#endif
+
++#if PY_MAJOR_VERSION >= 3
++static PyTypeObject CurlMulti_Type = {
++ PyVarObject_HEAD_INIT(NULL, 0)
++ "pycurl.CurlMulti", /* tp_name */
++ sizeof(CurlMultiObject), /* tp_basicsize */
++ 0, /* tp_itemsize */
++ (destructor)do_multi_dealloc,/* tp_dealloc */
++ 0, /* tp_print */
++ 0, // (getattrfunc)do_curl_getattr, /* tp_getattr */
++ 0, //(setattrfunc)do_curl_setattr, /* tp_setattr */
++ 0, /* tp_reserved */
++ 0, /* tp_repr */
++ 0, /* tp_as_number */
++ 0, /* tp_as_sequence */
++ 0, /* tp_as_mapping */
++ 0, /* tp_hash */
++ 0, /* tp_call */
++ 0, /* tp_str */
++ (getattrofunc)do_multi_getattro, //0, /* tp_getattro */
++ (setattrofunc)do_multi_setattro, /* tp_setattro */
++ 0, /* tp_as_buffer */
++ Py_TPFLAGS_HAVE_GC, /* tp_flags */
++ 0, /* tp_doc */
++ (traverseproc)do_multi_traverse, /* tp_traverse */
++ (inquiry)do_multi_clear, /* tp_clear */
++ 0, /* tp_richcompare */
++ 0, /* tp_weaklistoffset */
++ 0, /* tp_iter */
++ 0, /* tp_iternext */
++ curlmultiobject_methods, /* tp_methods */
++ 0, /* tp_members */
++ 0, /* tp_getset */
++ 0, /* tp_base */
++ 0, /* tp_dict */
++ 0, /* tp_descr_get */
++ 0, /* tp_descr_set */
++ 0, /* tp_dictoffset */
++ 0, /* tp_init */
++ 0, /* tp_alloc */
++ 0, /* tp_new */
++};
++#else
+ static PyTypeObject CurlMulti_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+@@ -3169,7 +3581,7 @@ static PyTypeObject CurlMulti_Type = {
+ * safely ignore any compiler warnings about missing initializers.
+ */
+ };
+-
++#endif
+
+ /*************************************************************************
+ // module level
+@@ -3227,7 +3639,11 @@ static PyObject *vi_str(const char *s)
+ }
+ while (*s == ' ' || *s == '\t')
+ s++;
++#if PY_MAJOR_VERSION >= 3
++ return PyUnicode_FromString(s);
++#else
+ return PyString_FromString(s);
++#endif
+ }
+
+ static PyObject *
+@@ -3354,7 +3770,13 @@ insobj2(PyObject *dict1, PyObject *dict2, char *name, PyObject *value)
+ goto error;
+ if (value == NULL)
+ goto error;
++
++#if PY_MAJOR_VERSION >= 3
++ key = PyUnicode_FromString(name);
++#else
+ key = PyString_FromString(name);
++#endif
++
+ if (key == NULL)
+ goto error;
+ #if 0
+@@ -3381,7 +3803,11 @@ error:
+ static void
+ insstr(PyObject *d, char *name, char *value)
+ {
++#if PY_MAJOR_VERSION >= 3
++ PyObject *v = PyUnicode_FromString(value);
++#else
+ PyObject *v = PyString_FromString(value);
++#endif
+ insobj2(d, NULL, name, v);
+ }
+
+@@ -3414,6 +3840,20 @@ insint_m(PyObject *d, char *name, long value)
+ }
+
+
++#if PY_MAJOR_VERSION >= 3
++static PyModuleDef curlmodule = {
++ PyModuleDef_HEAD_INIT,
++ "pycurl",
++ module_doc,
++ -1,
++ curl_methods, NULL, NULL, NULL, NULL
++};
++#endif
++
++
++#if PY_MAJOR_VERSION >= 3
++PyMODINIT_FUNC PyInit_pycurl(void)
++#else
+ /* Initialization function for the module */
+ #if defined(PyMODINIT_FUNC)
+ PyMODINIT_FUNC
+@@ -3424,6 +3864,7 @@ extern "C"
+ DL_EXPORT(void)
+ #endif
+ initpycurl(void)
++#endif
+ {
+ PyObject *m, *d;
+ const curl_version_info_data *vi;
+@@ -3433,13 +3874,29 @@ initpycurl(void)
+ p_Curl_Type = &Curl_Type;
+ p_CurlMulti_Type = &CurlMulti_Type;
+ p_CurlShare_Type = &CurlShare_Type;
+- Curl_Type.ob_type = &PyType_Type;
+- CurlMulti_Type.ob_type = &PyType_Type;
+- CurlShare_Type.ob_type = &PyType_Type;
++ Py_TYPE(&Curl_Type) = &PyType_Type;
++ Py_TYPE(&CurlMulti_Type) = &PyType_Type;
++ Py_TYPE(&CurlShare_Type) = &PyType_Type;
+
+ /* Create the module and add the functions */
++#if PY_MAJOR_VERSION >= 3
++ if (PyType_Ready(&Curl_Type) < 0)
++ return NULL;
++
++ if (PyType_Ready(&CurlMulti_Type) < 0)
++ return NULL;
++
++
++ m = PyModule_Create(&curlmodule);
++ if (m == NULL)
++ return NULL;
++
++ Py_INCREF(&Curl_Type);
++#else
++
+ m = Py_InitModule3("pycurl", curl_methods, module_doc);
+ assert(m != NULL && PyModule_Check(m));
++#endif
+
+ /* Add error object to the module */
+ d = PyModule_GetDict(m);
+@@ -3906,6 +4363,9 @@ initpycurl(void)
+ /* Finally initialize global interpreter lock */
+ PyEval_InitThreads();
+
++#if PY_MAJOR_VERSION >= 3
++ return m;
++#endif
+ }
+
+ /* vi:ts=4:et:nowrap
+diff --git a/tests/test_internals.py b/tests/test_internals.py
+index afcc53d..7c2f602 100644
+--- a/tests/test_internals.py
++++ b/tests/test_internals.py
+@@ -16,7 +16,10 @@ try:
+ except ImportError:
+ gc = None
+ import copy, os, sys
+-from StringIO import StringIO
++try:
++ from io import StringIO
++except ImportError:
++ from StringIO import StringIO
+ try:
+ import cPickle
+ except ImportError:
+@@ -41,10 +44,10 @@ if "-q" in sys.argv:
+ opts.verbose = opts.verbose - 1
+
+
+-print "Python", sys.version
+-print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
+-print "PycURL version info", pycurl.version_info()
+-print " %s, compiled %s" % (pycurl.__file__, pycurl.COMPILE_DATE)
++print("Python", sys.version)
++print("PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM))
++print("PycURL version info", pycurl.version_info())
++print(" %s, compiled %s" % (pycurl.__file__, pycurl.COMPILE_DATE))
+
+
+ # /***********************************************************************
+@@ -148,13 +151,13 @@ if 1 and copy:
+ m = CurlMulti()
+ try:
+ copy.copy(c)
+- except copy.Error:
++ except (copy.Error, TypeError):
+ pass
+ else:
+ assert 0, "internal error - copying should fail"
+ try:
+ copy.copy(m)
+- except copy.Error:
++ except (copy.Error, TypeError):
+ pass
+ else:
+ assert 0, "internal error - copying should fail"
+@@ -166,13 +169,13 @@ if 1 and pickle:
+ p = pickle.Pickler(fp, 1)
+ try:
+ p.dump(c)
+- except pickle.PicklingError:
++ except (pickle.PicklingError, TypeError):
+ pass
+ else:
+ assert 0, "internal error - pickling should fail"
+ try:
+ p.dump(m)
+- except pickle.PicklingError:
++ except (pickle.PicklingError, TypeError):
+ pass
+ else:
+ assert 0, "internal error - pickling should fail"
+@@ -229,7 +232,9 @@ if 1 and gc:
+ c.m.c = c
+ # delete
+ gc.collect()
+- flags = gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_OBJECTS
++ flags = gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE
++ if hasattr(gc, "DEBUG_OBJECTS"):
++ flags = flags | gc.DEBUG_OBJECTS
+ if opts.verbose >= 1:
+ flags = flags | gc.DEBUG_STATS
+ gc.set_debug(flags)
+@@ -237,17 +242,17 @@ if 1 and gc:
+ ##print gc.get_referrers(c)
+ ##print gc.get_objects()
+ if opts.verbose >= 1:
+- print "Tracked objects:", len(gc.get_objects())
++ print("Tracked objects:", len(gc.get_objects()))
+ # The `del' below should delete these 4 objects:
+ # Curl + internal dict, CurlMulti + internal dict
+ del c
+ gc.collect()
+ if opts.verbose >= 1:
+- print "Tracked objects:", len(gc.get_objects())
++ print("Tracked objects:", len(gc.get_objects()))
+
+
+ # /***********************************************************************
+ # // done
+ # ************************************************************************/
+
+-print "All tests passed."
++print("All tests passed.")
+diff --git a/tests/test_memleak.py b/tests/test_memleak.py
+index 284df62..ad7bad1 100644
+--- a/tests/test_memleak.py
++++ b/tests/test_memleak.py
+@@ -12,20 +12,22 @@ import gc, pycurl, sys
+ gc.enable()
+
+
+-print "Python", sys.version
+-print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
++print("Python", sys.version)
++print("PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM))
+ ##print "PycURL version info", pycurl.version_info()
+-print " %s, compiled %s" % (pycurl.__file__, pycurl.COMPILE_DATE)
++print(" %s, compiled %s" % (pycurl.__file__, pycurl.COMPILE_DATE))
+
+
+ gc.collect()
+-flags = gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_OBJECTS
++flags = gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE
++if hasattr(gc, "DEBUG_OBJECTS"):
++ flags = flags | gc.DEBUG_OBJECTS
+ if 1:
+ flags = flags | gc.DEBUG_STATS
+ gc.set_debug(flags)
+ gc.collect()
+
+-print "Tracked objects:", len(gc.get_objects())
++print("Tracked objects:", len(gc.get_objects()))
+
+ multi = pycurl.CurlMulti()
+ t = []
+@@ -34,20 +36,20 @@ for a in range(100):
+ multi.add_handle(curl)
+ t.append(curl)
+
+-print "Tracked objects:", len(gc.get_objects())
++print("Tracked objects:", len(gc.get_objects()))
+
+ for curl in t:
+ curl.close()
+ multi.remove_handle(curl)
+
+-print "Tracked objects:", len(gc.get_objects())
++print("Tracked objects:", len(gc.get_objects()))
+
+ del curl
+ del t
+ del multi
+
+-print "Tracked objects:", len(gc.get_objects())
++print("Tracked objects:", len(gc.get_objects()))
+ gc.collect()
+-print "Tracked objects:", len(gc.get_objects())
++print("Tracked objects:", len(gc.get_objects()))
+
+
diff --git a/dev-python/pycurl/pycurl-7.19.0-r3.ebuild b/dev-python/pycurl/pycurl-7.19.0-r3.ebuild
new file mode 100644
index 000000000000..f06af3f5ec4a
--- /dev/null
+++ b/dev-python/pycurl/pycurl-7.19.0-r3.ebuild
@@ -0,0 +1,58 @@
+# Copyright 1999-2013 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: /var/cvsroot/gentoo-x86/dev-python/pycurl/pycurl-7.19.0-r3.ebuild,v 1.1 2013/02/06 03:01:47 floppym Exp $
+
+EAPI=5
+
+# The selftests fail with pypy, and urlgrabber segfaults for me.
+PYTHON_COMPAT=( python{2_5,2_6,2_7,3_1,3_2,3_3} )
+
+inherit distutils-r1
+
+DESCRIPTION="python binding for curl/libcurl"
+HOMEPAGE="http://pycurl.sourceforge.net/ http://pypi.python.org/pypi/pycurl"
+SRC_URI="http://pycurl.sourceforge.net/download/${P}.tar.gz"
+
+LICENSE="LGPL-2.1"
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86 ~amd64-fbsd ~x86-fbsd ~x86-interix ~amd64-linux ~x86-linux ~ppc-macos ~x64-macos ~x86-macos"
+IUSE="curl_ssl_gnutls curl_ssl_nss +curl_ssl_openssl examples ssl"
+
+# Depend on a curl with curl_ssl_* USE flags.
+# libcurl must not be using an ssl backend we do not support.
+# If the libcurl ssl backend changes pycurl should be recompiled.
+# If curl uses gnutls, depend on at least gnutls 2.11.0 so that pycurl
+# does not need to initialize gcrypt threading and we do not need to
+# explicitly link to libgcrypt.
+DEPEND=">=net-misc/curl-7.25.0-r1[ssl=]
+ ssl? (
+ net-misc/curl[curl_ssl_gnutls=,curl_ssl_nss=,curl_ssl_openssl=,-curl_ssl_axtls,-curl_ssl_cyassl,-curl_ssl_polarssl]
+ curl_ssl_gnutls? ( >=net-libs/gnutls-2.11.0 )
+ )"
+RDEPEND="${DEPEND}"
+
+python_prepare_all() {
+ local PATCHES=(
+ "${FILESDIR}/${P}-linking-v2.patch"
+ "${FILESDIR}/${P}-python3.patch"
+ )
+
+ sed -e "/data_files=/d" -i setup.py || die
+
+ distutils-r1_python_prepare_all
+}
+
+python_test() {
+ "${PYTHON}" tests/test_internals.py -q || die "Tests fail with ${EPYTHON}"
+}
+
+python_install_all() {
+ local HTML_DOCS=( doc/. )
+
+ distutils-r1_python_install_all
+
+ if use examples; then
+ dodoc -r examples
+ docompress -x /usr/share/doc/${PF}/examples
+ fi
+}