From 28eeae465c22b4362dad3e77c8fcc21833b25407 Mon Sep 17 00:00:00 2001 From: Joel Griffith Date: Fri, 22 May 2015 17:37:12 -0400 Subject: [PATCH] Add support for Python 3 --- pydruid/client.py | 39 +++++++++++++++++++----------------- pydruid/utils/aggregators.py | 6 +++--- pydruid/utils/query_utils.py | 4 ++-- setup.py | 1 + 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/pydruid/client.py b/pydruid/client.py index 02ad08e2..af0ff953 100755 --- a/pydruid/client.py +++ b/pydruid/client.py @@ -14,20 +14,22 @@ # limitations under the License. # from __future__ import division -import urllib2 +from __future__ import absolute_import + +from six import iteritems +from six.moves import urllib try: import pandas except ImportError: - print 'Warning: unable to import Pandas. The export_pandas method will not work.' + print('Warning: unable to import Pandas. The export_pandas method will not work.') pass -from utils.aggregators import * -from utils.postaggregator import * -from utils.filters import * -from utils.having import * -from utils.query_utils import * - +from .utils.aggregators import * +from .utils.postaggregator import * +from .utils.filters import * +from .utils.having import * +from .utils.query_utils import * class PyDruid: """ @@ -106,23 +108,24 @@ def __init__(self, url, endpoint): def __post(self, query): try: - querystr = json.dumps(query) + querystr = json.dumps(query).encode('ascii') if self.url.endswith('/'): url = self.url + self.endpoint else: url = self.url + '/' + self.endpoint headers = {'Content-Type': 'application/json'} - req = urllib2.Request(url, querystr, headers) - res = urllib2.urlopen(req) + req = urllib.request.Request(url, querystr, headers) + res = urllib.request.urlopen(req) data = res.read() self.result_json = data res.close() - except urllib2.HTTPError, e: + except urllib.error.HTTPError: + _, e, _ = sys.exc_info() err=None if e.code==500: # has Druid returned an error? try: - err= json.loads(e.read()) + err= json.loads(e.read()) except ValueError: pass else: @@ -244,7 +247,7 @@ def export_pandas(self): """ if self.result: if self.query_type == "timeseries": - nres = [v['result'].items() + [('timestamp', v['timestamp'])] + nres = [list(v['result'].items()) + [('timestamp', v['timestamp'])] for v in self.result] nres = [dict(v) for v in nres] elif self.query_type == "topN": @@ -252,11 +255,11 @@ def export_pandas(self): for item in self.result: timestamp = item['timestamp'] results = item['result'] - tres = [dict(res.items() + [('timestamp', timestamp)]) + tres = [dict(list(res.items()) + [('timestamp', timestamp)]) for res in results] nres += tres elif self.query_type == "groupBy": - nres = [v['event'].items() + [('timestamp', v['timestamp'])] + nres = [list(v['event'].items()) + [('timestamp', v['timestamp'])] for v in self.result] nres = [dict(v) for v in nres] else: @@ -280,7 +283,7 @@ def validate_query(self, valid_parts, args): :raise ValueError: if an invalid object is given """ valid_parts = valid_parts[:] + ['context'] - for key, val in args.iteritems(): + for key, val in iteritems(args): if key not in valid_parts: raise ValueError( 'Query component: {0} is not valid for query type: {1}.' @@ -291,7 +294,7 @@ def validate_query(self, valid_parts, args): def build_query(self, args): query_dict = {'queryType': self.query_type} - for key, val in args.iteritems(): + for key, val in iteritems(args): if key == 'aggregations': query_dict[key] = build_aggregators(val) elif key == 'post_aggregations': diff --git a/pydruid/utils/aggregators.py b/pydruid/utils/aggregators.py index 6f023692..68ef4c96 100644 --- a/pydruid/utils/aggregators.py +++ b/pydruid/utils/aggregators.py @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # - +from six import iteritems def longsum(raw_metric): return {"type": "longSum", "fieldName": raw_metric} @@ -38,5 +38,5 @@ def hyperunique(raw_metric): return {"type": "hyperUnique", "fieldName": raw_metric} def build_aggregators(agg_input): - return [dict([('name', k)] + v.items()) - for (k, v) in agg_input.iteritems()] + return [dict([('name', k)] + list(v.items())) + for (k, v) in iteritems(agg_input)] diff --git a/pydruid/utils/query_utils.py b/pydruid/utils/query_utils.py index 00eda635..c7b77bcf 100644 --- a/pydruid/utils/query_utils.py +++ b/pydruid/utils/query_utils.py @@ -15,7 +15,7 @@ # import csv import codecs -import cStringIO +from six import StringIO # A special CSV writer which will write rows to TSV file "f", which is encoded in utf-8. # this is necessary because the values in druid are not all ASCII. @@ -26,7 +26,7 @@ class UnicodeWriter: # delimiter="\t" def __init__(self, f, dialect="excel-tab", encoding="utf-8", **kwds): # Redirect output to a queue - self.queue = cStringIO.StringIO() + self.queue = StringIO() self.writer = csv.writer(self.queue, dialect=dialect, **kwds) self.stream = f self.encoder = codecs.getincrementalencoder(encoding)() diff --git a/setup.py b/setup.py index 3852ba1f..c008b5e1 100644 --- a/setup.py +++ b/setup.py @@ -12,5 +12,6 @@ long_description='See https://github.com/metamx/pydruid for more information.', install_requires=[ "simplejson >= 3.3.0", + "six >= 1.9.0", ], )