diff --git a/redistimeseries/client.py b/redistimeseries/client.py index c493768..db27475 100644 --- a/redistimeseries/client.py +++ b/redistimeseries/client.py @@ -1,12 +1,20 @@ from redis import Redis from redis.client import Pipeline from redis.client import bool_ok -from redis._compat import nativestr +import six + +def to_string(s): + if isinstance(s, six.string_types): + return s + elif isinstance(s, six.binary_type): + return s.decode('utf-8') + else: + return s # Not a string we care about class TSInfo(object): rules = [] labels = [] - sourceKey = None + source_key = None chunk_count = None memory_usage = None total_samples = None @@ -15,21 +23,45 @@ class TSInfo(object): first_time_stamp = None max_samples_per_chunk = None + def parse_rules(self, rules): + if rules != []: + for rule in rules: + rule[0] = to_string(rule[0]) + rule[2] = to_string(rule[2]) + return rules + def __init__(self, args): - response = dict(zip(map(nativestr, args[::2]), args[1::2])) - self.rules = response['rules'] - self.sourceKey = response['sourceKey'] - self.chunkCount = response['chunkCount'] + response = dict(zip(map(to_string, args[::2]), map(to_string, args[1::2]))) + self.rules = self.parse_rules(response['rules']) + self.source_key = response['sourceKey'] + self.chunk_count = response['chunkCount'] self.memory_usage = response['memoryUsage'] self.total_samples = response['totalSamples'] self.labels = list_to_dict(response['labels']) self.retention_msecs = response['retentionTime'] - self.lastTimeStamp = response['lastTimestamp'] + self.last_time_stamp = response['lastTimestamp'] self.first_time_stamp = response['firstTimestamp'] - self.maxSamplesPerChunk = response['maxSamplesPerChunk'] + self.max_samples_per_chunk = response['maxSamplesPerChunk'] + + # backwards support + @property + def sourceKey(self): + return self.source_key + + @property + def chunkCount(self): + return self.chunk_count + + @property + def lastTimestamp(self): + return self.last_time_stamp + + @property + def maxSamplesPerChunk(self): + return self.max_samples_per_chunk def list_to_dict(aList): - return {nativestr(aList[i][0]):nativestr(aList[i][1]) + return {to_string(aList[i][0]):to_string(aList[i][1]) for i in range(len(aList))} def parse_range(response): @@ -38,7 +70,7 @@ def parse_range(response): def parse_m_range(response): res = [] for item in response: - res.append({ nativestr(item[0]) : [list_to_dict(item[1]), + res.append({ to_string(item[0]) : [list_to_dict(item[1]), parse_range(item[2])]}) return res @@ -51,9 +83,9 @@ def parse_m_get(response): res = [] for item in response: if item[2] == []: - res.append({ nativestr(item[0]) : [list_to_dict(item[1]), None, None]}) + res.append({ to_string(item[0]) : [list_to_dict(item[1]), None, None]}) else: - res.append({ nativestr(item[0]) : [list_to_dict(item[1]), + res.append({ to_string(item[0]) : [list_to_dict(item[1]), int(item[2][0]), float(item[2][1])]}) return res @@ -61,7 +93,7 @@ def parse_m_get(response): def parseToList(response): res = [] for item in response: - res.append(nativestr(item)) + res.append(to_string(item)) return res class Client(Redis): #changed from StrictRedis diff --git a/requirements.txt b/requirements.txt index 055b5ca..558f870 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ hiredis>=0.2.0 redis>=2.10 rmtest>=0.2 +six>=1.10.0 diff --git a/test_commands.py b/test_commands.py index dcb1969..5d0aa2f 100644 --- a/test_commands.py +++ b/test_commands.py @@ -193,7 +193,7 @@ def testPipeline(self): pipeline.execute() info = rts.info('with_pipeline') - self.assertEqual(info.lastTimeStamp, 99) + self.assertEqual(info.last_time_stamp, 99) self.assertEqual(info.total_samples, 100) self.assertEqual(rts.get('with_pipeline')[1], 99 * 1.1) @@ -205,5 +205,42 @@ def testUncompressed(self): uncompressed_info = rts.info('uncompressed') self.assertNotEqual(compressed_info.memory_usage, uncompressed_info.memory_usage) + def testInfo(self): + rts.create('info_series', retention_msecs=3600000, labels={'Test':'This', 'Taste':'That'}) + rts.create('avg_series', retention_msecs=3600000, labels={'Something':'Else'}) + rts.createrule('info_series','avg_series', 'AVG', 20) + for i in range(102): + rts.add('info_series', i, 1.1 * i) + + info_src = rts.info('info_series') + self.assertEqual(info_src.source_key, None) + self.assertEqual(info_src.chunk_count, 1) + self.assertEqual(info_src.memory_usage, 4293) + self.assertEqual(info_src.total_samples, 102) + self.assertEqual(info_src.retention_msecs, 3600000) + self.assertEqual(info_src.last_time_stamp, 101) + self.assertEqual(info_src.first_time_stamp, 0) + self.assertEqual(info_src.max_samples_per_chunk, 256) + self.assertEqual(info_src.rules, [['avg_series', 20, 'AVG']]) + self.assertEqual(info_src.labels, {'Test': 'This', 'Taste': 'That'}) + + info_avg = rts.info('avg_series') + self.assertEqual(info_avg.source_key, 'info_series') + self.assertEqual(info_avg.chunk_count, 1) + self.assertEqual(info_avg.memory_usage, 4215) + self.assertEqual(info_avg.total_samples, 5) + self.assertEqual(info_avg.retention_msecs, 3600000) + self.assertEqual(info_avg.last_time_stamp, 80) + self.assertEqual(info_avg.first_time_stamp, 0) + self.assertEqual(info_avg.max_samples_per_chunk, 256) + self.assertEqual(info_avg.rules, []) + self.assertEqual(info_avg.labels, {'Something':'Else'}) + + # check support for camelback vars + self.assertEqual(info_avg.sourceKey, 'info_series') + self.assertEqual(info_avg.chunkCount, 1) + self.assertEqual(info_avg.lastTimestamp, 80) + self.assertEqual(info_avg.maxSamplesPerChunk, 256) + if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main()