From 8e27b9f76e56b53ab8cc845a07d3ec93690c6b50 Mon Sep 17 00:00:00 2001 From: j Date: Wed, 3 Sep 2014 00:32:44 +0200 Subject: [PATCH] port to python3 --- README.md | 4 ++-- ctl | 16 ++++++++-------- oml/__main__.py | 2 +- oml/api.py | 4 ++-- oml/changelog.py | 6 +++--- oml/commands.py | 18 +++++++++--------- oml/directory.py | 7 ++++--- oml/downloads.py | 2 +- oml/item/api.py | 8 ++++---- oml/item/handlers.py | 6 +++--- oml/item/icons.py | 26 ++++++++++++------------- oml/item/models.py | 41 ++++++++++++++++++++-------------------- oml/item/person.py | 4 ++-- oml/item/query.py | 4 ++-- oml/item/scan.py | 6 +++--- oml/json_pickler.py | 11 +++++++++++ oml/localnodes.py | 20 ++++++++++---------- oml/media/__init__.py | 21 ++++++++++---------- oml/media/epub.py | 4 ++-- oml/media/opf.py | 2 +- oml/media/pdf.py | 10 +++++----- oml/media/txt.py | 2 +- oml/meta/__init__.py | 26 ++++++++++++------------- oml/meta/abebooks.py | 2 +- oml/meta/dewey.py | 8 ++++---- oml/meta/duckduckgo.py | 2 +- oml/meta/google.py | 2 +- oml/meta/loc.py | 10 +++++----- oml/meta/lookupbyisbn.py | 10 +++++----- oml/meta/openlibrary.py | 22 ++++++++++----------- oml/meta/utils.py | 4 +++- oml/meta/worldcat.py | 4 ++-- oml/metaremote.py | 4 ++-- oml/metaserver.py | 12 ++++++------ oml/node/cert.py | 4 ++-- oml/node/nodeapi.py | 2 +- oml/node/server.py | 4 ++-- oml/nodes.py | 28 +++++++++++++-------------- oml/oxtornado.py | 28 +++++++++++++-------------- oml/queryparser.py | 2 +- oml/server.py | 2 +- oml/settings.py | 8 ++++---- oml/ssl_request.py | 24 +++++++++++------------ oml/tasks.py | 4 ++-- oml/ui.py | 24 +++++++++++------------ oml/update.py | 10 +++++----- oml/user/api.py | 4 ++-- oml/user/models.py | 9 +++++---- oml/utils.py | 29 +++++++++++++++++----------- oml/websocket.py | 2 +- requirements.txt | 6 +++--- 51 files changed, 272 insertions(+), 248 deletions(-) create mode 100644 oml/json_pickler.py diff --git a/README.md b/README.md index 9855a92..7f0ac20 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,9 @@ To update to latest version: ./ctl update -On Linux you need a working python2 installation with PIL, pyhon-lxml and poppler-utils: +On Linux you need a working python2 installation with pillow, pyhon-lxml and poppler-utils: - apt-get install python2.7 python-imaging python-lxml poppler-utils + apt-get install python3.4 python3-pil python3-lxml poppler-utils Platform diff --git a/ctl b/ctl index 4cb3d14..f3ba771 100755 --- a/ctl +++ b/ctl @@ -26,7 +26,7 @@ export SHARED_ENV PATH="$SHARED_ENV/bin:$PATH" export PATH -PYTHONPATH="$PLATFORM_ENV/lib/python2.7/site-packages:$SHARED_ENV/lib/python2.7/site-packages:$BASE/$NAME" +PYTHONPATH="$PLATFORM_ENV/lib/python3.4/site-packages:$SHARED_ENV/lib/python3.4/site-packages:$BASE/$NAME" export PYTHONPATH oxCACHE="$BASE/config/ox" @@ -45,10 +45,10 @@ if [ "$1" == "start" ]; then exit 1 fi if [ ! -d "$BASE/$NAME/.git" ]; then - python2 oml install_update + python3 oml install_update cd "$BASE/$NAME" fi - python2 oml server $PID + python3 oml server $PID rm -f $PID exit $? fi @@ -59,7 +59,7 @@ if [ "$1" == "debug" ]; then exit 1 fi shift - python2 oml server $@ + python3 oml server $@ exit $? fi if [ "$1" == "stop" ]; then @@ -89,7 +89,7 @@ if [ "$1" == "open" ]; then fi if [ "$1" == "ui" ]; then shift - python2 $NAME/oml/ui.py $@ + python3 $NAME/oml/ui.py $@ exit $? fi if [ "$1" == "update" ]; then @@ -107,17 +107,17 @@ if [ "$1" == "update" ]; then NEW=`"$0" version` "$0" postupdate -o $OLD -n $NEW else - python2 oml update + python3 oml update fi exit $? fi if [ "$1" == "python" ]; then cd "$BASE/$NAME" shift - python2 $@ + python3 $@ exit $? fi cd "$BASE/$NAME" -python2 oml $@ +python3 oml $@ exit $? diff --git a/oml/__main__.py b/oml/__main__.py index df8db8b..9b52a73 100644 --- a/oml/__main__.py +++ b/oml/__main__.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division, print_function + import sys diff --git a/oml/api.py b/oml/api.py index b697721..8fedf29 100644 --- a/oml/api.py +++ b/oml/api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import subprocess import json @@ -67,7 +67,7 @@ def autocompleteFolder(data): else: folder, name = os.path.split(path) if os.path.exists(folder): - prefix, folders, files = os.walk(folder).next() + prefix, folders, files = next(os.walk(folder)) folders = [os.path.join(prefix, f) for f in folders if (not name or f.startswith(name)) and not f.startswith('.')] if prefix == path: folders = [path] + folders diff --git a/oml/changelog.py b/oml/changelog.py index 6937d03..e65505d 100644 --- a/oml/changelog.py +++ b/oml/changelog.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + from datetime import datetime import json @@ -100,7 +100,7 @@ class Changelog(db.Model): return True else: logger.debug('INVLAID SIGNATURE ON CHANGE %s', change) - raise Exception, 'invalid signature' + raise Exception('invalid signature') else: logger.debug('revsion does not match! got %s expecting %s', revision, next_revision) return False @@ -168,7 +168,7 @@ class Changelog(db.Model): if i.timestamp > timestamp: logger.debug('ignore edititem change %s %s %s', timestamp, itemid, meta) return True - keys = filter(lambda k: k in Item.id_keys, meta.keys()) + keys = [k for k in list(meta.keys()) if k in Item.id_keys] if keys: key = keys[0] primary = [key, meta[key]] diff --git a/oml/commands.py b/oml/commands.py index 34e17e8..315aa54 100644 --- a/oml/commands.py +++ b/oml/commands.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import subprocess from os.path import join, exists, dirname @@ -22,7 +22,7 @@ def get(*cmd): return stdout def r(*cmd): - print ' '.join(cmd) + print(' '.join(cmd)) return subprocess.call(cmd) def version(module): @@ -40,7 +40,7 @@ def command_version(*args): """ Print current version """ - print version('openmedialibrary') + print(version('openmedialibrary')) def command_debug(*args): """ @@ -66,7 +66,7 @@ def command_install_update(*args): """ import update if not update.install(): - print "UPDATE FAILED" + print("UPDATE FAILED") sys.exit(1) def command_update(*args): @@ -75,7 +75,7 @@ def command_update(*args): """ import update if not (update.download() and update.install()): - print "UPDATE FAILED" + print("UPDATE FAILED") def command_postupdate(*args): """ @@ -84,7 +84,7 @@ def command_postupdate(*args): def run(*args): o, old, n, new = args if o != '-o' or n != '-n': - print 'usage: -o oldversion -n newversion' + print('usage: -o oldversion -n newversion') sys.exit(1) if old <= '20140521-65-e14c686' and new > '20140521-65-e14c686': if not os.path.exists(settings.db_path): @@ -117,7 +117,7 @@ def command_release(*args): """ Release new version """ - print 'checking...' + print('checking...') import os import json import hashlib @@ -171,7 +171,7 @@ def command_release(*args): sign(release) with open('updates/release.json', 'w') as fd: json.dump(release, fd, indent=2) - print 'signed latest release in updates/release.json' + print('signed latest release in updates/release.json') def command_shell(*args): ''' @@ -223,5 +223,5 @@ def main(): info = actions["command_%s"%command].__doc__.split('\n') info = [' %s%s' % (' ' * indent, i.strip()) for i in info] info = '\n'.join(info).strip() - print(" %s%s%s" % (command, space, info)) + print((" %s%s%s" % (command, space, info))) sys.exit(1) diff --git a/oml/directory.py b/oml/directory.py index e56cff1..6e5cdac 100644 --- a/oml/directory.py +++ b/oml/directory.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 # DHT placeholder -from __future__ import division + import logging import requests import ed25519 import json + import settings logger = logging.getLogger('oml.directory') @@ -27,7 +28,7 @@ def get(vk): vk = ed25519.VerifyingKey(id, encoding='base64') try: vk.verify(sig, data, encoding='base64') - data = json.loads(data) + data = json.loads(data.decode('utf-8')) except ed25519.BadSignatureError: logger.debug('invalid signature') @@ -36,7 +37,7 @@ def get(vk): def put(sk, data): id = sk.get_verifying_key().to_ascii(encoding='base64') - data = json.dumps(data) + data = json.dumps(data).encode('utf-8') sig = sk.sign(data, encoding='base64') url ='%s/%s' % (base, id) headers = { diff --git a/oml/downloads.py b/oml/downloads.py index e7457ee..b6cd57d 100644 --- a/oml/downloads.py +++ b/oml/downloads.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + from threading import Thread import time diff --git a/oml/item/api.py b/oml/item/api.py index 3fa0c39..55db710 100644 --- a/oml/item/api.py +++ b/oml/item/api.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import json import hashlib @@ -11,8 +11,8 @@ from oxtornado import actions from utils import cleanup_id from websocket import trigger_event import metaremote as meta -import models -import query +from . import models +from . import query import settings import state import utils @@ -183,7 +183,7 @@ def getMetadata(data): include_edits = data.pop('includeEdits') else: include_edits = False - key, value = data.iteritems().next() + key, value = next(iter(data.items())) value = cleanup_id(key, value) response = meta.lookup(key, value) if include_edits: diff --git a/oml/item/handlers.py b/oml/item/handlers.py index fd021b6..72312be 100644 --- a/oml/item/handlers.py +++ b/oml/item/handlers.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division, with_statement + from datetime import datetime import mimetypes import os import zipfile -from models import Item +from .models import Item import db import settings import tornado.web @@ -46,7 +46,7 @@ def serve_static(handler, path, mimetype, include_body=True): handler.set_header('Content-Type', mimetype) handler.set_header('Content-Length', str(os.stat(path).st_size)) if include_body: - with open(path) as fd: + with open(path, 'rb') as fd: handler.write(fd.read()) return diff --git a/oml/item/icons.py b/oml/item/icons.py index 094aa37..58fab69 100644 --- a/oml/item/icons.py +++ b/oml/item/icons.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division, with_statement -from StringIO import StringIO + +from io import BytesIO from PIL import Image import sqlite3 @@ -32,30 +32,30 @@ class Icons(dict): def create(self): conn = self.connect() c = conn.cursor() - c.execute(u'CREATE TABLE IF NOT EXISTS icon (id varchar(64) unique, data blob)') - c.execute(u'CREATE TABLE IF NOT EXISTS setting (key varchar(256) unique, value text)') + c.execute('CREATE TABLE IF NOT EXISTS icon (id varchar(64) unique, data blob)') + c.execute('CREATE TABLE IF NOT EXISTS setting (key varchar(256) unique, value text)') if int(self.get_setting(c, 'version', 0)) < 1: self.set_setting(c, 'version', 1) def get_setting(self, c, key, default=None): - c.execute(u'SELECT value FROM setting WHERE key = ?', (key, )) + c.execute('SELECT value FROM setting WHERE key = ?', (key, )) for row in c: return row[0] return default def set_setting(self, c, key, value): - c.execute(u'INSERT OR REPLACE INTO setting values (?, ?)', (key, str(value))) + c.execute('INSERT OR REPLACE INTO setting values (?, ?)', (key, str(value))) def black(self): img = Image.new('RGB', (80, 128)) - o = StringIO() + o = BytesIO() img.save(o, format='jpeg') data = o.getvalue() o.close() return data def __getitem__(self, id, default=None): - sql = u'SELECT data FROM icon WHERE id=?' + sql = 'SELECT data FROM icon WHERE id=?' conn = self.connect() c = conn.cursor() c.execute(sql, (id, )) @@ -68,7 +68,7 @@ class Icons(dict): return data def __setitem__(self, id, data): - sql = u'INSERT OR REPLACE INTO icon values (?, ?)' + sql = 'INSERT OR REPLACE INTO icon values (?, ?)' conn = self.connect() c = conn.cursor() data = sqlite3.Binary(data) @@ -78,7 +78,7 @@ class Icons(dict): conn.close() def __delitem__(self, id): - sql = u'DELETE FROM icon WHERE id = ?' + sql = 'DELETE FROM icon WHERE id = ?' conn = self.connect() c = conn.cursor() c.execute(sql, (id, )) @@ -94,7 +94,7 @@ def get_icon(id, type_, size, callback): skey = '%s:%s:%s' % (type_, id, size) data = icons[skey] if data: - callback(str(data)) + callback(bytes(data)) return key = '%s:%s' % (type_, id) data = icons[key] @@ -114,7 +114,7 @@ def get_icon(id, type_, size, callback): size = None if size: data = icons[skey] = resize_image(data, size=size) - data = str(data) or '' + data = bytes(data) or '' callback(data) @run_async @@ -144,7 +144,7 @@ def get_icon_app(id, type_, size, callback): size = None if size: data = icons[skey] = resize_image(data, size=size) - data = str(data) or '' + data = bytes(data) or '' callback(data) class IconHandler(tornado.web.RequestHandler): diff --git a/oml/item/models.py b/oml/item/models.py index 760f7d2..4d2f530 100644 --- a/oml/item/models.py +++ b/oml/item/models.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + from datetime import datetime -from StringIO import StringIO +from io import StringIO import base64 import hashlib import json @@ -18,8 +18,9 @@ import sqlalchemy as sa from changelog import Changelog from db import MutableDict -from icons import icons -from person import get_sort_name +import json_pickler +from .icons import icons +from .person import get_sort_name from settings import config from utils import remove_empty_folders from websocket import trigger_event @@ -46,8 +47,8 @@ class Item(db.Model): id = sa.Column(sa.String(32), primary_key=True) - info = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json))) - meta = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json))) + info = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json_pickler))) + meta = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json_pickler))) # why is this in db and not in i.e. info? added = sa.Column(sa.DateTime()) # added to local library @@ -104,7 +105,7 @@ class Item(db.Model): if t: j['transferadded'] = t.added j['transferprogress'] = t.progress - j['users'] = map(str, list(self.users)) + j['users'] = list(map(str, list(self.users))) if self.info: j.update(self.info) @@ -115,7 +116,7 @@ class Item(db.Model): if key not in self.meta and key in j: del j[key] if keys: - for k in j.keys(): + for k in list(j.keys()): if k not in keys: del j[k] return j @@ -140,19 +141,19 @@ class Item(db.Model): elif sort_type == 'name': if not isinstance(value, list): value = [value] - value = map(get_sort_name, value) - value = ox.sort_string(u'\n'.join(value)) + value = list(map(get_sort_name, value)) + value = ox.sort_string('\n'.join(value)) elif sort_type == 'title': if isinstance(value, dict): - value = value.values() + value = list(value.values()) if isinstance(value, list): - value = u''.join(value) + value = ''.join(value) value = utils.sort_title(value).lower() else: if isinstance(value, list): - value = u'\n'.join(value) + value = '\n'.join(value) if value: - value = unicode(value) + value = str(value) value = ox.sort_string(value).lower() elif isinstance(value, list): #empty list value = '' @@ -178,7 +179,7 @@ class Item(db.Model): if value: Find.query.filter_by(item_id=self.id, key=key['id']).delete() if isinstance(value, dict): - value = ' '.join(value.values()) + value = ' '.join(list(value.values())) if not isinstance(value, list): value = [value] for v in value: @@ -194,7 +195,7 @@ class Item(db.Model): if key not in self.info: self.info[key] = self.meta[key] del self.meta[key] - users = map(str, list(self.users)) + users = list(map(str, list(self.users))) self.info['mediastate'] = 'available' # available, unavailable, transferring t = Transfer.get(self.id) if t and t.added and t.progress < 1: @@ -230,7 +231,7 @@ class Item(db.Model): record[key] = data[key] self.meta[key] = data[key] update = True - for key in self.meta.keys(): + for key in list(self.meta.keys()): if key not in self.meta_keys: del self.meta[key] update = True @@ -446,7 +447,7 @@ class Find(db.Model): findvalue = sa.Column(sa.Text(), index=True) def __repr__(self): - return (u'%s=%s' % (self.key, self.findvalue)).encode('utf-8') + return ('%s=%s' % (self.key, self.findvalue)).encode('utf-8') @classmethod def get(cls, item, key): @@ -470,7 +471,7 @@ class File(db.Model): sha1 = sa.Column(sa.String(32), primary_key=True) path = sa.Column(sa.String(2048)) - info = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json))) + info = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json_pickler))) item_id = sa.Column(sa.String(32), sa.ForeignKey('item.id')) item = sa.orm.relationship('Item', backref=sa.orm.backref('files', lazy='dynamic')) @@ -591,7 +592,7 @@ class Metadata(db.Model): key = sa.Column(sa.String(256)) value = sa.Column(sa.String(256)) - data = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json))) + data = sa.Column(MutableDict.as_mutable(sa.PickleType(pickler=json_pickler))) def __repr__(self): return '='.join([self.key, self.value]) diff --git a/oml/item/person.py b/oml/item/person.py index cffd7af..fae64d0 100644 --- a/oml/item/person.py +++ b/oml/item/person.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import unicodedata @@ -19,7 +19,7 @@ def get_sort_name(name, sortname=None): person.save() sortname = unicodedata.normalize('NFKD', person.sortname) else: - sortname = u'' + sortname = '' return sortname class Person(db.Model): diff --git a/oml/item/query.py b/oml/item/query.py index 358c898..d2a55c5 100644 --- a/oml/item/query.py +++ b/oml/item/query.py @@ -1,12 +1,12 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + #does not work in sqlite #from sqlalchemy.sql.expression import nullslast from queryparser import Parser -import models +from . import models import settings import utils diff --git a/oml/item/scan.py b/oml/item/scan.py index 7575abd..32bbc6b 100644 --- a/oml/item/scan.py +++ b/oml/item/scan.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + from datetime import datetime import os @@ -67,7 +67,7 @@ def run_scan(): prefix = os.path.join(os.path.expanduser(prefs['libraryPath']), 'Books/') if not prefix[-1] == '/': prefix += '/' - assert isinstance(prefix, unicode) + assert isinstance(prefix, str) books = [] for root, folders, files in os.walk(prefix): for f in files: @@ -121,7 +121,7 @@ def run_import(options=None): listname = options.get('list') if listname: listitems = [] - assert isinstance(prefix, unicode) + assert isinstance(prefix, str) books = [] count = 0 for root, folders, files in os.walk(prefix): diff --git a/oml/json_pickler.py b/oml/json_pickler.py new file mode 100644 index 0000000..ced07af --- /dev/null +++ b/oml/json_pickler.py @@ -0,0 +1,11 @@ +import json + +def loads(*args, **kargs): + #print('loads', args, kargs) + if isinstance(args[0], bytes): + args = (args[0].decode('utf-8'),) + args[1:] + return json.loads(*args, **kargs) + +def dumps(*args, **kargs): + #print('dumps', args, kargs) + return json.dumps(*args, **kargs).encode('utf-8') diff --git a/oml/localnodes.py b/oml/localnodes.py index 3140b14..bdea185 100644 --- a/oml/localnodes.py +++ b/oml/localnodes.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import json import socket import struct -import thread +import _thread from threading import Thread import time @@ -57,8 +57,8 @@ class LocalNodesBase(Thread): 'port': server['node_port'], 'cert': server['cert'] }) - sig = sk.sign(message, encoding='base64') - packet = json.dumps([sig, USER_ID, message]) + sig = sk.sign(message.encode('utf-8'), encoding='base64') + packet = json.dumps([sig, USER_ID, message]).encode('utf-8') else: packet = None return packet @@ -89,7 +89,7 @@ class LocalNodesBase(Thread): now = time.mktime(time.localtime()) if now - last > 60: last = now - thread.start_new_thread(self.send, ()) + _thread.start_new_thread(self.send, ()) except: if self._active: logger.debug('receive failed. restart later', exc_info=1) @@ -115,7 +115,7 @@ class LocalNodesBase(Thread): #print addr if data['id'] != USER_ID: if data['id'] not in self._nodes: - thread.start_new_thread(self.new_node, (data, )) + _thread.start_new_thread(self.new_node, (data, )) elif can_connect(data): self._nodes[data['id']] = data @@ -166,7 +166,7 @@ class LocalNodes4(LocalNodesBase): s = socket.socket (socket.AF_INET, socket.SOCK_DGRAM) s.setsockopt (socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, self._TTL) try: - s.sendto(packet + '\0', sockaddr) + s.sendto(packet + b'\0', sockaddr) except: logger.debug('LocalNodes4.send failed', exc_info=1) s.close() @@ -198,7 +198,7 @@ class LocalNodes6(LocalNodesBase): s = socket.socket(family, socktype, proto) s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, ttl) try: - s.sendto(packet + '\0', sockaddr) + s.sendto(packet + b'\0', sockaddr) except: logger.debug('LocalNodes6.send failed', exc_info=1) s.close() @@ -206,7 +206,7 @@ class LocalNodes6(LocalNodesBase): def get_socket(self): s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - group_bin = socket.inet_pton(socket.AF_INET6, self._BROADCAST) + '\0'*4 + group_bin = socket.inet_pton(socket.AF_INET6, self._BROADCAST) + b'\0'*4 s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_JOIN_GROUP, group_bin) self._socket = s return s @@ -229,7 +229,7 @@ class LocalNodes(object): def cleanup(self): if self._active: - for id in self._nodes.keys(): + for id in list(self._nodes.keys()): if not can_connect(self._nodes[id]): del self._nodes[id] if not self._active: diff --git a/oml/media/__init__.py b/oml/media/__init__.py index 1c88946..ce8952d 100644 --- a/oml/media/__init__.py +++ b/oml/media/__init__.py @@ -1,23 +1,24 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import base64 import hashlib import os +import codecs import ox -import pdf -import epub -import txt -import opf +from . import pdf +from . import epub +from . import txt +from . import opf def get_id(f=None, data=None): if data: - return base64.b32encode(hashlib.sha1(data).digest()) + return base64.b32encode(hashlib.sha1(data).digest()).decode() else: - return base64.b32encode(ox.sha1sum(f, cached=True).decode('hex')) + return base64.b32encode(codecs.decode(ox.sha1sum(f, cached=True), 'hex')).decode() def metadata(f, from_=None): @@ -55,16 +56,16 @@ def metadata(f, from_=None): if key in opf_info: data[key] = opf_info[key] if key in data: - if isinstance(data[key], basestring): + if isinstance(data[key], str): data[key] = data[key].replace('\x00', '') elif isinstance(data[key], list): - data[key] = [e.replace('\x00', '') if isinstance(e, basestring) else e for e in data[key]] + data[key] = [e.replace('\x00', '') if isinstance(e, str) else e for e in data[key]] if 'isbn' in data: data['primaryid'] = ['isbn', data['isbn'][0]] elif 'asin' in data: data['primaryid'] = ['asin', data['asin'][0]] if 'author' in data: - if isinstance(data['author'], basestring): + if isinstance(data['author'], str): if data['author'].strip(): data['author'] = data['author'].strip().split('; ') else: diff --git a/oml/media/epub.py b/oml/media/epub.py index a4f931f..7762093 100644 --- a/oml/media/epub.py +++ b/oml/media/epub.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import os import xml.etree.ElementTree as ET import zipfile -from StringIO import StringIO +from io import StringIO import re from PIL import Image diff --git a/oml/media/opf.py b/oml/media/opf.py index dc55ef3..c7ad78d 100644 --- a/oml/media/opf.py +++ b/oml/media/opf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import xml.etree.ElementTree as ET diff --git a/oml/media/pdf.py b/oml/media/pdf.py index 95fa53c..d79fe31 100644 --- a/oml/media/pdf.py +++ b/oml/media/pdf.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import sys import tempfile @@ -9,7 +9,7 @@ import os import shutil from glob import glob -from pyPdf import PdfFileReader +#from pyPdf import PdfFileReader import stdnum.isbn import settings @@ -139,9 +139,9 @@ def info(pdf): if stdnum.isbn.is_valid(value): data['isbn'] = [value] del data['identifier'] - for key, value in data.iteritems(): + for key, value in data.items(): if isinstance(value, dict): - value = ' '.join(value.values()) + value = ' '.join(list(value.values())) data[key] = value text = extract_text(pdf) data['textsize'] = len(text) @@ -150,7 +150,7 @@ def info(pdf): isbn = extract_isbn(text) if isbn: data['isbn'] = [isbn] - if 'isbn' in data and isinstance(data['isbn'], basestring): + if 'isbn' in data and isinstance(data['isbn'], str): data['isbn'] = [data['isbn']] if 'date' in data and len(data['date']) == 8 and data['date'].isdigit(): d = data['date'] diff --git a/oml/media/txt.py b/oml/media/txt.py index 6d8283c..06f5cb9 100644 --- a/oml/media/txt.py +++ b/oml/media/txt.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import os from utils import find_isbns diff --git a/oml/meta/__init__.py b/oml/meta/__init__.py index 221a735..c4aa64d 100644 --- a/oml/meta/__init__.py +++ b/oml/meta/__init__.py @@ -1,17 +1,17 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import stdnum.isbn import ox -import abebooks -import loc -import lookupbyisbn -import openlibrary -import worldcat -import google -import duckduckgo +from . import abebooks +from . import loc +from . import lookupbyisbn +from . import openlibrary +from . import worldcat +from . import google +from . import duckduckgo import logging logger = logging.getLogger('meta') @@ -51,22 +51,22 @@ def lookup(key, value): ids.append(kv) done = False logger.debug('FIXME: sort ids') - ids.sort(key=lambda i: ox.sort_string(u''.join(i))) + ids.sort(key=lambda i: ox.sort_string(''.join(i))) logger.debug('IDS %s', ids) for k, v in ids: for provider, id in providers: if id == k: if provider not in provider_data: provider_data[provider] = {} - for k_, v_ in globals()[provider].lookup(v).iteritems(): + for k_, v_ in globals()[provider].lookup(v).items(): if k_ not in provider_data[provider]: provider_data[provider][k_] = v_ for provider in sorted( - provider_data.keys(), + list(provider_data.keys()), key=lambda x: -len(provider_data[x]) ): - logger.debug('%s %s %s', provider, len(provider_data[provider]), provider_data[provider].keys()) - for k_, v_ in provider_data[provider].iteritems(): + logger.debug('%s %s %s', provider, len(provider_data[provider]), list(provider_data[provider].keys())) + for k_, v_ in provider_data[provider].items(): if not k_ in data: data[k_] = v_ for k, v in ids: diff --git a/oml/meta/abebooks.py b/oml/meta/abebooks.py index 7669428..8d3420d 100644 --- a/oml/meta/abebooks.py +++ b/oml/meta/abebooks.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import re diff --git a/oml/meta/dewey.py b/oml/meta/dewey.py index 113b5ed..033d527 100644 --- a/oml/meta/dewey.py +++ b/oml/meta/dewey.py @@ -2,10 +2,10 @@ # vi:si:et:sw=4:sts=4:ts=4 def get_classification(id): - name = u'%s' % id + name = '%s' % id base = ''.join([s for s in id.split('/')[0].split('.')[0] if s.isdigit()]) if base in DEWEY: - name = u'%s %s' % (name, DEWEY[base].decode('utf-8')) + name = '%s %s' % (name, DEWEY[base].decode('utf-8')) return name DEWEY = { @@ -941,9 +941,9 @@ if __name__ == '__main__': dewey = {} for i in range(0, 1000): url = 'http://dewey.info/class/%s/about.en.json' % i - print url + print(url) data = json.loads(read_url(url)) - for d in data.values(): + for d in list(data.values()): if 'http://www.w3.org/2004/02/skos/core#prefLabel' in d: value = d['http://www.w3.org/2004/02/skos/core#prefLabel'][0]['value'] dewey[str(i)] = value diff --git a/oml/meta/duckduckgo.py b/oml/meta/duckduckgo.py index 04e8234..b560ab6 100644 --- a/oml/meta/duckduckgo.py +++ b/oml/meta/duckduckgo.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import ox.web.duckduckgo import stdnum.isbn diff --git a/oml/meta/google.py b/oml/meta/google.py index d74755d..f35ae8d 100644 --- a/oml/meta/google.py +++ b/oml/meta/google.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import ox.web.google import stdnum.isbn diff --git a/oml/meta/loc.py b/oml/meta/loc.py index 9a966bf..a171903 100644 --- a/oml/meta/loc.py +++ b/oml/meta/loc.py @@ -1,15 +1,15 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + from ox.cache import read_url import ox import re import xml.etree.ElementTree as ET -from dewey import get_classification -from marc_countries import COUNTRIES -from utils import normalize_isbn +from .dewey import get_classification +from .marc_countries import COUNTRIES +from .utils import normalize_isbn import logging logger = logging.getLogger('meta.loc') @@ -86,7 +86,7 @@ def lookup(id): toc = mods.findall(ns + 'tableOfContents') if toc: info['description'] = toc[0].text.strip() - for key in info.keys(): + for key in list(info.keys()): if not info[key]: del info[key] return info diff --git a/oml/meta/lookupbyisbn.py b/oml/meta/lookupbyisbn.py index 0f8b5b1..da6961c 100644 --- a/oml/meta/lookupbyisbn.py +++ b/oml/meta/lookupbyisbn.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + import re @@ -8,7 +8,7 @@ from ox.cache import read_url from ox import find_re, strip_tags, decode_html import stdnum.isbn -from utils import find_isbns +from .utils import find_isbns import logging logger = logging.getLogger('meta.lookupbyisbn') @@ -78,13 +78,13 @@ def lookup(id): r['description'] = decode_html(strip_tags(desc)) r['cover'] = find_re(data, 'Book cover').replace('._SL160_', '')
     for key in r:
-        if isinstance(r[key], basestring):
+        if isinstance(r[key], str):
             r[key] = decode_html(strip_tags(r[key])).strip()
-    if 'author' in r and isinstance(r['author'], basestring) and r['author']:
+    if 'author' in r and isinstance(r['author'], str) and r['author']:
         r['author'] = [r['author']]
     else:
         r['author'] = []
-    if r['description'].lower() == u'Description of this item is not available at this time.'.lower():
+    if r['description'].lower() == 'Description of this item is not available at this time.'.lower():
         r['description'] = ''
     return r
 
diff --git a/oml/meta/openlibrary.py b/oml/meta/openlibrary.py
index 53a545a..a64940e 100644
--- a/oml/meta/openlibrary.py
+++ b/oml/meta/openlibrary.py
@@ -1,16 +1,16 @@
 # -*- coding: utf-8 -*-
 # vi:si:et:sw=4:sts=4:ts=4
-from __future__ import division
+
 
 from datetime import datetime
-from urllib import urlencode
+from urllib.parse import urlencode
 import json
 
 from ox.cache import read_url
 
-from dewey import get_classification
-from marc_countries import COUNTRIES
-from utils import normalize_isbn
+from .dewey import get_classification
+from .marc_countries import COUNTRIES
+from .utils import normalize_isbn
 
 import logging
 logger = logging.getLogger('meta.openlibrary')
@@ -41,7 +41,7 @@ def find(query):
     results = []
     ids = [b for b in r.get('result', []) if b.startswith('/books')]
     books = api.get_many(ids).get('result', [])
-    for olid, value in books.iteritems():
+    for olid, value in books.items():
         olid = olid.split('/')[-1]
         book = format(value)
         book['olid'] = [olid]
@@ -84,7 +84,7 @@ def lookup(id, return_all=False):
         data['olid'] = []
     if id not in data['olid']:
         data['olid'] = [id]
-    logger.debug('lookup %s => %s', id, data.keys())
+    logger.debug('lookup %s => %s', id, list(data.keys()))
     return data
 
 def get_type(obj):
@@ -129,7 +129,7 @@ def format(info, return_all=False):
             elif key in ('isbn_10', 'isbn_13'):
                 if not isinstance(value, list):
                     value = [value]
-                value = map(normalize_isbn, value)
+                value = list(map(normalize_isbn, value))
                 if KEYS[key] in data:
                     value = data[KEYS[key]] + value
             elif isinstance(value, list) and key not in ('publish_places', 'lccn', 'oclc_numbers'):
@@ -149,7 +149,7 @@ def format(info, return_all=False):
 def resolve_names(objects, key='name'):
     r = []
     data = api.get_many([k['key'] for k in objects]).get('result', {})
-    for k, value in data.iteritems():
+    for k, value in data.items():
         if 'location' in value and value.get('type', {}).get('key') == '/type/redirect':
             value = api.get(value['location']).get('result', {})
         r.append(value[key])
@@ -160,7 +160,7 @@ class API(object):
 
     def _request(self, action, data, timeout=None):
         for key in data:
-            if not isinstance(data[key], basestring):
+            if not isinstance(data[key], str):
                 data[key] = json.dumps(data[key])
         url = self.base + '/' + action + '?' + urlencode(data)
         if timeout is None:
@@ -181,7 +181,7 @@ class API(object):
         return data
 
     def search(self, query):
-        if isinstance(query, basestring):
+        if isinstance(query, str):
             query = {
                 'query': query
             }
diff --git a/oml/meta/utils.py b/oml/meta/utils.py
index 33f3843..3133884 100644
--- a/oml/meta/utils.py
+++ b/oml/meta/utils.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # vi:si:et:sw=4:sts=4:ts=4
-from __future__ import division
+
 
 import re
 import stdnum.isbn
@@ -10,6 +10,8 @@ def normalize_isbn(value):
     return ''.join([s for s in value if s.isdigit() or s == 'X'])
 
 def find_isbns(text):
+    if isinstance(text, bytes):
+        text = text.decode()
     matches = re.compile('\d[\d\-X\ ]+').findall(text)
     matches = [normalize_isbn(value) for value in matches]
     return [isbn for isbn in matches if stdnum.isbn.is_valid(isbn)
diff --git a/oml/meta/worldcat.py b/oml/meta/worldcat.py
index 98ff9ec..35cda9e 100644
--- a/oml/meta/worldcat.py
+++ b/oml/meta/worldcat.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # vi:si:et:sw=4:sts=4:ts=4
-from __future__ import division
+
 
 import re
 import hashlib
@@ -99,7 +99,7 @@ def lookup(id):
             if m:
                 data['date'] = m[0]
 
-    logger.debug('lookup %s => %s', id, data.keys())
+    logger.debug('lookup %s => %s', id, list(data.keys()))
     return data
 
 info = lookup
diff --git a/oml/metaremote.py b/oml/metaremote.py
index bc61b50..e511e8f 100644
--- a/oml/metaremote.py
+++ b/oml/metaremote.py
@@ -1,9 +1,9 @@
 # -*- coding: utf-8 -*-
 # vi:si:et:sw=4:sts=4:ts=4
-from __future__ import division
+
 
 import json
-from urllib import urlencode
+from urllib.parse import urlencode
 
 from ox.cache import read_url
 
diff --git a/oml/metaserver.py b/oml/metaserver.py
index ca025c2..fa45e97 100644
--- a/oml/metaserver.py
+++ b/oml/metaserver.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # vi:si:et:sw=4:sts=4:ts=4
-from __future__ import division, print_function
+
 
 import os
 
@@ -8,11 +8,11 @@ from tornado.web import Application
 from tornado.httpserver import HTTPServer
 from tornado.ioloop import IOLoop
 
-import oxtornado
-from oxtornado import actions
+from . import oxtornado
+from .oxtornado import actions
 
-import meta
-import utils
+from . import meta
+from . import utils
 
 import logging
 logger = logging.getLogger('metaoml')
@@ -49,7 +49,7 @@ def getMetadata(data):
         include_edits = data.pop('includeEdits')
     else:
         include_edits = False
-    key, value = data.iteritems().next()
+    key, value = next(iter(data.items()))
     if key == 'isbn':
         value = utils.normalize_isbn(value)
     response = meta.lookup(key, value)
diff --git a/oml/node/cert.py b/oml/node/cert.py
index a820b14..bda83f1 100644
--- a/oml/node/cert.py
+++ b/oml/node/cert.py
@@ -19,9 +19,9 @@ def generate_ssl():
     key = OpenSSL.crypto.PKey()
     key.generate_key(OpenSSL.crypto.TYPE_RSA, 2048)
     with open(settings.ssl_key_path, 'wb') as fd:
-        os.chmod(settings.ssl_key_path, 0600)
+        os.chmod(settings.ssl_key_path, 0o600)
         fd.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, key))
-        os.chmod(settings.ssl_key_path, 0400)
+        os.chmod(settings.ssl_key_path, 0o400)
 
     ca = OpenSSL.crypto.X509()
     ca.set_version(2)
diff --git a/oml/node/nodeapi.py b/oml/node/nodeapi.py
index 7491a7d..b1ba3f5 100644
--- a/oml/node/nodeapi.py
+++ b/oml/node/nodeapi.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # vi:si:et:sw=4:sts=4:ts=4
-from __future__ import division
+
 
 from changelog import Changelog
 from user.models import User
diff --git a/oml/node/server.py b/oml/node/server.py
index bfecf95..c3c68a0 100644
--- a/oml/node/server.py
+++ b/oml/node/server.py
@@ -11,11 +11,11 @@ from tornado.ioloop import PeriodicCallback
 from oxtornado import run_async
 from utils import valid, get_public_ipv6
 from websocket import trigger_event
-import cert
+from . import cert
 import db
 import directory
 import json
-import nodeapi
+from . import nodeapi
 import settings
 import state
 import user
diff --git a/oml/nodes.py b/oml/nodes.py
index 7399caf..055a374 100644
--- a/oml/nodes.py
+++ b/oml/nodes.py
@@ -1,14 +1,14 @@
 # -*- coding: utf-8 -*-
 # vi:si:et:sw=4:sts=4:ts=4
-from __future__ import division
 
-from Queue import Queue
+
+from queue import Queue
 from threading import Thread
 import json
 import socket
-from StringIO import StringIO
+from io import StringIO
 import gzip
-import urllib2
+import urllib.request, urllib.error, urllib.parse
 from datetime import datetime
 import os
 import time
@@ -135,10 +135,10 @@ class Node(Thread):
             'X-Ed25519-Key': settings.USER_ID,
             'X-Ed25519-Signature': sig,
         }
-        self._opener.addheaders = zip(headers.keys(), headers.values())
+        self._opener.addheaders = list(zip(list(headers.keys()), list(headers.values())))
         try:
             r = self._opener.open(url, data=content, timeout=self.TIMEOUT)
-        except urllib2.HTTPError as e:
+        except urllib.error.HTTPError as e:
             if e.code == 403:
                 logger.debug('REMOTE ENDED PEERING')
                 with db.session():
@@ -150,7 +150,7 @@ class Node(Thread):
             logger.debug('urllib2.HTTPError %s %s', e, e.code)
             self.online = False
             return None
-        except urllib2.URLError as e:
+        except urllib.error.URLError as e:
             logger.debug('urllib2.URLError %s', e)
             self.online = False
             return None
@@ -201,7 +201,7 @@ class Node(Thread):
                     'X-Node-Protocol': settings.NODE_PROTOCOL,
                     'Accept-Encoding': 'gzip',
                 }
-                self._opener.addheaders = zip(headers.keys(), headers.values())
+                self._opener.addheaders = list(zip(list(headers.keys()), list(headers.values())))
                 r = self._opener.open(url, timeout=1)
                 version = r.headers.get('X-Node-Protocol', None)
                 if version != settings.NODE_PROTOCOL:
@@ -297,7 +297,7 @@ class Node(Thread):
         }
         t1 = datetime.utcnow()
         logger.debug('download %s', url)
-        self._opener.addheaders = zip(headers.keys(), headers.values())
+        self._opener.addheaders = list(zip(list(headers.keys()), list(headers.values())))
         r = self._opener.open(url, timeout=self.TIMEOUT*2)
         if r.getcode() == 200:
             if r.headers.get('content-encoding', None) == 'gzip':
@@ -338,7 +338,7 @@ class Node(Thread):
                 headers = {
                     'User-Agent': settings.USER_AGENT,
                 }
-                self._opener.addheaders = zip(headers.keys(), headers.values())
+                self._opener.addheaders = list(zip(list(headers.keys()), list(headers.values())))
                 r = self._opener.open(url)
                 if r.getcode() == 200:
                     with open(path, 'w') as fd:
@@ -379,11 +379,11 @@ class Nodes(Thread):
 
     def _call(self, target, action, *args):
         if target == 'all':
-            nodes = self._nodes.values()
+            nodes = list(self._nodes.values())
         elif target == 'peered':
-            nodes = [n for n in self._nodes.values() if n.user.peered]
+            nodes = [n for n in list(self._nodes.values()) if n.user.peered]
         elif target == 'online':
-            nodes = [n for n in self._nodes.values() if n.online]
+            nodes = [n for n in list(self._nodes.values()) if n.online]
         else:
             nodes = [self._nodes[target]]
         for node in nodes:
@@ -412,7 +412,7 @@ class Nodes(Thread):
     def join(self):
         self._running = False
         self._q.put(None)
-        for node in self._nodes.values():
+        for node in list(self._nodes.values()):
             node.join()
         self._local.join()
         return Thread.join(self)
diff --git a/oml/oxtornado.py b/oml/oxtornado.py
index 778d900..ad302bb 100644
--- a/oml/oxtornado.py
+++ b/oml/oxtornado.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 # vi:si:et:sw=4:sts=4:ts=4
-from __future__ import division, with_statement
+
 
 from contextlib import contextmanager
 import inspect
@@ -30,7 +30,7 @@ def _to_json(python_object):
             tt = python_object.timetuple()
             return '%d-%02d-%02dT%02d:%02d%02dZ' % tuple(list(tt)[:6])
         return python_object.strftime('%Y-%m-%dT%H:%M:%SZ')
-    raise TypeError(u'%s %s is not JSON serializable' % (repr(python_object), type(python_object)))
+    raise TypeError('%s %s is not JSON serializable' % (repr(python_object), type(python_object)))
 
 def json_dumps(obj):
     indent = 2
@@ -52,14 +52,14 @@ def trim(docstring):
     # and split into a list of lines:
     lines = docstring.expandtabs().splitlines()
     # Determine minimum indentation (first line doesn't count):
-    indent = sys.maxint
+    indent = sys.maxsize
     for line in lines[1:]:
         stripped = line.lstrip()
         if stripped:
             indent = min(indent, len(line) - len(stripped))
     # Remove indentation (first line is special):
     trimmed = [lines[0].strip()]
-    if indent < sys.maxint:
+    if indent < sys.maxsize:
         for line in lines[1:]:
             trimmed.append(line[indent:].rstrip())
     # Strip off trailing and leading blank lines:
@@ -78,11 +78,11 @@ def defaultcontext():
 def api_task(context, request, callback):
     if context == None:
         context = defaultcontext
-    action = request.arguments.get('action', [None])[0]
-    data = request.arguments.get('data', ['{}'])[0]
-    data = json.loads(data) if data else {}
+    action = request.arguments.get('action', [None])[0].decode('utf-8')
+    data = request.arguments.get('data', [b'{}'])[0]
+    data = json.loads(data.decode('utf-8')) if data else {}
     if not action:
-        methods = actions.keys()
+        methods = list(actions.keys())
         api = []
         for f in sorted(methods):
             api.append({'name': f,
@@ -154,7 +154,7 @@ class ApiActions(dict):
             data = data or {}
             docs = data.get('docs', False)
             code = data.get('code', False)
-            _actions = self.keys()
+            _actions = list(self.keys())
             _actions.sort()
             actions = {}
             for a in _actions:
@@ -172,16 +172,16 @@ class ApiActions(dict):
 
     def code(self, name, version=None):
         f = self[name]
-        if name != 'api' and hasattr(f, 'func_closure') and f.func_closure:
-            fc = filter(lambda c: hasattr(c.cell_contents, '__call__'), f.func_closure)
+        if name != 'api' and hasattr(f, 'func_closure') and f.__closure__:
+            fc = [c for c in f.__closure__ if hasattr(c.cell_contents, '__call__')]
             f = fc[len(fc)-1].cell_contents 
-        info = f.func_code.co_filename
-        info = u'%s:%s' % (info, f.func_code.co_firstlineno)
+        info = f.__code__.co_filename
+        info = '%s:%s' % (info, f.__code__.co_firstlineno)
         return info, trim(inspect.getsource(f))
 
     def register(self, method, action=None, cache=True, version=None):
         if not action:
-            action = method.func_name
+            action = method.__name__
         if version:
             if not version in self.versions:
                 self.versions[version] = {}
diff --git a/oml/queryparser.py b/oml/queryparser.py
index a7a850c..3dc1f1d 100644
--- a/oml/queryparser.py
+++ b/oml/queryparser.py
@@ -101,7 +101,7 @@ class Parser(object):
                 q = ~q
             return q
         elif key_type in (1: @@ -208,7 +215,7 @@ def remove_empty_tree(leaf): else: break -utc_0 = int(time.mktime(datetime(1970, 01, 01).timetuple())) +utc_0 = int(time.mktime(datetime(1970, 0o1, 0o1).timetuple())) def datetime2ts(dt): return int(time.mktime(dt.utctimetuple())) - utc_0 diff --git a/oml/websocket.py b/oml/websocket.py index 3836a84..e090c20 100644 --- a/oml/websocket.py +++ b/oml/websocket.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # vi:si:et:sw=4:sts=4:ts=4 -from __future__ import division + from tornado.websocket import WebSocketHandler from tornado.ioloop import IOLoop diff --git a/requirements.txt b/requirements.txt index 134b16e..4b56c22 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -Twisted simplejson ed25519 -SQLAlchemy==0.9.4 -pyopenssl>=0.13.1 +SQLAlchemy==0.9.7 +pyopenssl>=0.14 +pillow