Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge remote-tracking branch 'akheron/python3'

  • Loading branch information...
commit 695a315c45f2ced81848ecc177cb040c2849e439 2 parents 5f5aa6d + 424b288
@nailor nailor authored
View
2  setup.py
@@ -20,6 +20,8 @@
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.2',
'Topic :: Database',
]
)
View
27 test/couch_util.py
@@ -27,7 +27,16 @@
import shutil
import subprocess
import time
-import urllib2
+import sys
+
+try:
+ # Python 3
+ from urllib import request
+ from urllib.error import URLError
+except ImportError:
+ # Python 3
+ import urllib2 as request
+ from urllib2 import URLError
import nose.tools
from tornado.httpclient import HTTPClient
@@ -38,7 +47,9 @@ def setup():
global _proc, baseurl
try:
shutil.rmtree('tmp')
- except OSError, err:
+ except OSError:
+ # Python 3
+ err = sys.exc_info()[1]
if err.errno != errno.ENOENT:
raise
@@ -53,7 +64,7 @@ def setup():
baseurl = 'http://localhost:%d/' % port
with open(ini, 'w') as fobj:
- print >>fobj, '''\
+ fobj.write('''\
[couchdb]
database_dir = %(dbdir)s
view_index_dir = %(dbdir)s
@@ -64,7 +75,7 @@ def setup():
[log]
file = %(log)s
-''' % dict(dbdir=dbdir, log=log, port=port)
+''' % dict(dbdir=dbdir, log=log, port=port))
cmdline = 'couchdb -a %s' % ini
null = open('/dev/null', 'w')
@@ -76,11 +87,11 @@ def setup():
while True:
try:
- f = urllib2.urlopen(baseurl)
- except urllib2.URLError:
+ f = request.urlopen(baseurl)
+ except URLError:
continue
try:
- data = json.load(f)
+ json.loads(f.read().decode('utf-8'))
except ValueError:
continue
# Got a sensible response
@@ -101,7 +112,7 @@ def inner(*args, **kwargs):
# Delete all old databases
response = cli.fetch('%s_all_dbs' % baseurl)
try:
- dbs = json.loads(response.body)
+ dbs = json.loads(response.body.decode('utf-8'))
except ValueError:
print >> sys.stderr, \
"CouchDB's response was invalid JSON: %s" % db_string
View
110 test/test_client.py
@@ -24,17 +24,25 @@
from __future__ import with_statement
from datetime import datetime
+import sys
+
from nose.tools import eq_ as eq
-from couch_util import setup, teardown, with_couchdb
-from util import with_ioloop, DatetimeEncoder
+from .couch_util import setup, teardown, with_couchdb
+from .util import with_ioloop, DatetimeEncoder
try:
import json
except ImportError:
import simplejson as json
-import functools
-import urllib
+try:
+ # Python 3
+ from urllib.request import urlopen
+ from urllib.error import HTTPError
+except ImportError:
+ # Python 2
+ from urllib2 import urlopen
+ from urllib2 import HTTPError
import trombi
import trombi.errors
@@ -71,8 +79,8 @@ def test_create_db(baseurl, ioloop):
def create_callback(db):
eq(db.error, False)
assert isinstance(db, trombi.Database)
- f = urllib.urlopen('%s_all_dbs' % baseurl)
- assert 'couchdb-database' in json.load(f)
+ f = urlopen('%s_all_dbs' % baseurl)
+ assert 'couchdb-database' in json.loads(f.read().decode('utf-8'))
ioloop.stop()
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -95,8 +103,8 @@ def callback(result):
eq(result.error, True)
eq(result.errno, trombi.errors.PRECONDITION_FAILED)
eq(result.msg, "Database already exists: 'couchdb-database'")
- f = urllib.urlopen('%s_all_dbs' % baseurl)
- assert 'couchdb-database' in json.load(f)
+ f = urlopen('%s_all_dbs' % baseurl)
+ assert 'couchdb-database' in json.loads(f.read().decode('utf-8'))
ioloop.stop()
s.create('couchdb-database', callback=first_callback)
@@ -157,8 +165,9 @@ def create_callback(db):
def delete_callback(result):
eq(result.error, False)
- f = urllib.urlopen('%s_all_dbs' % baseurl)
- eq([x for x in json.load(f) if not x.startswith('_')], [])
+ f = urlopen('%s_all_dbs' % baseurl)
+ data = f.read().decode('utf-8')
+ eq([x for x in json.loads(data) if not x.startswith('_')], [])
ioloop.stop()
s.create('testdatabase', callback=create_callback)
@@ -366,13 +375,13 @@ def _assert_on_fetch(*a, **kw):
doc.load_attachment('foo', got_attachment)
def got_attachment(data):
- eq(data, 'bar')
+ eq(data, b'bar')
ioloop.stop()
db.set(
{'testvalue': 'something'},
create_doc_callback,
- attachments={'foo': (None, 'bar')}
+ attachments={'foo': (None, b'bar')}
)
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -388,14 +397,14 @@ def start():
db.set(
{'testvalue': 'something'},
doc_created,
- attachments={'foo': (None, 'bar')},
+ attachments={'foo': (None, b'bar')},
)
def doc_created(doc):
db.get_attachment(doc.id, 'foo', check_attachment)
def check_attachment(data):
- eq(data, 'bar')
+ eq(data, b'bar')
ioloop.stop()
start()
@@ -461,8 +470,9 @@ def create_doc_callback(doc):
eq(doc['testvalue'], 'something')
- f = urllib.urlopen('%stestdb/testid' % baseurl)
- eq(json.load(f),
+ f = urlopen('%stestdb/testid' % baseurl)
+ data = f.read().decode('utf-8')
+ eq(json.loads(data),
{'_id': 'testid',
'_rev': doc.rev,
'testvalue': 'something',
@@ -491,10 +501,17 @@ def create_doc_callback(doc):
def delete_doc_callback(db):
eq(db.error, False)
assert isinstance(db, trombi.Database)
- ioloop.stop()
- f = urllib.urlopen('%stestdb/testid' % baseurl)
- eq(f.getcode(), 404)
+ try:
+ urlopen('%stestdb/testid' % baseurl)
+ except HTTPError:
+ # Python 3
+ e = sys.exc_info()[1]
+ eq(e.code, 404)
+ else:
+ assert 0
+
+ ioloop.stop()
db.set(
'testid',
@@ -689,12 +706,12 @@ def create_db_callback(db):
'testid',
{'testvalue': 'something'},
data_callback,
- attachments={'foobar': (None, 'some textual data')},
+ attachments={'foobar': (None, b'some textual data')},
)
def data_callback(doc):
- f = urllib.urlopen('%stestdb/testid/foobar' % baseurl)
- eq(f.read(), 'some textual data')
+ f = urlopen('%stestdb/testid/foobar' % baseurl)
+ eq(f.read(), b'some textual data')
ioloop.stop()
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -711,14 +728,14 @@ def create_db_callback(db):
{'testvalue': 'something'},
data_callback,
attachments={'foobar':
- ('application/x-custom', 'some textual data')
+ ('application/x-custom', b'some textual data')
},
)
def data_callback(doc):
- f = urllib.urlopen('%stestdb/testid/foobar' % baseurl)
+ f = urlopen('%stestdb/testid/foobar' % baseurl)
eq(f.info()['Content-Type'], 'application/x-custom')
- eq(f.read(), 'some textual data')
+ eq(f.read(), b'some textual data')
ioloop.stop()
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -737,12 +754,12 @@ def create_db_callback(db):
)
def create_doc_callback(doc):
- data = 'some textual data'
+ data = b'some textual data'
doc.attach('foobar', data, callback=data_callback)
def data_callback(doc):
- f = urllib.urlopen('%stestdb/testid/foobar' % baseurl)
- eq(f.read(), 'some textual data')
+ f = urlopen('%stestdb/testid/foobar' % baseurl)
+ eq(f.read(), b'some textual data')
ioloop.stop()
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -785,14 +802,14 @@ def create_db_callback(db):
)
def create_doc_callback(doc):
- data = 'some textual data'
+ data = b'some textual data'
doc.attach('foobar', data, callback=attach_callback)
def attach_callback(doc):
doc.load_attachment('foobar', callback=data_callback)
def data_callback(data):
- eq(data, 'some textual data')
+ eq(data, b'some textual data')
ioloop.stop()
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -832,14 +849,14 @@ def create_db_callback(db):
'testid',
{'testvalue': 'something'},
attach_callback,
- attachments={'foobar': (None, 'some textual data')},
+ attachments={'foobar': (None, b'some textual data')},
)
def attach_callback(doc):
doc.load_attachment('foobar', callback=data_callback)
def data_callback(data):
- eq(data, 'some textual data')
+ eq(data, b'some textual data')
ioloop.stop()
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -855,7 +872,7 @@ def create_db_callback(db):
'testid',
{'testvalue': 'something'},
attach_callback,
- attachments={'foobar': (None, 'some textual data')},
+ attachments={'foobar': (None, b'some textual data')},
)
def attach_callback(doc):
@@ -866,7 +883,7 @@ def _broken_fetch(*a, **kw):
doc.load_attachment('foobar', callback=data_callback)
def data_callback(data):
- eq(data, 'some textual data')
+ eq(data, b'some textual data')
ioloop.stop()
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -885,15 +902,22 @@ def create_db_callback(db):
)
def create_doc_callback(doc):
- data = 'some textual data'
+ data = b'some textual data'
doc.attach('foobar', data, callback=attach_callback)
def attach_callback(doc):
doc.delete_attachment('foobar', callback=delete_callback)
def delete_callback(doc):
- f = urllib.urlopen('%stestdb/testid/foobar' % baseurl)
- eq(f.getcode(), 404)
+ try:
+ urlopen('%stestdb/testid/foobar' % baseurl)
+ except HTTPError:
+ # Python 3
+ e = sys.exc_info()[1]
+ eq(e.code, 404)
+ else:
+ assert 0
+
ioloop.stop()
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -1279,7 +1303,7 @@ def create_db_callback(db):
db.set(
{'testvalue': 'something'},
create_doc_callback,
- attachments={'foo': (None, 'bar')}
+ attachments={'foo': (None, b'bar')}
)
def create_doc_callback(doc):
@@ -1288,7 +1312,7 @@ def create_doc_callback(doc):
def copy_done(doc):
eq(doc.id, 'newname')
eq(dict(doc), {'testvalue': 'something'})
- eq(doc.attachments.keys(), ['foo'])
+ eq(list(doc.attachments.keys()), ['foo'])
eq(doc.attachments['foo']['content_type'], 'text/plain')
ioloop.stop()
@@ -1304,7 +1328,7 @@ def create_db_callback(db):
db.set(
{'testvalue': 'something'},
create_doc_callback,
- attachments={'foo': (None, 'bar')}
+ attachments={'foo': (None, b'bar')}
)
def create_doc_callback(doc):
@@ -1319,7 +1343,7 @@ def copy_done(doc):
doc.load_attachment('foo', loaded_attachment)
def loaded_attachment(attach):
- eq(attach, 'bar')
+ eq(attach, b'bar')
ioloop.stop()
s = trombi.Server(baseurl, io_loop=ioloop)
@@ -1334,7 +1358,7 @@ def create_db_callback(db):
db.set(
{'testvalue': 'something'},
create_doc_callback,
- attachments={'foo': (None, 'bar')}
+ attachments={'foo': (None, b'bar')}
)
def create_doc_callback(doc):
@@ -1346,7 +1370,7 @@ def got_doc(doc):
def copy_done(doc):
eq(doc.id, 'newname')
eq(dict(doc), {'testvalue': 'something'})
- eq(doc.attachments.keys(), ['foo'])
+ eq(list(doc.attachments.keys()), ['foo'])
eq(doc.attachments['foo']['content_type'], 'text/plain')
ioloop.stop()
View
18 test/util.py
@@ -24,12 +24,11 @@
import os
import sys
import errno
-import new
import shutil
+import types
import nose.tools
from datetime import datetime
-from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
def unrandom(random=None):
@@ -58,7 +57,7 @@ def wrapper(*args, **kwargs):
# Override ioloop's _run_callback to let all exceptions through
def run_callback(self, callback):
callback()
- ioloop._run_callback = new.instancemethod(run_callback, ioloop)
+ ioloop._run_callback = types.MethodType(run_callback, ioloop)
return func(ioloop, *args, **kwargs)
@@ -67,7 +66,9 @@ def run_callback(self, callback):
def mkdir(*a, **kw):
try:
os.mkdir(*a, **kw)
- except OSError, e:
+ except OSError:
+ # Python 3
+ e = sys.exc_info()[1]
if e.errno == errno.EEXIST:
pass
else:
@@ -119,7 +120,9 @@ def maketemp():
tmp = os.path.join(tmp, name)
try:
shutil.rmtree(tmp)
- except OSError, e:
+ except OSError:
+ # Python 3
+ e = sys.exc_info()[1]
if e.errno == errno.ENOENT:
pass
else:
@@ -134,8 +137,9 @@ def assert_raises(excClass, callableObj, *args, **kwargs):
"""
try:
callableObj(*args, **kwargs)
- except excClass, e:
- return e
+ except excClass:
+ # Python 3
+ return sys.exc_info()[1]
except:
if hasattr(excClass,'__name__'): excName = excClass.__name__
else: excName = str(excClass)
View
89 trombi/client.py
@@ -26,10 +26,18 @@
import functools
import logging
import re
-import urllib
import collections
import tornado.ioloop
+try:
+ # Python 3
+ from urllib.parse import quote as urlquote
+ from urllib.parse import urlencode
+except ImportError:
+ # Python 2
+ from urllib import quote as urlquote
+ from urllib import urlencode
+
from base64 import b64encode, b64decode
from tornado.httpclient import AsyncHTTPClient
from tornado.httputil import HTTPHeaders
@@ -45,9 +53,14 @@
def from_uri(uri, fetch_args=None, io_loop=None, **kwargs):
- import urlparse
+ try:
+ # Python 3
+ from urllib.parse import urlparse, urlunsplit
+ except ImportError:
+ # Python 2
+ from urlparse import urlparse, urlunsplit
- p = urlparse.urlparse(uri)
+ p = urlparse(uri)
if p.params or p.query or p.fragment:
raise ValueError(
'Invalid database address: %s (extra query params)' % uri)
@@ -55,7 +68,7 @@ def from_uri(uri, fetch_args=None, io_loop=None, **kwargs):
raise ValueError(
'Invalid database address: %s (only http:// is supported)' % uri)
- baseurl = urlparse.urlunsplit((p.scheme, p.netloc, '', '', ''))
+ baseurl = urlunsplit((p.scheme, p.netloc, '', '', ''))
server = Server(baseurl, fetch_args, io_loop=io_loop, **kwargs)
db_name = p.path.lstrip('/').rstrip('/')
@@ -106,9 +119,9 @@ def to_basetype(self):
def _jsonize_params(params):
result = dict()
- for key, value in params.iteritems():
+ for key, value in params.items():
result[key] = json.dumps(value)
- return urllib.urlencode(result)
+ return urlencode(result)
def _error_response(response):
@@ -116,7 +129,7 @@ def _error_response(response):
return TrombiErrorResponse(599, 'Unable to connect to CouchDB')
try:
- content = json.loads(response.body)
+ content = json.loads(response.body.decode('utf-8'))
except ValueError:
return TrombiErrorResponse(response.code, response.body)
try:
@@ -234,7 +247,8 @@ def _really_callback(response):
def list(self, callback):
def _really_callback(response):
if response.code == 200:
- callback(Database(self, x) for x in json.loads(response.body))
+ body = response.body.decode('utf-8')
+ callback(Database(self, x) for x in json.loads(body))
else:
callback(_error_response(response))
@@ -262,7 +276,8 @@ def _fetch(self, url, *args, **kwargs):
def info(self, callback):
def _really_callback(response):
if response.code == 200:
- callback(TrombiDict(json.loads(response.body)))
+ body = response.body.decode('utf-8')
+ callback(TrombiDict(json.loads(body)))
else:
callback(_error_response(response))
@@ -279,7 +294,7 @@ def set(self, *args, **kwargs):
'Database.set expected 2 or 3 arguments, got %d' % len(args))
if kwargs:
- if kwargs.keys() != ['attachments']:
+ if list(kwargs.keys()) != ['attachments']:
if len(kwargs) > 1:
raise TypeError(
'%s are invalid keyword arguments for this function') %(
@@ -287,7 +302,7 @@ def set(self, *args, **kwargs):
else:
raise TypeError(
'%s is invalid keyword argument for this function' % (
- kwargs.keys()[0]))
+ list(kwargs.keys())[0]))
attachments = kwargs['attachments']
else:
@@ -303,7 +318,7 @@ def set(self, *args, **kwargs):
doc_id = doc.id
if doc_id is not None:
- url = urllib.quote(doc_id, safe='')
+ url = urlquote(doc_id, safe='')
method = 'PUT'
else:
url = ''
@@ -315,12 +330,12 @@ def set(self, *args, **kwargs):
content_type = 'text/plain'
doc.attachments[name] = {
'content_type': content_type,
- 'data': b64encode(attachment_data),
+ 'data': b64encode(attachment_data).decode('utf-8'),
}
def _really_callback(response):
try:
- content = json.loads(response.body)
+ content = json.loads(response.body.decode('utf-8'))
except ValueError:
content = response.body
@@ -341,7 +356,7 @@ def _really_callback(response):
def get(self, doc_id, callback, attachments=False):
def _really_callback(response):
if response.code == 200:
- data = json.loads(response.body)
+ data = json.loads(response.body.decode('utf-8'))
doc = Document(self, data)
callback(doc)
elif response.code == 404:
@@ -350,7 +365,7 @@ def _really_callback(response):
else:
callback(_error_response(response))
- doc_id = urllib.quote(doc_id, safe='')
+ doc_id = urlquote(doc_id, safe='')
kwargs = {}
@@ -377,8 +392,8 @@ def _really_callback(response):
else:
callback(_error_response(response))
- doc_id = urllib.quote(doc_id, safe='')
- attachment_name = urllib.quote(attachment_name, safe='')
+ doc_id = urlquote(doc_id, safe='')
+ attachment_name = urlquote(attachment_name, safe='')
self._fetch(
'%s/%s' % (doc_id, attachment_name),
@@ -388,8 +403,9 @@ def _really_callback(response):
def view(self, design_doc, viewname, callback, **kwargs):
def _really_callback(response):
if response.code == 200:
+ body = response.body.decode('utf-8')
callback(
- ViewResult(json.loads(response.body), db=self)
+ ViewResult(json.loads(body), db=self)
)
else:
callback(_error_response(response))
@@ -432,8 +448,9 @@ def temporary_view(self, callback, map_fun, reduce_fun=None,
language='javascript', **kwargs):
def _really_callback(response):
if response.code == 200:
+ body = response.body.decode('utf-8')
callback(
- ViewResult(json.loads(response.body), db=self)
+ ViewResult(json.loads(body), db=self)
)
else:
callback(_error_response(response))
@@ -453,7 +470,7 @@ def _really_callback(response):
def delete(self, data, callback):
def _really_callback(response):
try:
- json.loads(response.body)
+ json.loads(response.body.decode('utf-8'))
except ValueError:
callback(_error_response(response))
return
@@ -467,7 +484,7 @@ def _really_callback(response):
else:
doc = Document(self, data)
- doc_id = urllib.quote(doc.id, safe='')
+ doc_id = urlquote(doc.id, safe='')
self._fetch(
'%s?rev=%s' % (doc_id, doc.rev),
_really_callback,
@@ -478,7 +495,7 @@ def bulk_docs(self, data, callback, all_or_nothing=False):
def _really_callback(response):
if response.code == 200 or response.code == 201:
try:
- content = json.loads(response.body)
+ content = json.loads(response.body.decode('utf-8'))
except ValueError:
callback(TrombiErrorResponse(response.code, response.body))
else:
@@ -515,12 +532,13 @@ def _really_callback(response):
# this, if the mode is continous
callback(None)
else:
- callback(TrombiResult(json.loads(response.body)))
+ body = response.body.decode('utf-8')
+ callback(TrombiResult(json.loads(body)))
stream_buffer = []
def _stream(text):
- stream_buffer.append(text)
+ stream_buffer.append(text.decode('utf-8'))
chunks = ''.join(stream_buffer).split('\n')
# The last chunk is either an empty string or an
@@ -557,7 +575,7 @@ def _stream(text):
if timeout is not None:
# CouchDB takes timeouts in milliseconds
couchdb_params['timeout'] = timeout * 1000
- url = '_changes?%s' % urllib.urlencode(couchdb_params)
+ url = '_changes?%s' % urlencode(couchdb_params)
params = dict()
if feed == 'continuous':
params['streaming_callback'] = _stream
@@ -621,7 +639,7 @@ def _copy_done(response):
callback(_error_response(response))
return
- content = json.loads(response.body)
+ content = json.loads(response.body.decode('utf-8'))
doc = Document(self.db, self.data)
doc.attachments = self.attachments.copy()
doc.id = content['id']
@@ -629,7 +647,7 @@ def _copy_done(response):
callback(doc)
self.db._fetch(
- '%s' % urllib.quote(self.id, safe=''),
+ '%s' % urlquote(self.id, safe=''),
_copy_done,
allow_nonstandard_methods=True,
method='COPY',
@@ -641,7 +659,7 @@ def _really_callback(response):
if response.code != 201:
callback(_error_response(response))
return
- data = json.loads(response.body)
+ data = json.loads(response.body.decode('utf-8'))
assert data['id'] == self.id
self.rev = data['rev']
self.attachments[name] = {
@@ -655,8 +673,8 @@ def _really_callback(response):
self.db._fetch(
'%s/%s?rev=%s' % (
- urllib.quote(self.id, safe=''),
- urllib.quote(name, safe=''),
+ urlquote(self.id, safe=''),
+ urlquote(name, safe=''),
self.rev),
_really_callback,
method='PUT',
@@ -674,12 +692,13 @@ def _really_callback(response):
if (hasattr(self, 'attachments') and
name in self.attachments and
not self.attachments[name].get('stub', False)):
- callback(b64decode(self.attachments[name]['data']))
+ data = self.attachments[name]['data'].encode('utf-8')
+ callback(b64decode(data))
else:
self.db._fetch(
'%s/%s' % (
- urllib.quote(self.id, safe=''),
- urllib.quote(name, safe='')
+ urlquote(self.id, safe=''),
+ urlquote(name, safe='')
),
_really_callback,
)
@@ -831,7 +850,7 @@ def _really_callback(response):
try:
self.start_doc_id = self.rows[0]['_id']
self.end_doc_id = self.rows[-1]['_id']
- except IndexError, KeyError:
+ except (IndexError, KeyError):
# empty set
self.start_doc_id = None
self.end_doc_id = None
Please sign in to comment.
Something went wrong with that request. Please try again.