From fc16931e39015b27b96e4cb9bbb44645ea87ed6f Mon Sep 17 00:00:00 2001 From: z4r <24erre@gmail.com> Date: Wed, 11 Sep 2013 16:19:30 +0200 Subject: [PATCH 1/5] testable redis client --- .gitignore | 1 + reding/resources.py | 60 +++++++++++++++++------------------ reding/settings.py | 12 +------ reding/tests/documentation.py | 13 ++++++-- reding/tests/utils.py | 6 ---- 5 files changed, 41 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index eb7cc2c..68fd9dc 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Reding.egg-info/ .cache/ .coverage VENV/ +.idea/ diff --git a/reding/resources.py b/reding/resources.py index 4e40a35..4a717f4 100644 --- a/reding/resources.py +++ b/reding/resources.py @@ -67,8 +67,6 @@ def get_key_name(template, **kw): class RedingResource(restful.Resource): - - redis = rclient parser_cls = reqparse.RequestParser def __init__(self): @@ -96,7 +94,7 @@ def get(self): sort = '-' if sort == '+': - amounts = self.redis.zrangebyscore( + amounts = rclient.zrangebyscore( get_object_key_name(**args), '-inf', '+inf', @@ -105,7 +103,7 @@ def get(self): num=args['size'], ) else: - amounts = self.redis.zrevrangebyscore( + amounts = rclient.zrevrangebyscore( get_object_key_name(**args), '+inf', '-inf', @@ -117,7 +115,7 @@ def get(self): reply = [] for o, a in amounts: args['object_id'] = o - n = self.redis.zcount( + n = rclient.zcount( get_user_object_key_name( **args ), @@ -162,15 +160,15 @@ def post(self): tmp_key = '{0}:tmp:{1}'.format(get_object_key_name(**args), int(time())) tmp_dest_key = '{0}:tmp_dest:{1}'.format(get_object_key_name(**args), int(time())) - self.redis.sadd(tmp_key, *objects) - self.redis.zinterstore(tmp_dest_key, (get_object_key_name(**args), tmp_key), aggregate='SUM') + rclient.sadd(tmp_key, *objects) + rclient.zinterstore(tmp_dest_key, (get_object_key_name(**args), tmp_key), aggregate='SUM') if sort == '+': - sorted = self.redis.zrangebyscore(tmp_dest_key, '-inf', '+inf') + sorted = rclient.zrangebyscore(tmp_dest_key, '-inf', '+inf') else: - sorted = self.redis.zrevrangebyscore(tmp_dest_key, '+inf', '-inf') + sorted = rclient.zrevrangebyscore(tmp_dest_key, '+inf', '-inf') - self.redis.delete(tmp_key, tmp_dest_key) + rclient.delete(tmp_key, tmp_dest_key) sorted_set = set(sorted) object_set = set(objects) @@ -187,7 +185,7 @@ def get(self, object_id): vote = args['vote'] - amount = self.redis.zscore( + amount = rclient.zscore( get_object_key_name(**args), object_id, ) @@ -198,7 +196,7 @@ def get(self, object_id): min_vote = vote max_vote = vote - number = self.redis.zcount( + number = rclient.zcount( get_user_object_key_name( object_id=object_id, **args @@ -257,7 +255,7 @@ def get(self, object_id): end = vote if sort == '+': - votes = self.redis.zrangebyscore( + votes = rclient.zrangebyscore( get_user_object_key_name( object_id=object_id, **args @@ -269,7 +267,7 @@ def get(self, object_id): num=args['size'], ) else: - votes = self.redis.zrevrangebyscore( + votes = rclient.zrevrangebyscore( get_user_object_key_name( object_id=object_id, **args @@ -287,7 +285,7 @@ def get(self, object_id): user_id=u, vote=v, when=datetime.fromtimestamp( - self.redis.zscore( + rclient.zscore( get_user_key_name( user_id=u, **args @@ -319,7 +317,7 @@ def get(self, user_id): sort = '-' if sort == '+': - votetimes = self.redis.zrangebyscore( + votetimes = rclient.zrangebyscore( get_user_key_name( user_id=user_id, **args @@ -331,7 +329,7 @@ def get(self, user_id): num=args['size'], ) else: - votetimes = self.redis.zrevrangebyscore( + votetimes = rclient.zrevrangebyscore( get_user_key_name( user_id=user_id, **args @@ -347,7 +345,7 @@ def get(self, user_id): get_user_object_reply( object_id=o, user_id=user_id, - vote=self.redis.zscore( + vote=rclient.zscore( get_user_object_key_name( object_id=o, **args @@ -355,7 +353,7 @@ def get(self, user_id): user_id, ), when=datetime.fromtimestamp( - self.redis.zscore( + rclient.zscore( get_user_key_name( user_id=user_id, **args @@ -375,7 +373,7 @@ class VoteSummaryResource(RedingResource): def get(self, object_id, user_id): args = self.parser.parse_args() - vote = self.redis.zscore( + vote = rclient.zscore( get_user_object_key_name( object_id=object_id, **args @@ -383,7 +381,7 @@ def get(self, object_id, user_id): user_id, ) - when_ts = self.redis.zscore( + when_ts = rclient.zscore( get_user_key_name( user_id=user_id, **args @@ -419,7 +417,7 @@ def put(self, object_id, user_id): self._perform_correction(object_id, user_id, next_vote, args) - self.redis.zadd( + rclient.zadd( get_user_object_key_name( object_id=object_id, **args @@ -428,7 +426,7 @@ def put(self, object_id, user_id): user_id, ) - self.redis.zadd( + rclient.zadd( get_user_key_name( user_id=user_id, **args @@ -440,7 +438,7 @@ def put(self, object_id, user_id): return get_user_object_reply( object_id=object_id, user_id=user_id, - vote=self.redis.zscore( + vote=rclient.zscore( get_user_object_key_name( object_id=object_id, **args @@ -448,7 +446,7 @@ def put(self, object_id, user_id): user_id, ), when=datetime.fromtimestamp( - self.redis.zscore( + rclient.zscore( get_user_key_name( user_id=user_id, **args @@ -464,7 +462,7 @@ def delete(self, object_id, user_id): next_vote = 0 self._perform_correction(object_id, user_id, next_vote, args) - self.redis.zrem( + rclient.zrem( get_user_key_name( user_id=user_id, **args @@ -472,7 +470,7 @@ def delete(self, object_id, user_id): object_id, ) - self.redis.zrem( + rclient.zrem( get_user_object_key_name( object_id=object_id, **args @@ -483,7 +481,7 @@ def delete(self, object_id, user_id): return '', 204 def _perform_correction(self, object_id, user_id, next_vote, args): - prev_vote = self.redis.zscore( + prev_vote = rclient.zscore( get_user_object_key_name( object_id=object_id, **args @@ -498,19 +496,19 @@ def _perform_correction(self, object_id, user_id, next_vote, args): # perform vote correction in `all apps` zset if correction: - self.redis.zincrby( + rclient.zincrby( get_object_key_name(**args), object_id, correction, ) - amount = self.redis.zscore( + amount = rclient.zscore( get_object_key_name(**args), object_id, ) if not amount and amount == 0: - self.redis.zrem( + rclient.zrem( get_object_key_name(**args), object_id, ) diff --git a/reding/settings.py b/reding/settings.py index 1709f8d..c04959d 100644 --- a/reding/settings.py +++ b/reding/settings.py @@ -1,5 +1,4 @@ import redis - import os REDIS_CONFIG = { @@ -8,16 +7,7 @@ 'db': int(os.getenv('REDING_REDIS_DB', 0)), } -TEST_REDIS_CONFIG = { - 'host': os.getenv('REDING_TEST_REDIS_HOST', 'localhost'), - 'port': int(os.getenv('REDING_TEST_REDIS_PORT', 6379)), - 'db': int(os.getenv('REDING_TEST_REDIS_DB', 15)), -} - -if 'unittest' in globals(): - rclient = redis.StrictRedis(**TEST_REDIS_CONFIG) -else: - rclient = redis.StrictRedis(**REDIS_CONFIG) +rclient = redis.StrictRedis(**REDIS_CONFIG) DAEMON_CONFIG = { 'host': os.getenv('REDING_DAEMON_HOST', '0.0.0.0'), diff --git a/reding/tests/documentation.py b/reding/tests/documentation.py index cc4a3d2..fafbbe8 100644 --- a/reding/tests/documentation.py +++ b/reding/tests/documentation.py @@ -1,12 +1,19 @@ -from reding.tests.utils import RedingTestCase - +import os import json +import redis +from reding import resources +from reding.tests.utils import RedingTestCase +resources.rclient = redis.StrictRedis( + host=os.getenv('REDING_TEST_REDIS_HOST', 'localhost'), + port=int(os.getenv('REDING_TEST_REDIS_PORT', 6379)), + db=int(os.getenv('REDING_TEST_REDIS_DB', 15)), +) class RedingDocumentationTestCase(RedingTestCase): def test_00_voted_list_resource_empty(self): - self.redis.flushdb() + resources.rclient.flushdb() response = self.assert_get('/objects/') self.assertEqual(json.loads(response.data), []) diff --git a/reding/tests/utils.py b/reding/tests/utils.py index 5ba799b..51bb9b2 100644 --- a/reding/tests/utils.py +++ b/reding/tests/utils.py @@ -1,12 +1,8 @@ from reding.app import app -from reding.settings import rclient - import unittest import json -import redis from datetime import datetime from dateutil import parser as dtparser -import pytz class RedingTestCase(unittest.TestCase): @@ -16,7 +12,6 @@ class RedingTestCase(unittest.TestCase): def __init__(self, methodName='runTest'): super(RedingTestCase, self).__init__(methodName) self.app = app.test_client() - self.redis = rclient def assert_get(self, url): r = self.app.get(url) @@ -41,7 +36,6 @@ def assert_post_or_put(self, url, headers, data, put=False): return r def _check_post(self, response, object_id, user_id, vote): - now = datetime.utcnow().replace(tzinfo=pytz.utc) resp = json.loads(response.data) self.assertEqual(resp['object_id'], object_id) self.assertEqual(resp['user_id'], user_id) From f0f8afa30b38f5a9f13998718369eedae9d567a5 Mon Sep 17 00:00:00 2001 From: z4r <24erre@gmail.com> Date: Thu, 12 Sep 2013 11:37:54 +0200 Subject: [PATCH 2/5] ...and refactoring for all --- reding/__init__.py | 4 +- reding/managers.py | 151 +++++++++++++ reding/resources.py | 403 +++++++--------------------------- reding/tests/documentation.py | 6 +- 4 files changed, 231 insertions(+), 333 deletions(-) create mode 100644 reding/managers.py diff --git a/reding/__init__.py b/reding/__init__.py index 2945f43..39b04ec 100644 --- a/reding/__init__.py +++ b/reding/__init__.py @@ -33,7 +33,9 @@ if __name__ == '__main__': from reding.app import app from reding.settings import DAEMON_CONFIG - # app.run(debug=True, port=5001); import sys; sys.exit() + app.run(debug=True, port=5001) + import sys + sys.exit() from cherrypy import wsgiserver w = wsgiserver.WSGIPathInfoDispatcher({'/': app.wsgi_app}) diff --git a/reding/managers.py b/reding/managers.py new file mode 100644 index 0000000..279351b --- /dev/null +++ b/reding/managers.py @@ -0,0 +1,151 @@ +from datetime import datetime +from reding.settings import KEY_CONFIG, rclient + + +def get_key_name(template, **kw): + d = KEY_CONFIG.copy() + d.update(dict((key, value) for (key, value) in kw.iteritems() if value)) + return template.format(**d) + + +class ObjectSubjectsManager(object): + def __init__(self, **kwargs): + self.template = get_key_name('{prefix}:{object}:{{object_id}}:{subjects}', **kwargs) + + def count(self, object_id, min_vote='-inf', max_vote='+inf'): + return rclient.zcount( + name=self.template.format(object_id=object_id), + min=min_vote, + max=max_vote, + ) + + def scoredrange(self, object_id, offset, size, min_vote='-inf', max_vote='+inf', reverse=False): + func = rclient.zrangebyscore + if reverse: + func = rclient.zrevrangebyscore + min_vote, max_vote = max_vote, min_vote + return func( + name=self.template.format(object_id=object_id), + min=min_vote, + max=max_vote, + start=offset, + num=size, + withscores=True, + ) + + def score(self, object_id, user_id): + return rclient.zscore( + name=self.template.format(object_id=object_id), + value=user_id, + ) + + def create(self, object_id, user_id, vote): + rclient.zadd( + self.template.format(object_id=object_id), + vote, + user_id, + ) + + def remove(self, object_id, user_id): + rclient.zrem( + self.template.format(object_id=object_id), + user_id, + ) + + +class SubjectObjectsManager(object): + def __init__(self, **kwargs): + self.template = get_key_name('{prefix}:{subject}:{{user_id}}:{objects}', **kwargs) + + def scoredrange(self, user_id, offset, size, min_vote='-inf', max_vote='+inf', reverse=False): + func = rclient.zrangebyscore + if reverse: + func = rclient.zrevrangebyscore + min_vote, max_vote = max_vote, min_vote + return func( + name=self.template.format(user_id=user_id), + min=min_vote, + max=max_vote, + start=offset, + num=size, + withscores=True, + ) + + def score(self, user_id, object_id): + try: + return datetime.fromtimestamp(rclient.zscore( + name=self.template.format(user_id=user_id), + value=object_id, + )) + except TypeError: + return 0 + + def create(self, user_id, object_id, ts): + rclient.zadd( + self.template.format(user_id=user_id), + ts, + object_id, + ) + + def remove(self, user_id, object_id): + rclient.zrem( + self.template.format(user_id=user_id), + object_id, + ) + + +class ObjectsManager(object): + def __init__(self, **kwargs): + self.template = get_key_name('{prefix}:{objects}', **kwargs) + + def scoredrange(self, offset, size, min_vote='-inf', max_vote='+inf', reverse=False): + func = rclient.zrangebyscore + if reverse: + func = rclient.zrevrangebyscore + min_vote, max_vote = max_vote, min_vote + return func( + name=self.template, + min=min_vote, + max=max_vote, + start=offset, + num=size, + withscores=True, + ) + + def score(self, object_id): + return rclient.zscore( + name=self.template, + value=object_id, + ) + + def incrby(self, object_id, delta): + rclient.zincrby( + name=self.template, + value=object_id, + amount=delta, + ) + + def remove(self, object_id): + rclient.zrem( + self.template, + object_id, + ) + + def filtered(self, objects, now, reverse): + if not objects: + return [] + + tmp_key = '{0}:tmp:{1}'.format(self.template, now) + tmp_dest_key = '{0}:tmp_dest:{1}'.format(self.template, now) + + rclient.sadd(tmp_key, *objects) + rclient.zinterstore(tmp_dest_key, (self.template, tmp_key), aggregate='SUM') + + if reverse: + zsorted = rclient.zrevrangebyscore(tmp_dest_key, '+inf', '-inf') + else: + zsorted = rclient.zrangebyscore(tmp_dest_key, '-inf', '+inf') + + rclient.delete(tmp_key, tmp_dest_key) + + return zsorted + list(set(objects).difference(set(zsorted))) diff --git a/reding/resources.py b/reding/resources.py index 4a717f4..1886a9e 100644 --- a/reding/resources.py +++ b/reding/resources.py @@ -1,4 +1,5 @@ -from reding.settings import KEY_CONFIG, rclient +from reding.managers import ObjectSubjectsManager, SubjectObjectsManager, ObjectsManager +from reding.settings import KEY_CONFIG from reding.settings import PAGINATION_DEFAULT_OFFSET as OFFSET from reding.settings import PAGINATION_DEFAULT_SIZE as SIZE @@ -6,7 +7,6 @@ from flask.ext import restful from time import time -from datetime import datetime def add_vote_arg(parser, required=False): @@ -27,30 +27,6 @@ def get_user_object_reply(object_id, user_id, vote, when): } -def get_user_key_name(**kw): - t = "{prefix}:{subject}:{user_id}:{objects}" - return get_key_name(t, **kw) - - -def get_object_key_name(**kw): - t = "{prefix}:{objects}" - return get_key_name(t, **kw) - - -def get_user_object_key_name(**kw): - t = "{prefix}:{object}:{object_id}:{subjects}" - return get_key_name(t, **kw) - - -def get_key_name(template, **kw): - kw = dict((key, value) for (key, value) in kw.iteritems() if value) - - d = KEY_CONFIG.copy() - d.update(kw) - - return template.format(**d) - - object_resource_fields = { 'votes_no': fields.Integer, 'amount': fields.Integer, @@ -76,7 +52,6 @@ def __init__(self): class VotedListResource(RedingResource): - def __init__(self): super(VotedListResource, self).__init__() self.parser.add_argument('object_id', type=str, action='append') @@ -88,55 +63,25 @@ def __init__(self): def get(self): args = self.parser.parse_args() - sort = '+' - if args['sort'] in ('-', '+'): - if args['sort'] == '-': - sort = '-' - - if sort == '+': - amounts = rclient.zrangebyscore( - get_object_key_name(**args), - '-inf', - '+inf', - withscores=True, - start=args['offset'], - num=args['size'], - ) - else: - amounts = rclient.zrevrangebyscore( - get_object_key_name(**args), - '+inf', - '-inf', - withscores=True, - start=args['offset'], - num=args['size'], - ) + amounts = ObjectsManager(**args).scoredrange( + offset=args['offset'], + size=args['size'], + reverse=args['sort'] == '-', + ) reply = [] - for o, a in amounts: - args['object_id'] = o - n = rclient.zcount( - get_user_object_key_name( - **args - ), - '-inf', - '+inf', - ) - - average = 0 - if n: - average = a / n - - # skipping objects with zero votes + osmanager = ObjectSubjectsManager(**args) + for object_id, amount in amounts: + votes_no = osmanager.count(object_id=object_id) + if votes_no: # skipping objects with no votes reply.append( dict( - votes_no=n, - average=average, - amount=a, - object_id=o, + votes_no=votes_no, + average=amount / votes_no, + amount=amount, + object_id=object_id, ) ) - return reply def post(self): @@ -147,37 +92,14 @@ def post(self): """ args = self.parser.parse_args() - sort = '+' - if args['sort'] in ('-', '+'): - if args['sort'].startswith('-'): - sort = '-' - - objects = args['object_id'] - - if not objects: - return [] - - tmp_key = '{0}:tmp:{1}'.format(get_object_key_name(**args), int(time())) - tmp_dest_key = '{0}:tmp_dest:{1}'.format(get_object_key_name(**args), int(time())) - - rclient.sadd(tmp_key, *objects) - rclient.zinterstore(tmp_dest_key, (get_object_key_name(**args), tmp_key), aggregate='SUM') - - if sort == '+': - sorted = rclient.zrangebyscore(tmp_dest_key, '-inf', '+inf') - else: - sorted = rclient.zrevrangebyscore(tmp_dest_key, '+inf', '-inf') - - rclient.delete(tmp_key, tmp_dest_key) - - sorted_set = set(sorted) - object_set = set(objects) - - return sorted + list(object_set.difference(sorted_set)) + return ObjectsManager(**args).filtered( + objects=args['object_id'], + now=int(time()), + reverse=args['sort'] == '-', + ) class VotedSummaryResource(RedingResource): - @marshal_with(object_resource_fields) def get(self, object_id): add_vote_arg(self.parser) @@ -185,40 +107,26 @@ def get(self, object_id): vote = args['vote'] - amount = rclient.zscore( - get_object_key_name(**args), - object_id, - ) + amount = ObjectsManager(**args).score(object_id=object_id) or 0 - min_vote = '-inf' - max_vote = '+inf' - if vote: - min_vote = vote - max_vote = vote - - number = rclient.zcount( - get_user_object_key_name( - object_id=object_id, - **args - ), - min_vote, - max_vote, + votes_no = ObjectSubjectsManager(**args).count( + object_id=object_id, + min_vote=vote or '-inf', + max_vote=vote or '+inf', ) - if not amount: - amount = 0 # FIXME can test this line with a single vote=0 to a new object - if not number: + if not votes_no: average = 0 amount = 0 elif vote: average = vote - amount = vote * number + amount = vote * votes_no else: - average = amount / number + average = amount / votes_no return ( dict( - votes_no=number, + votes_no=votes_no, average=average, amount=amount, object_id=object_id, @@ -227,7 +135,6 @@ def get(self, object_id): class VotingUserListResource(RedingResource): - def __init__(self): super(VotingUserListResource, self).__init__() self.parser.add_argument('sort', type=str, default='+') @@ -239,68 +146,27 @@ def __init__(self): def get(self, object_id): args = self.parser.parse_args() - sort = '+' - start = '-inf' - end = '+inf' - if args['sort'] in ('-', '+'): - if args['sort'].startswith('-'): - sort = '-' - start = '+inf' - end = '-inf' - - vote = args['vote'] - - if vote: - start = vote - end = vote - - if sort == '+': - votes = rclient.zrangebyscore( - get_user_object_key_name( - object_id=object_id, - **args - ), - start, - end, - withscores=True, - start=args['offset'], - num=args['size'], - ) - else: - votes = rclient.zrevrangebyscore( - get_user_object_key_name( - object_id=object_id, - **args - ), - start, - end, - withscores=True, - start=args['offset'], - num=args['size'], - ) - + votes = ObjectSubjectsManager(**args).scoredrange( + object_id=object_id, + offset=args['offset'], + size=args['size'], + min_vote=args['vote'] or '-inf', + max_vote=args['vote'] or '+inf', + reverse=args['sort'] == '-', + ) + somanager = SubjectObjectsManager(**args) reply = [ get_user_object_reply( object_id=object_id, - user_id=u, - vote=v, - when=datetime.fromtimestamp( - rclient.zscore( - get_user_key_name( - user_id=u, - **args - ), - object_id, - ), - ), - ) for u, v in votes + user_id=user_id, + vote=vote, + when=somanager.score(user_id=user_id, object_id=object_id), + ) for user_id, vote in votes ] - return reply class UserSummaryResource(RedingResource): - def __init__(self): super(UserSummaryResource, self).__init__() self.parser.add_argument('sort', type=str, default='+') @@ -311,98 +177,47 @@ def __init__(self): def get(self, user_id): args = self.parser.parse_args() - sort = '+' - if args['sort'] in ('-', '+'): - if args['sort'].startswith('-'): - sort = '-' - - if sort == '+': - votetimes = rclient.zrangebyscore( - get_user_key_name( - user_id=user_id, - **args - ), - '-inf', - '+inf', - withscores=True, - start=args['offset'], - num=args['size'], - ) - else: - votetimes = rclient.zrevrangebyscore( - get_user_key_name( - user_id=user_id, - **args - ), - '+inf', - '-inf', - withscores=True, - start=args['offset'], - num=args['size'], - ) + somanager = SubjectObjectsManager(**args) + osmanager = ObjectSubjectsManager(**args) + votetimes = somanager.scoredrange( + user_id=user_id, + offset=args['offset'], + size=args['size'], + reverse=args['sort'] == '-', + ) reply = [ get_user_object_reply( - object_id=o, + object_id=object_id, user_id=user_id, - vote=rclient.zscore( - get_user_object_key_name( - object_id=o, - **args - ), - user_id, - ), - when=datetime.fromtimestamp( - rclient.zscore( - get_user_key_name( - user_id=user_id, - **args - ), - o, - ), - ) - ) for o, t in votetimes + vote=osmanager.score(object_id=object_id, user_id=user_id), + when=somanager.score(user_id=user_id, object_id=object_id), + ) for object_id, t in votetimes ] return reply class VoteSummaryResource(RedingResource): - @marshal_with(user_object_resource_fields) def get(self, object_id, user_id): args = self.parser.parse_args() - vote = rclient.zscore( - get_user_object_key_name( - object_id=object_id, - **args - ), - user_id, - ) - - when_ts = rclient.zscore( - get_user_key_name( - user_id=user_id, - **args - ), - object_id, - ) + vote = ObjectSubjectsManager(**args).score(object_id=object_id, user_id=user_id) + when = SubjectObjectsManager(**args).score(user_id=user_id, object_id=object_id) - if not (vote and when_ts): - m = "No vote on {object_id} by {user_id}.".format( + if not (vote and when): + message = "No vote on {object_id} by {user_id}.".format( object_id=object_id, user_id=user_id ) - abort(404, message=m) + abort(404, message=message) return get_user_object_reply( object_id=object_id, user_id=user_id, vote=vote, - when=datetime.fromtimestamp( - when_ts, - ), + when=when, ) def post(self, object_id, user_id): @@ -413,105 +228,35 @@ def put(self, object_id, user_id): add_vote_arg(self.parser, required=True) args = self.parser.parse_args() - next_vote = args['vote'] - - self._perform_correction(object_id, user_id, next_vote, args) - - rclient.zadd( - get_user_object_key_name( - object_id=object_id, - **args - ), - next_vote, - user_id, - ) - - rclient.zadd( - get_user_key_name( - user_id=user_id, - **args - ), - time(), - object_id, - ) + self._perform_correction(object_id, user_id, args['vote'], args) + ObjectSubjectsManager(**args).create(object_id=object_id, user_id=user_id, vote=args['vote']) + SubjectObjectsManager(**args).create(user_id=user_id, object_id=object_id, ts=time()) return get_user_object_reply( object_id=object_id, user_id=user_id, - vote=rclient.zscore( - get_user_object_key_name( - object_id=object_id, - **args - ), - user_id, - ), - when=datetime.fromtimestamp( - rclient.zscore( - get_user_key_name( - user_id=user_id, - **args - ), - object_id, - ), - ) + vote=ObjectSubjectsManager(**args).score(object_id=object_id, user_id=user_id), + when=SubjectObjectsManager(**args).score(user_id=user_id, object_id=object_id), ) def delete(self, object_id, user_id): args = self.parser.parse_args() - next_vote = 0 - self._perform_correction(object_id, user_id, next_vote, args) - - rclient.zrem( - get_user_key_name( - user_id=user_id, - **args - ), - object_id, - ) - - rclient.zrem( - get_user_object_key_name( - object_id=object_id, - **args - ), - user_id, - ) + self._perform_correction(object_id, user_id, 0, args) + SubjectObjectsManager(**args).remove(user_id=user_id, object_id=object_id) + ObjectSubjectsManager(**args).remove(object_id=object_id, user_id=user_id) return '', 204 def _perform_correction(self, object_id, user_id, next_vote, args): - prev_vote = rclient.zscore( - get_user_object_key_name( - object_id=object_id, - **args - ), - user_id, - ) - - if not prev_vote: - prev_vote = 0 - + prev_vote = ObjectSubjectsManager(**args).score(object_id=object_id, user_id=user_id) or 0 correction = next_vote - prev_vote + omanager = ObjectsManager(**args) + omanager.incrby(object_id=object_id, delta=correction) + amount = omanager.score(object_id=object_id) - # perform vote correction in `all apps` zset - if correction: - rclient.zincrby( - get_object_key_name(**args), - object_id, - correction, - ) - - amount = rclient.zscore( - get_object_key_name(**args), - object_id, - ) - - if not amount and amount == 0: - rclient.zrem( - get_object_key_name(**args), - object_id, - ) + if amount == 0: + omanager.remove(object_id=object_id) __all__ = ( 'VotedSummaryResource', diff --git a/reding/tests/documentation.py b/reding/tests/documentation.py index fafbbe8..61f6b47 100644 --- a/reding/tests/documentation.py +++ b/reding/tests/documentation.py @@ -1,9 +1,9 @@ import os import json import redis -from reding import resources +from reding import resources, managers from reding.tests.utils import RedingTestCase -resources.rclient = redis.StrictRedis( +managers.rclient = redis.StrictRedis( host=os.getenv('REDING_TEST_REDIS_HOST', 'localhost'), port=int(os.getenv('REDING_TEST_REDIS_PORT', 6379)), db=int(os.getenv('REDING_TEST_REDIS_DB', 15)), @@ -13,7 +13,7 @@ class RedingDocumentationTestCase(RedingTestCase): def test_00_voted_list_resource_empty(self): - resources.rclient.flushdb() + managers.rclient.flushdb() response = self.assert_get('/objects/') self.assertEqual(json.loads(response.data), []) From f121f5a844f276c6d3da55b5d39b4adb657e050f Mon Sep 17 00:00:00 2001 From: z4r <24erre@gmail.com> Date: Fri, 13 Sep 2013 11:52:09 +0200 Subject: [PATCH 3/5] Reviews for Reding --- README.md | 32 +++++++++----- reding/managers.py | 52 +++++++++++++++------- reding/resources.py | 81 +++++++++++++++++++++-------------- reding/tests/documentation.py | 16 ++++--- reding/tests/utils.py | 3 +- 5 files changed, 119 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index fd8b3d6..7546a89 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,8 @@ Server: mindflayer "vote": 10, "when": "Fri, 01 Feb 2013 17:57:44 -0000", "user_id": "gsalluzzo", - "object_id": "978-0132678209" + "object_id": "978-0132678209", + "review": null } ``` Ehy hackers, I've just used a PUT call, but yes, I know, it's the first vote, I should use a POST one. Reding maps POST method on the PUT one, so the client does not need to know if it's the first time I'm voting this object. @@ -68,7 +69,8 @@ Server: mindflayer "vote": 9, "when": "Fri, 01 Feb 2013 18:03:16 -0000", "user_id": "gsalluzzo", - "object_id": "978-0132678209" + "object_id": "978-0132678209", + "review": null } ``` @@ -104,7 +106,8 @@ Server: mindflayer "vote": 10, "when": "Fri, 01 Feb 2013 18:08:03 -0000", "user_id": "wchun", - "object_id": "978-0132678209" + "object_id": "978-0132678209", + "review": null } ``` The author said '10'! What a surprise! :D @@ -159,7 +162,8 @@ Server: mindflayer "vote": 9, "when": "Fri, 01 Feb 2013 18:03:16 -0000", "user_id": "gsalluzzo", - "object_id": "978-0132678209" + "object_id": "978-0132678209", + "review": null } ``` @@ -187,7 +191,8 @@ Server: mindflayer "vote": 3, "when": "Fri, 01 Feb 2013 18:15:38 -0000", "user_id": "mymom", - "object_id": "978-0132678209" + "object_id": "978-0132678209", + "review": null } ``` @@ -209,9 +214,10 @@ Server: mindflayer } ``` -Well, stop programming books...I'm gonna give a '10' to the amazing 'The Lord of the Rings Sketchbook': +Well, stop programming books...I'm gonna give a '10' to the amazing 'The Lord of the Rings Sketchbook', +but this time let me add a review: ``` -$ curl -i -XPUT http://localhost:5000/objects/978-0618640140/users/gsalluzzo/ -d "vote=10" +$ curl -i -XPUT http://localhost:5000/objects/978-0618640140/users/gsalluzzo/ -d "vote=10&review=LOTR is awesome!" HTTP/1.1 200 OK Content-Type: application/json Content-Length: 110 @@ -223,11 +229,13 @@ Server: mindflayer "vote": 10, "when": "Fri, 01 Feb 2013 18:21:56 -0000", "user_id": "gsalluzzo", - "object_id": "978-0618640140" + "object_id": "978-0618640140", + "review": "LOTR is awesome!" +} } ``` -Let's see the books I voted: +Let's see the books I voted and what I wrote about them: ``` $ curl -i http://localhost:5000/users/gsalluzzo/ HTTP/1.1 200 OK @@ -241,12 +249,14 @@ Server: mindflayer "vote": 9, "when": "Fri, 01 Feb 2013 18:03:16 -0000", "user_id": "gsalluzzo", - "object_id": "978-0132678209" + "object_id": "978-0132678209", + "review": null }, { "vote": 10, "when": "Fri, 01 Feb 2013 18:21:56 -0000", "user_id": "gsalluzzo", - "object_id": "978-0618640140" + "object_id": "978-0618640140", + "review": "LOTR is awesome!" }] ``` diff --git a/reding/managers.py b/reding/managers.py index 279351b..f17f9f9 100644 --- a/reding/managers.py +++ b/reding/managers.py @@ -8,9 +8,17 @@ def get_key_name(template, **kw): return template.format(**d) +def zrange(start, end, reverse): + if not reverse: + return rclient.zrangebyscore, start, end + else: + return rclient.zrevrangebyscore, end, start + + class ObjectSubjectsManager(object): def __init__(self, **kwargs): self.template = get_key_name('{prefix}:{object}:{{object_id}}:{subjects}', **kwargs) + self.template_review = get_key_name('{prefix}:{object}:{{object_id}}:review:{subjects}', **kwargs) def count(self, object_id, min_vote='-inf', max_vote='+inf'): return rclient.zcount( @@ -20,10 +28,7 @@ def count(self, object_id, min_vote='-inf', max_vote='+inf'): ) def scoredrange(self, object_id, offset, size, min_vote='-inf', max_vote='+inf', reverse=False): - func = rclient.zrangebyscore - if reverse: - func = rclient.zrevrangebyscore - min_vote, max_vote = max_vote, min_vote + func, min_vote, max_vote = zrange(min_vote, max_vote, reverse) return func( name=self.template.format(object_id=object_id), min=min_vote, @@ -39,18 +44,38 @@ def score(self, object_id, user_id): value=user_id, ) - def create(self, object_id, user_id, vote): + def review(self, object_id, user_id): + return rclient.hget( + name=self.template_review.format(object_id=object_id), + key=user_id, + ) + + def reviews(self, object_id, *user_ids): + return dict(zip(user_ids, rclient.hmget( + self.template_review.format(object_id=object_id), user_ids + ))) + + def create(self, object_id, user_id, vote, review): rclient.zadd( self.template.format(object_id=object_id), vote, user_id, ) + name = self.template_review.format(object_id=object_id) + if review: + rclient.hset(name,user_id, review) + else: + rclient.hdel(name, user_id) def remove(self, object_id, user_id): rclient.zrem( self.template.format(object_id=object_id), user_id, ) + rclient.hdel( + self.template_review.format(object_id=object_id), + user_id, + ) class SubjectObjectsManager(object): @@ -58,11 +83,8 @@ def __init__(self, **kwargs): self.template = get_key_name('{prefix}:{subject}:{{user_id}}:{objects}', **kwargs) def scoredrange(self, user_id, offset, size, min_vote='-inf', max_vote='+inf', reverse=False): - func = rclient.zrangebyscore - if reverse: - func = rclient.zrevrangebyscore - min_vote, max_vote = max_vote, min_vote - return func( + func, min_vote, max_vote = zrange(min_vote, max_vote, reverse) + scored = func( name=self.template.format(user_id=user_id), min=min_vote, max=max_vote, @@ -70,6 +92,7 @@ def scoredrange(self, user_id, offset, size, min_vote='-inf', max_vote='+inf', r num=size, withscores=True, ) + return [(k, datetime.fromtimestamp(v)) for k, v in scored] def score(self, user_id, object_id): try: @@ -80,10 +103,10 @@ def score(self, user_id, object_id): except TypeError: return 0 - def create(self, user_id, object_id, ts): + def create(self, user_id, object_id, timestamp): rclient.zadd( self.template.format(user_id=user_id), - ts, + timestamp, object_id, ) @@ -99,10 +122,7 @@ def __init__(self, **kwargs): self.template = get_key_name('{prefix}:{objects}', **kwargs) def scoredrange(self, offset, size, min_vote='-inf', max_vote='+inf', reverse=False): - func = rclient.zrangebyscore - if reverse: - func = rclient.zrevrangebyscore - min_vote, max_vote = max_vote, min_vote + func, min_vote, max_vote = zrange(min_vote, max_vote, reverse) return func( name=self.template, min=min_vote, diff --git a/reding/resources.py b/reding/resources.py index 1886a9e..53443ba 100644 --- a/reding/resources.py +++ b/reding/resources.py @@ -9,21 +9,13 @@ from time import time -def add_vote_arg(parser, required=False): - parser.add_argument('vote', type=int, required=required, default=0) - - -def add_config_args(parser): - for k in KEY_CONFIG: - parser.add_argument(k, type=str) - - -def get_user_object_reply(object_id, user_id, vote, when): +def get_user_object_reply(object_id, user_id, vote, when, review): return { 'object_id': object_id, 'user_id': user_id, 'vote': vote, 'when': when, + 'review': review } @@ -36,6 +28,7 @@ def get_user_object_reply(object_id, user_id, vote, when): user_object_resource_fields = { 'vote': fields.Integer, + 'review': fields.String, 'object_id': fields.String, 'user_id': fields.String, 'when': fields.DateTime @@ -48,12 +41,16 @@ class RedingResource(restful.Resource): def __init__(self): super(RedingResource, self).__init__() self.parser = self.parser_cls() - add_config_args(self.parser) + self.configure() + + def configure(self): + for key in KEY_CONFIG: + self.parser.add_argument(key, type=str) class VotedListResource(RedingResource): - def __init__(self): - super(VotedListResource, self).__init__() + def configure(self): + super(VotedListResource, self).configure() self.parser.add_argument('object_id', type=str, action='append') self.parser.add_argument('sort', type=str, default='+') self.parser.add_argument('offset', type=int, default=OFFSET) @@ -100,9 +97,12 @@ def post(self): class VotedSummaryResource(RedingResource): + def configure(self): + super(VotedSummaryResource, self).configure() + self.parser.add_argument('vote', type=int, default=0) + @marshal_with(object_resource_fields) def get(self, object_id): - add_vote_arg(self.parser) args = self.parser.parse_args() vote = args['vote'] @@ -135,18 +135,21 @@ def get(self, object_id): class VotingUserListResource(RedingResource): - def __init__(self): - super(VotingUserListResource, self).__init__() + def configure(self): + super(VotingUserListResource, self).configure() self.parser.add_argument('sort', type=str, default='+') self.parser.add_argument('offset', type=int, default=OFFSET) self.parser.add_argument('size', type=int, default=SIZE) - add_vote_arg(self.parser) + self.parser.add_argument('vote', type=int, default=0) @marshal_with(user_object_resource_fields) def get(self, object_id): args = self.parser.parse_args() - votes = ObjectSubjectsManager(**args).scoredrange( + osmanager = ObjectSubjectsManager(**args) + somanager = SubjectObjectsManager(**args) + + votes = osmanager.scoredrange( object_id=object_id, offset=args['offset'], size=args['size'], @@ -154,21 +157,27 @@ def get(self, object_id): max_vote=args['vote'] or '+inf', reverse=args['sort'] == '-', ) - somanager = SubjectObjectsManager(**args) + + if not votes: + return [] + + reviews = osmanager.reviews(object_id, *[user_id for user_id, _ in votes]) + reply = [ get_user_object_reply( object_id=object_id, user_id=user_id, vote=vote, when=somanager.score(user_id=user_id, object_id=object_id), + review=reviews[user_id], ) for user_id, vote in votes ] return reply class UserSummaryResource(RedingResource): - def __init__(self): - super(UserSummaryResource, self).__init__() + def configure(self): + super(UserSummaryResource, self).configure() self.parser.add_argument('sort', type=str, default='+') self.parser.add_argument('offset', type=int, default=OFFSET) self.parser.add_argument('size', type=int, default=SIZE) @@ -177,8 +186,8 @@ def __init__(self): def get(self, user_id): args = self.parser.parse_args() - somanager = SubjectObjectsManager(**args) osmanager = ObjectSubjectsManager(**args) + somanager = SubjectObjectsManager(**args) votetimes = somanager.scoredrange( user_id=user_id, @@ -191,8 +200,9 @@ def get(self, user_id): object_id=object_id, user_id=user_id, vote=osmanager.score(object_id=object_id, user_id=user_id), - when=somanager.score(user_id=user_id, object_id=object_id), - ) for object_id, t in votetimes + review=osmanager.review(object_id=object_id, user_id=user_id), + when=when, + ) for object_id, when in votetimes ] return reply @@ -203,8 +213,11 @@ class VoteSummaryResource(RedingResource): def get(self, object_id, user_id): args = self.parser.parse_args() - vote = ObjectSubjectsManager(**args).score(object_id=object_id, user_id=user_id) - when = SubjectObjectsManager(**args).score(user_id=user_id, object_id=object_id) + osmanager = ObjectSubjectsManager(**args) + somanager = SubjectObjectsManager(**args) + + vote = osmanager.score(object_id=object_id, user_id=user_id) + when = somanager.score(user_id=user_id, object_id=object_id) if not (vote and when): message = "No vote on {object_id} by {user_id}.".format( @@ -218,6 +231,7 @@ def get(self, object_id, user_id): user_id=user_id, vote=vote, when=when, + review=osmanager.review(object_id=object_id, user_id=user_id), ) def post(self, object_id, user_id): @@ -225,18 +239,23 @@ def post(self, object_id, user_id): @marshal_with(user_object_resource_fields) def put(self, object_id, user_id): - add_vote_arg(self.parser, required=True) + self.parser.add_argument('vote', type=int, required=True) + self.parser.add_argument('review', type=str) args = self.parser.parse_args() + osmanager = ObjectSubjectsManager(**args) + somanager = SubjectObjectsManager(**args) + self._perform_correction(object_id, user_id, args['vote'], args) - ObjectSubjectsManager(**args).create(object_id=object_id, user_id=user_id, vote=args['vote']) - SubjectObjectsManager(**args).create(user_id=user_id, object_id=object_id, ts=time()) + osmanager.create(object_id=object_id, user_id=user_id, vote=args['vote'], review=args['review']) + somanager.create(user_id=user_id, object_id=object_id, timestamp=time()) return get_user_object_reply( object_id=object_id, user_id=user_id, - vote=ObjectSubjectsManager(**args).score(object_id=object_id, user_id=user_id), - when=SubjectObjectsManager(**args).score(user_id=user_id, object_id=object_id), + vote=osmanager.score(object_id=object_id, user_id=user_id), + when=somanager.score(user_id=user_id, object_id=object_id), + review=osmanager.review(object_id=object_id, user_id=user_id), ) def delete(self, object_id, user_id): diff --git a/reding/tests/documentation.py b/reding/tests/documentation.py index 61f6b47..2e599d9 100644 --- a/reding/tests/documentation.py +++ b/reding/tests/documentation.py @@ -1,7 +1,7 @@ import os import json import redis -from reding import resources, managers +from reding import managers from reding.tests.utils import RedingTestCase managers.rclient = redis.StrictRedis( host=os.getenv('REDING_TEST_REDIS_HOST', 'localhost'), @@ -11,7 +11,6 @@ class RedingDocumentationTestCase(RedingTestCase): - def test_00_voted_list_resource_empty(self): managers.rclient.flushdb() response = self.assert_get('/objects/') @@ -101,7 +100,7 @@ def test_06_voted_list_resource_check_votes_single_object(self): expected = { u"amount": 19, u"average": u"9.5", - u"object_id": url_parts['object_id'], + u"object_id": url_parts[u'object_id'], u"votes_no": 2, } self.assertEqual(json.loads(response.data), expected) @@ -116,7 +115,8 @@ def test_07_voted_list_resource_check_vote_single_user(self): ) expected = { u"vote": 9, - u"when": self.user_vote_dates[url_parts['user_id']][url_parts['object_id']] + u'review': None, + u"when": self.user_vote_dates[url_parts[u'user_id']][url_parts[u'object_id']] } expected.update(url_parts) self.assertEqual(json.loads(response.data), expected) @@ -194,6 +194,7 @@ def test_11_vote_summary_resource_forth_vote(self): headers = [] data = { u'vote': 10, + u'review': u'LOTR is awesome', } response = self.assert_post_or_put( '/objects/{object_id}/users/{user_id}/'.format(**url_parts), @@ -214,13 +215,15 @@ def test_12_voted_list_resource_check_vote_single_user(self): expected = [ { u"vote": 9, - u"when": self.user_vote_dates[url_parts['user_id']][reply_objects[0]], + u'review': None, + u"when": self.user_vote_dates[url_parts[u'user_id']][reply_objects[0]], u"user_id": url_parts[u'user_id'], u"object_id": reply_objects[0], }, { u"vote": 10, - u"when": self.user_vote_dates[url_parts['user_id']][reply_objects[1]], + u'review': u'LOTR is awesome', + u"when": self.user_vote_dates[url_parts[u'user_id']][reply_objects[1]], u"user_id": url_parts[u'user_id'], u"object_id": reply_objects[1], } @@ -252,6 +255,7 @@ def test_14_user_list_resource(self): expected = [ { u'vote': 10, + u'review': u'LOTR is awesome', u'user_id': user_id, u'when': self.user_vote_dates[user_id][object_id], u'object_id': object_id, diff --git a/reding/tests/utils.py b/reding/tests/utils.py index 51bb9b2..464ea88 100644 --- a/reding/tests/utils.py +++ b/reding/tests/utils.py @@ -35,11 +35,12 @@ def assert_post_or_put(self, url, headers, data, put=False): self.assertEqual(r.mimetype, 'application/json') return r - def _check_post(self, response, object_id, user_id, vote): + def _check_post(self, response, object_id, user_id, vote, review=None): resp = json.loads(response.data) self.assertEqual(resp['object_id'], object_id) self.assertEqual(resp['user_id'], user_id) self.assertEqual(resp['vote'], vote) + self.assertEqual(resp['review'], review) self.user_vote_dates.setdefault(user_id, {}) self.user_vote_dates[user_id][object_id] = resp['when'] dt = dtparser.parse(resp['when']) From 43bd6ddac895e71e5e09ca0b7ee405adbf2da1a3 Mon Sep 17 00:00:00 2001 From: z4r <24erre@gmail.com> Date: Fri, 13 Sep 2013 12:54:25 +0200 Subject: [PATCH 4/5] =?UTF-8?q?the=20=E2=98=83=20loves=20lotr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +++--- reding/managers.py | 6 ++++-- reding/resources.py | 5 +++-- reding/settings.py | 3 --- reding/tests/documentation.py | 7 ++++--- 5 files changed, 14 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 7546a89..d33d331 100644 --- a/README.md +++ b/README.md @@ -217,7 +217,7 @@ Server: mindflayer Well, stop programming books...I'm gonna give a '10' to the amazing 'The Lord of the Rings Sketchbook', but this time let me add a review: ``` -$ curl -i -XPUT http://localhost:5000/objects/978-0618640140/users/gsalluzzo/ -d "vote=10&review=LOTR is awesome!" +$ curl -i -XPUT http://localhost:5000/objects/978-0618640140/users/gsalluzzo/ -d "vote=10&review=the ☃ loves lotr" HTTP/1.1 200 OK Content-Type: application/json Content-Length: 110 @@ -230,7 +230,7 @@ Server: mindflayer "when": "Fri, 01 Feb 2013 18:21:56 -0000", "user_id": "gsalluzzo", "object_id": "978-0618640140", - "review": "LOTR is awesome!" + "review": "the ☃ loves lotr" } } ``` @@ -256,7 +256,7 @@ Server: mindflayer "when": "Fri, 01 Feb 2013 18:21:56 -0000", "user_id": "gsalluzzo", "object_id": "978-0618640140", - "review": "LOTR is awesome!" + "review": "the ☃ loves lotr" }] ``` diff --git a/reding/managers.py b/reding/managers.py index f17f9f9..96f1d9e 100644 --- a/reding/managers.py +++ b/reding/managers.py @@ -1,5 +1,7 @@ from datetime import datetime -from reding.settings import KEY_CONFIG, rclient +import redis +from reding.settings import KEY_CONFIG, REDIS_CONFIG +rclient = redis.StrictRedis(**REDIS_CONFIG) def get_key_name(template, **kw): @@ -63,7 +65,7 @@ def create(self, object_id, user_id, vote, review): ) name = self.template_review.format(object_id=object_id) if review: - rclient.hset(name,user_id, review) + rclient.hset(name, user_id, review) else: rclient.hdel(name, user_id) diff --git a/reding/resources.py b/reding/resources.py index 53443ba..a471813 100644 --- a/reding/resources.py +++ b/reding/resources.py @@ -7,6 +7,7 @@ from flask.ext import restful from time import time +from six import text_type def get_user_object_reply(object_id, user_id, vote, when, review): @@ -28,7 +29,7 @@ def get_user_object_reply(object_id, user_id, vote, when, review): user_object_resource_fields = { 'vote': fields.Integer, - 'review': fields.String, + 'review': fields.Raw, 'object_id': fields.String, 'user_id': fields.String, 'when': fields.DateTime @@ -240,7 +241,7 @@ def post(self, object_id, user_id): @marshal_with(user_object_resource_fields) def put(self, object_id, user_id): self.parser.add_argument('vote', type=int, required=True) - self.parser.add_argument('review', type=str) + self.parser.add_argument('review', type=text_type) args = self.parser.parse_args() osmanager = ObjectSubjectsManager(**args) diff --git a/reding/settings.py b/reding/settings.py index c04959d..619e8b1 100644 --- a/reding/settings.py +++ b/reding/settings.py @@ -1,4 +1,3 @@ -import redis import os REDIS_CONFIG = { @@ -7,8 +6,6 @@ 'db': int(os.getenv('REDING_REDIS_DB', 0)), } -rclient = redis.StrictRedis(**REDIS_CONFIG) - DAEMON_CONFIG = { 'host': os.getenv('REDING_DAEMON_HOST', '0.0.0.0'), 'port': int(os.getenv('REDING_DAEMON_PORT', 5000)), diff --git a/reding/tests/documentation.py b/reding/tests/documentation.py index 2e599d9..e49b19f 100644 --- a/reding/tests/documentation.py +++ b/reding/tests/documentation.py @@ -1,3 +1,4 @@ +# coding=utf-8 import os import json import redis @@ -194,7 +195,7 @@ def test_11_vote_summary_resource_forth_vote(self): headers = [] data = { u'vote': 10, - u'review': u'LOTR is awesome', + u'review': u'the ☃ loves lotr', } response = self.assert_post_or_put( '/objects/{object_id}/users/{user_id}/'.format(**url_parts), @@ -222,7 +223,7 @@ def test_12_voted_list_resource_check_vote_single_user(self): }, { u"vote": 10, - u'review': u'LOTR is awesome', + u'review': u'the ☃ loves lotr', u"when": self.user_vote_dates[url_parts[u'user_id']][reply_objects[1]], u"user_id": url_parts[u'user_id'], u"object_id": reply_objects[1], @@ -255,7 +256,7 @@ def test_14_user_list_resource(self): expected = [ { u'vote': 10, - u'review': u'LOTR is awesome', + u'review': u'the ☃ loves lotr', u'user_id': user_id, u'when': self.user_vote_dates[user_id][object_id], u'object_id': object_id, From 7a5a9828c08e7a894677ae05eecce0827080b64a Mon Sep 17 00:00:00 2001 From: z4r <24erre@gmail.com> Date: Fri, 13 Sep 2013 13:00:10 +0200 Subject: [PATCH 5/5] debug is evil --- reding/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/reding/__init__.py b/reding/__init__.py index 39b04ec..2945f43 100644 --- a/reding/__init__.py +++ b/reding/__init__.py @@ -33,9 +33,7 @@ if __name__ == '__main__': from reding.app import app from reding.settings import DAEMON_CONFIG - app.run(debug=True, port=5001) - import sys - sys.exit() + # app.run(debug=True, port=5001); import sys; sys.exit() from cherrypy import wsgiserver w = wsgiserver.WSGIPathInfoDispatcher({'/': app.wsgi_app})