From d444b627dbf6cf065e980405b72339b0ac35c60f Mon Sep 17 00:00:00 2001 From: dongweiming Date: Sun, 11 Jun 2017 22:52:01 +0800 Subject: [PATCH 01/10] Compatible with py 3 --- redisco/containers.py | 1 + redisco/models/attributes.py | 31 ++++++++++++++--------- redisco/models/base.py | 48 ++++++++++++++++++++---------------- redisco/models/key.py | 2 ++ redisco/models/modelset.py | 13 +++++----- requirements.txt | 3 +-- 6 files changed, 58 insertions(+), 40 deletions(-) diff --git a/redisco/containers.py b/redisco/containers.py index 700bac5fe..0fe8a8666 100644 --- a/redisco/containers.py +++ b/redisco/containers.py @@ -3,6 +3,7 @@ import collections from functools import partial +from six import text_type as unicode from . import default_expire_time diff --git a/redisco/models/attributes.py b/redisco/models/attributes.py index c91c3ada0..91aa8ac3e 100644 --- a/redisco/models/attributes.py +++ b/redisco/models/attributes.py @@ -4,12 +4,15 @@ """ import time import sys +from functools import partial from datetime import datetime, date, timedelta from dateutil.tz import tzutc, tzlocal +from six import string_types, text_type as unicode from calendar import timegm from redisco.containers import List from .exceptions import FieldValidationError, MissingID + __all__ = ['Attribute', 'CharField', 'ListField', 'DateTimeField', 'DateField', 'TimeDeltaField', 'ReferenceField', 'Collection', 'IntegerField', 'FloatField', 'BooleanField', 'Counter', @@ -52,12 +55,16 @@ def __get__(self, instance, owner): try: return getattr(instance, '_' + self.name) except AttributeError: - if callable(self.default): - default = self.default() - else: - default = self.default - self.__set__(instance, default) - return default + val = instance.db.hget(instance.key(), self.name) + if not val: + if callable(self.default): + default = self.default() + else: + default = self.default + val = default + val = self.typecast_for_read(val) + self.__set__(instance, val) + return val def __set__(self, instance, value): setattr(instance, '_' + self.name, value) @@ -78,7 +85,7 @@ def value_type(self): return unicode def acceptable_types(self): - return basestring + return string_types def validate(self, instance): val = getattr(instance, self.name) @@ -320,8 +327,8 @@ def __init__(self, target_type, self.required = required self.validator = validator self.default = default or [] - from base import Model - self._redisco_model = (isinstance(target_type, basestring) or + from .base import Model + self._redisco_model = (isinstance(target_type, string_types) or issubclass(target_type, Model)) def __get__(self, instance, owner): @@ -335,6 +342,8 @@ def __get__(self, instance, owner): val = List(key).members if val is not None: klass = self.value_type() + if klass == str: + klass = partial(str, encoding='utf-8') if self._redisco_model: val = filter(lambda o: o is not None, [klass.objects.get_by_id(v) for v in val]) else: @@ -346,8 +355,8 @@ def __set__(self, instance, value): setattr(instance, '_' + self.name, value) def value_type(self): - if isinstance(self._target_type, basestring): - t = self._target_type + if isinstance(self._target_type, string_types): + self._target_type = partial(self._target_type, 'utf-8') from base import get_model_from_key self._target_type = get_model_from_key(self._target_type) if self._target_type is None: diff --git a/redisco/models/base.py b/redisco/models/base.py index 28d9d44fa..e444ac1d0 100644 --- a/redisco/models/base.py +++ b/redisco/models/base.py @@ -1,6 +1,8 @@ import time +from functools import partial from datetime import datetime, date from dateutil.tz import tzutc +from six import with_metaclass import redisco from redisco.containers import Set, List, SortedSet, NonPersistentList from .attributes import * @@ -9,6 +11,9 @@ from .exceptions import FieldValidationError, MissingID, BadKeyError, WatchError from .attributes import Counter +_str = str +str = partial(str, encoding='utf-8') + __all__ = ['Model', 'from_key'] ZINDEXABLE = (IntegerField, DateTimeField, DateField, FloatField) @@ -29,10 +34,10 @@ def _initialize_attributes(model_class, name, bases, attrs): for parent in bases: if not isinstance(parent, ModelBase): continue - for k, v in parent._attributes.iteritems(): + for k, v in parent._attributes.items(): model_class._attributes[k] = v - for k, v in attrs.iteritems(): + for k, v in attrs.items(): if isinstance(v, Attribute): model_class._attributes[k] = v v.name = v.name or k @@ -66,10 +71,10 @@ def _initialize_lists(model_class, name, bases, attrs): for parent in bases: if not isinstance(parent, ModelBase): continue - for k, v in parent._lists.iteritems(): + for k, v in parent._lists.items(): model_class._lists[k] = v - for k, v in attrs.iteritems(): + for k, v in attrs.items(): if isinstance(v, ListField): model_class._lists[k] = v v.name = v.name or k @@ -85,7 +90,7 @@ def _initialize_references(model_class, name, bases, attrs): for parent in bases: if not isinstance(parent, ModelBase): continue - for k, v in parent._references.iteritems(): + for k, v in parent._references.items(): model_class._references[k] = v # We skip updating the attributes since this is done # already at the parent construction and then copied back @@ -94,7 +99,7 @@ def _initialize_references(model_class, name, bases, attrs): if refd: deferred.append(refd) - for k, v in attrs.iteritems(): + for k, v in attrs.items(): if isinstance(v, ReferenceField): model_class._references[k] = v v.name = v.name or k @@ -116,14 +121,14 @@ def _initialize_indices(model_class, name, bases, attrs): for parent in bases: if not isinstance(parent, ModelBase): continue - for k, v in parent._attributes.iteritems(): + for k, v in parent._attributes.items(): if v.indexed: model_class._indices.append(k) - for k, v in parent._lists.iteritems(): + for k, v in parent._lists.items(): if v.indexed: model_class._indices.append(k) - for k, v in attrs.iteritems(): + for k, v in attrs.items(): if isinstance(v, (Attribute, ListField)) and v.indexed: model_class._indices.append(k) if model_class._meta['indices']: @@ -142,7 +147,7 @@ def _initialize_counters(model_class, name, bases, attrs): for c in parent._counters: model_class._counters.append(c) - for k, v in attrs.iteritems(): + for k, v in attrs.items(): if isinstance(v, Counter): # When subclassing, we want to override the attributes if k in model_class._counters: @@ -167,7 +172,7 @@ def _initialize_manager(model_class, name, bases, attrs): """ model_class.objects = ManagerDescriptor(Manager(model_class)) - for key, val in attrs.iteritems(): + for key, val in attrs.items(): if isinstance(val, type) and issubclass(val, Manager): attr_name = getattr(val, "__attr_name__", key.lower()) descriptor = ManagerDescriptor(val(model_class)) @@ -230,8 +235,7 @@ def __init__(cls, name, bases, attrs): def __getitem__(self, id): return self.objects.get_by_id(id) -class Model(object): - __metaclass__ = ModelBase +class Model(with_metaclass(ModelBase)): def __init__(self, **kwargs): self.update_attributes(**kwargs) @@ -309,8 +313,8 @@ def update_attributes(self, **kwargs): >>> f.name 'Tesla' """ - attrs = self.attributes.values() + self.lists.values() \ - + self.references.values() + attrs = list(self.attributes.values()) + list(self.lists.values()) \ + + list(self.references.values()) for att in attrs: if att.name in kwargs: att.__set__(self, kwargs[att.name]) @@ -519,8 +523,8 @@ def errors(self): @property def fields(self): """Returns the list of field names of the model.""" - return (self.attributes.values() + self.lists.values() - + self.references.values()) + return (list(self.attributes.values()) + list(self.lists.values()) + + list(self.references.values())) @property def counters(self): @@ -534,8 +538,8 @@ def counters(self): @classmethod def exists(cls, id): """Checks if the model with id exists.""" - return bool((cls._meta['db'] or redisco.get_client()).exists(cls._key[str(id)]) or - (cls._meta['db'] or redisco.get_client()).sismember(cls._key['all'], str(id))) + return bool((cls._meta['db'] or redisco.get_client()).exists(cls._key[_str(id)]) or + (cls._meta['db'] or redisco.get_client()).sismember(cls._key['all'], _str(id))) ################### # Private methods # @@ -556,7 +560,7 @@ def _write(self, _new=False): self._update_indices(pipeline) h = {} # attributes - for k, v in self.attributes.iteritems(): + for k, v in self.attributes.items(): if isinstance(v, DateTimeField): if v.auto_now: setattr(self, k, datetime.now(tz=tzutc())) @@ -567,6 +571,7 @@ def _write(self, _new=False): setattr(self, k, datetime.now(tz=tzutc())) if v.auto_now_add and _new: setattr(self, k, datetime.now(tz=tzutc())) + for_storage = getattr(self, k) if for_storage is not None: h[k] = v.typecast_for_storage(for_storage) @@ -582,11 +587,12 @@ def _write(self, _new=False): except UnicodeError: h[index] = unicode(v.decode('utf-8')) pipeline.delete(self.key()) + if h: pipeline.hmset(self.key(), h) # lists - for k, v in self.lists.iteritems(): + for k, v in self.lists.items(): l = List(self.key()[k], pipeline=pipeline) l.clear() values = getattr(self, k) diff --git a/redisco/models/key.py b/redisco/models/key.py index 31325d8bf..b50e90fd0 100644 --- a/redisco/models/key.py +++ b/redisco/models/key.py @@ -6,4 +6,6 @@ class Key(unicode): def __getitem__(self, key): + if isinstance(key, bytes): + key = unicode(key, 'u8') return Key(u"%s:%s" % (self, key)) diff --git a/redisco/models/modelset.py b/redisco/models/modelset.py index 87e542901..afe2fc1e5 100644 --- a/redisco/models/modelset.py +++ b/redisco/models/modelset.py @@ -33,7 +33,7 @@ def __getitem__(self, index): if isinstance(index, slice): return map(lambda id: self._get_item_with_id(id), self._set[index]) else: - id = self._set[index] + id = str(self._set[index], 'utf-8') if id: return self._get_item_with_id(id) else: @@ -80,7 +80,7 @@ def get_by_id(self, id): >>> [f.delete() for f in Foo.objects.all()] # doctest: +ELLIPSIS [...] """ - if (self._filters or self._exclusions or self._zfilters) and str(id) not in self._set: + if (self._filters or self._exclusions or self._zfilters) and str(id, 'utf-8') not in self._set: return if self.model_class.exists(id): return self._get_item_with_id(id) @@ -257,7 +257,7 @@ def get_or_create(self, **kwargs): [...] """ opts = {} - for k, v in kwargs.iteritems(): + for k, v in kwargs.items(): if k in self.model_class._indices: opts[k] = v o = self.filter(**opts).first() @@ -308,7 +308,7 @@ def _add_set_filter(self, s): :return: the new Set """ indices = [] - for k, v in self._filters.iteritems(): + for k, v in self._filters.items(): index = self._build_key_from_filter_item(k, v) if k not in self.model_class._indices: raise AttributeNotIndexed( @@ -332,7 +332,7 @@ def _add_set_exclusions(self, s): :return: the new Set """ indices = [] - for k, v in self._exclusions.iteritems(): + for k, v in self._exclusions.items(): index = self._build_key_from_filter_item(k, v) if k not in self.model_class._indices: raise AttributeNotIndexed( @@ -449,7 +449,8 @@ def _set_without_ordering(self, skey): self.db.sort(old_set_key, store=new_set_key, start=start, - num=num) + num=num, + alpha=True) if old_set_key != self.key: Set(old_set_key, db=self.db).set_expire() new_list = List(new_set_key, db=self.db) diff --git a/requirements.txt b/requirements.txt index ed402347d..3d56c5c62 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ DateUtils==0.6.6 -hiredis==0.1.1 redis>=2.7.5 -redislite>=1.0.228 \ No newline at end of file +redislite>=1.0.228 From 2fd737512634e28989bdc6abfde78df031a1311e Mon Sep 17 00:00:00 2001 From: Andrew Burdyug Date: Thu, 24 Aug 2017 14:42:39 +0300 Subject: [PATCH 02/10] Fix: NameError, python 3.6.2 (name long is not defined) --- redisco/models/attributes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/redisco/models/attributes.py b/redisco/models/attributes.py index 91aa8ac3e..d19091e90 100644 --- a/redisco/models/attributes.py +++ b/redisco/models/attributes.py @@ -7,7 +7,7 @@ from functools import partial from datetime import datetime, date, timedelta from dateutil.tz import tzutc, tzlocal -from six import string_types, text_type as unicode +from six import string_types, integer_types, text_type as unicode from calendar import timegm from redisco.containers import List from .exceptions import FieldValidationError, MissingID @@ -174,7 +174,7 @@ def value_type(self): return int def acceptable_types(self): - return (int, long) + return integer_types class FloatField(Attribute): From 532dcd2e74e3c16d1882a30f05cf31787ef7c736 Mon Sep 17 00:00:00 2001 From: chan Date: Fri, 8 Sep 2017 19:26:36 +0800 Subject: [PATCH 03/10] fix bug in Attribute __get__() --- .gitignore | 2 ++ redisco/models/attributes.py | 16 ++++++---------- redisco/models/base.py | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 2fe0fc51d..f1cf562a5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ dump.rdb /.emacs.desktop /redisco/.ropeproject/config.py .ropeproject +venv +.idea/ diff --git a/redisco/models/attributes.py b/redisco/models/attributes.py index d19091e90..2f6996f90 100644 --- a/redisco/models/attributes.py +++ b/redisco/models/attributes.py @@ -55,16 +55,12 @@ def __get__(self, instance, owner): try: return getattr(instance, '_' + self.name) except AttributeError: - val = instance.db.hget(instance.key(), self.name) - if not val: - if callable(self.default): - default = self.default() - else: - default = self.default - val = default - val = self.typecast_for_read(val) - self.__set__(instance, val) - return val + if callable(self.default): + default = self.default() + else: + default = self.default + self.__set__(instance, default) + return default def __set__(self, instance, value): setattr(instance, '_' + self.name, value) diff --git a/redisco/models/base.py b/redisco/models/base.py index e444ac1d0..1ef2b0b03 100644 --- a/redisco/models/base.py +++ b/redisco/models/base.py @@ -547,7 +547,7 @@ def exists(cls, id): def _initialize_id(self): """Initializes the id of the instance.""" - self._id = str(self.db.incr(self._key['id'])) + self._id = _str(self.db.incr(self._key['id'])) def _write(self, _new=False): """Writes the values of the attributes to the datastore. From 95593cf96ce0c11942854db2cf52986d31a170fe Mon Sep 17 00:00:00 2001 From: chan Date: Fri, 8 Sep 2017 20:19:52 +0800 Subject: [PATCH 04/10] Fix bug in ListField --- redisco/models/attributes.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/redisco/models/attributes.py b/redisco/models/attributes.py index 2f6996f90..d903f1ca5 100644 --- a/redisco/models/attributes.py +++ b/redisco/models/attributes.py @@ -341,7 +341,7 @@ def __get__(self, instance, owner): if klass == str: klass = partial(str, encoding='utf-8') if self._redisco_model: - val = filter(lambda o: o is not None, [klass.objects.get_by_id(v) for v in val]) + val = list(filter(lambda o: o is not None, [klass.objects.get_by_id(v) for v in val])) else: val = [klass(v) for v in val] self.__set__(instance, val) @@ -352,8 +352,8 @@ def __set__(self, instance, value): def value_type(self): if isinstance(self._target_type, string_types): - self._target_type = partial(self._target_type, 'utf-8') - from base import get_model_from_key + t = self._target_type + from .base import get_model_from_key self._target_type = get_model_from_key(self._target_type) if self._target_type is None: raise ValueError("Unknown Redisco class %s" % t) From a24e3c776b84e3e6a31bfe865127740b7b54d453 Mon Sep 17 00:00:00 2001 From: chan Date: Mon, 11 Sep 2017 10:58:48 +0800 Subject: [PATCH 05/10] python3 compatible --- .gitignore | 3 ++ benchmarks/common.py | 1 + benchmarks/create.py | 10 +++-- redisco/containers.py | 27 ++++++------ redisco/containerstests.py | 16 ++++--- redisco/models/attributes.py | 32 ++++++++------ redisco/models/base.py | 83 ++++++++++++++++++++---------------- redisco/models/basetests.py | 14 +++--- redisco/models/exceptions.py | 8 +++- redisco/models/key.py | 11 +++-- redisco/models/managers.py | 4 +- redisco/models/modelset.py | 22 ++++++---- redisco/tests/__init__.py | 25 +++++++---- 13 files changed, 156 insertions(+), 100 deletions(-) diff --git a/.gitignore b/.gitignore index 2fe0fc51d..691e8e338 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,6 @@ dump.rdb /.emacs.desktop /redisco/.ropeproject/config.py .ropeproject +venv +venv2 +.idea diff --git a/benchmarks/common.py b/benchmarks/common.py index 8eb5e8267..961dad1f6 100644 --- a/benchmarks/common.py +++ b/benchmarks/common.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import from redisco import models diff --git a/benchmarks/create.py b/benchmarks/create.py index 633226d47..91e1b0483 100644 --- a/benchmarks/create.py +++ b/benchmarks/create.py @@ -1,6 +1,10 @@ -from redisco import get_client +from __future__ import absolute_import +from __future__ import print_function + import timeit -from common import Event + +from redisco import get_client +from .common import Event def create_events(): @@ -16,7 +20,7 @@ def find_events(): def display_results(results, name): - print "%s: 5000 Loops, best of 3: %.02f sec" % (name, min(results)) + print("%s: 5000 Loops, best of 3: %.02f sec" % (name, min(results))) def profile(): import cProfile diff --git a/redisco/containers.py b/redisco/containers.py index 700bac5fe..fd27a61b9 100644 --- a/redisco/containers.py +++ b/redisco/containers.py @@ -1,9 +1,12 @@ # -*- coding: utf-8 -*- # doctest: +ELLIPSIS +from __future__ import absolute_import import collections from functools import partial from . import default_expire_time +import six +from six.moves import range def _parse_values(values): @@ -264,9 +267,9 @@ def union(self, key, *other_sets): >>> s3.clear() """ - if not isinstance(key, str) and not isinstance(key, unicode): + if not isinstance(key, str) and not isinstance(key, six.text_type): raise ValueError("Expect a (unicode) string as key") - key = unicode(key) + key = six.text_type(key) self.db.sunionstore(key, [self.key] + [o.key for o in other_sets]) return Set(key) @@ -296,9 +299,9 @@ def intersection(self, key, *other_sets): """ - if not isinstance(key, str) and not isinstance(key, unicode): + if not isinstance(key, str) and not isinstance(key, six.text_type): raise ValueError("Expect a (unicode) string as key") - key = unicode(key) + key = six.text_type(key) self.db.sinterstore(key, [self.key] + [o.key for o in other_sets]) return Set(key) @@ -327,9 +330,9 @@ def difference(self, key, *other_sets): >>> s3.clear() """ - if not isinstance(key, str) and not isinstance(key, unicode): + if not isinstance(key, str) and not isinstance(key, six.text_type): raise ValueError("Expect a (unicode) string as key") - key = unicode(key) + key = six.text_type(key) self.db.sdiffstore(key, [self.key] + [o.key for o in other_sets]) return Set(key) @@ -709,13 +712,13 @@ def __init__(self, key, target_type, type_args=[], type_kwargs={}, **kwargs): self.klass = self.value_type(target_type) self._klass_args = type_args self._klass_kwargs = type_kwargs - from models.base import Model + from .models.base import Model self._redisco_model = issubclass(self.klass, Model) def value_type(self, target_type): - if isinstance(target_type, basestring): + if isinstance(target_type, six.string_types): t = target_type - from models.base import get_model_from_key + from .models.base import get_model_from_key target_type = get_model_from_key(target_type) if target_type is None: raise ValueError("Unknown Redisco class %s" % t) @@ -729,7 +732,7 @@ def typecast_item(self, value): def typecast_iter(self, values): if self._redisco_model: - return filter(lambda o: o is not None, [self.klass.objects.get_by_id(v) for v in values]) + return [o for o in [self.klass.objects.get_by_id(v) for v in values] if o is not None] else: return [self.klass(v, *self._klass_args, **self._klass_kwargs) for v in values] @@ -757,13 +760,13 @@ def append(self, value): self.list.append(self.typecast_stor(value)) def extend(self, iter): - self.list.extend(map(lambda i: self.typecast_stor(i), iter)) + self.list.extend([self.typecast_stor(i) for i in iter]) def __setitem__(self, index, value): self.list[index] = self.typecast_stor(value) def __iter__(self): - for i in xrange(len(self.list)): + for i in range(len(self.list)): yield self[i] def __repr__(self): diff --git a/redisco/containerstests.py b/redisco/containerstests.py index 34b2cdc96..ec2fdbd42 100644 --- a/redisco/containerstests.py +++ b/redisco/containerstests.py @@ -1,6 +1,10 @@ +from __future__ import absolute_import import unittest import redisco from redisco import containers as cont +import six +from six.moves import range +from six.moves import zip class SetTestCase(unittest.TestCase): @@ -293,7 +297,7 @@ def test_common_operations(self): def test_pop_onto(self): a = cont.List('alpha') b = cont.List('beta') - a.extend(range(10)) + a.extend(list(range(10))) # test pop_onto a_snap = list(a.members) @@ -345,20 +349,20 @@ def tearDown(self): self.client.flushdb() def test_basic_types(self): - alpha = cont.TypedList('alpha', unicode, type_args=('UTF-8',)) + alpha = cont.TypedList('alpha', six.text_type, type_args=('UTF-8',)) monies = u'\u0024\u00a2\u00a3\u00a5' alpha.append(monies) val = alpha[-1] self.assertEquals(monies, val) beta = cont.TypedList('beta', int) - for i in xrange(1000): + for i in range(1000): beta.append(i) for i, x in enumerate(beta): self.assertEquals(i, x) charlie = cont.TypedList('charlie', float) - for i in xrange(100): + for i in range(100): val = 1 * pow(10, i*-1) charlie.append(val) for i, x in enumerate(charlie): @@ -448,9 +452,9 @@ def test_basic(self): self.assertEqual({'name': "Richard Cypher", 'real_name': "Richard Rahl"}, h.dict) - self.assertEqual(['name', 'real_name'], h.keys()) + self.assertEqual(['name', 'real_name'], list(h.keys())) self.assertEqual(["Richard Cypher", "Richard Rahl"], - h.values()) + list(h.values())) del h['name'] pulled = self.client.hgetall('hkey') diff --git a/redisco/models/attributes.py b/redisco/models/attributes.py index c91c3ada0..f527192f4 100644 --- a/redisco/models/attributes.py +++ b/redisco/models/attributes.py @@ -2,11 +2,15 @@ """ Defines the fields that can be added to redisco models. """ -import time +from __future__ import absolute_import + import sys +from calendar import timegm from datetime import datetime, date, timedelta + +import six from dateutil.tz import tzutc, tzlocal -from calendar import timegm + from redisco.containers import List from .exceptions import FieldValidationError, MissingID @@ -70,15 +74,15 @@ def typecast_for_read(self, value): def typecast_for_storage(self, value): """Typecasts the value for storing to Redis.""" try: - return unicode(value) + return six.text_type(value) except UnicodeError: return value.decode('utf-8') def value_type(self): - return unicode + return six.text_type def acceptable_types(self): - return basestring + return six.string_types def validate(self, instance): val = getattr(instance, self.name) @@ -88,7 +92,7 @@ def validate(self, instance): errors.append((self.name, 'bad type',)) # validate first standard stuff if self.required: - if val is None or not unicode(val).strip(): + if val is None or not six.text_type(val).strip(): errors.append((self.name, 'required')) # validate uniquness if val and self.unique: @@ -161,13 +165,13 @@ def typecast_for_read(self, value): def typecast_for_storage(self, value): if value is None: return "0" - return unicode(value) + return six.text_type(value) def value_type(self): return int def acceptable_types(self): - return (int, long) + return six.integer_types class FloatField(Attribute): @@ -320,8 +324,8 @@ def __init__(self, target_type, self.required = required self.validator = validator self.default = default or [] - from base import Model - self._redisco_model = (isinstance(target_type, basestring) or + from .base import Model + self._redisco_model = (isinstance(target_type, six.string_types) or issubclass(target_type, Model)) def __get__(self, instance, owner): @@ -336,7 +340,7 @@ def __get__(self, instance, owner): if val is not None: klass = self.value_type() if self._redisco_model: - val = filter(lambda o: o is not None, [klass.objects.get_by_id(v) for v in val]) + val = [o for o in [klass.objects.get_by_id(v) for v in val] if o is not None] else: val = [klass(v) for v in val] self.__set__(instance, val) @@ -346,9 +350,9 @@ def __set__(self, instance, value): setattr(instance, '_' + self.name, value) def value_type(self): - if isinstance(self._target_type, basestring): + if isinstance(self._target_type, six.string_types): t = self._target_type - from base import get_model_from_key + from .base import get_model_from_key self._target_type = get_model_from_key(self._target_type) if self._target_type is None: raise ValueError("Unknown Redisco class %s" % t) @@ -495,7 +499,7 @@ def validate(self, instance): class Counter(IntegerField): def __init__(self, **kwargs): super(Counter, self).__init__(**kwargs) - if not kwargs.has_key('default') or self.default is None: + if 'default' not in kwargs or self.default is None: self.default = 0 def __set__(self, instance, value): diff --git a/redisco/models/base.py b/redisco/models/base.py index 28d9d44fa..e2ea985e1 100644 --- a/redisco/models/base.py +++ b/redisco/models/base.py @@ -1,18 +1,24 @@ +from __future__ import absolute_import + import time -from datetime import datetime, date +from datetime import datetime + +import six from dateutil.tz import tzutc + import redisco -from redisco.containers import Set, List, SortedSet, NonPersistentList +from redisco.containers import Set, List from .attributes import * +from .attributes import Counter +from .exceptions import FieldValidationError, MissingID, BadKeyError, WatchError from .key import Key from .managers import ManagerDescriptor, Manager -from .exceptions import FieldValidationError, MissingID, BadKeyError, WatchError -from .attributes import Counter __all__ = ['Model', 'from_key'] ZINDEXABLE = (IntegerField, DateTimeField, DateField, FloatField) + ############################## # Model Class Initialization # ############################## @@ -29,30 +35,32 @@ def _initialize_attributes(model_class, name, bases, attrs): for parent in bases: if not isinstance(parent, ModelBase): continue - for k, v in parent._attributes.iteritems(): + for k, v in six.iteritems(parent._attributes): model_class._attributes[k] = v - for k, v in attrs.iteritems(): + for k, v in six.iteritems(attrs): if isinstance(v, Attribute): model_class._attributes[k] = v v.name = v.name or k + def _initialize_referenced(model_class, attribute): """ Adds a property to the target of a reference field that returns the list of associated objects. """ + # this should be a descriptor def _related_objects(self): return (model_class.objects .filter(**{attribute.attname: self.id})) klass = attribute._target_type - if isinstance(klass, basestring): + if isinstance(klass, six.string_types): return (klass, model_class, attribute) else: related_name = (attribute.related_name or - model_class.__name__.lower() + '_set') + model_class.__name__.lower() + '_set') if not hasattr(klass, related_name): setattr(klass, related_name, property(_related_objects)) @@ -66,10 +74,10 @@ def _initialize_lists(model_class, name, bases, attrs): for parent in bases: if not isinstance(parent, ModelBase): continue - for k, v in parent._lists.iteritems(): + for k, v in six.iteritems(parent._lists): model_class._lists[k] = v - for k, v in attrs.iteritems(): + for k, v in six.iteritems(attrs): if isinstance(v, ListField): model_class._lists[k] = v v.name = v.name or k @@ -85,7 +93,7 @@ def _initialize_references(model_class, name, bases, attrs): for parent in bases: if not isinstance(parent, ModelBase): continue - for k, v in parent._references.iteritems(): + for k, v in six.iteritems(parent._references): model_class._references[k] = v # We skip updating the attributes since this is done # already at the parent construction and then copied back @@ -94,7 +102,7 @@ def _initialize_references(model_class, name, bases, attrs): if refd: deferred.append(refd) - for k, v in attrs.iteritems(): + for k, v in six.iteritems(attrs): if isinstance(v, ReferenceField): model_class._references[k] = v v.name = v.name or k @@ -116,14 +124,14 @@ def _initialize_indices(model_class, name, bases, attrs): for parent in bases: if not isinstance(parent, ModelBase): continue - for k, v in parent._attributes.iteritems(): + for k, v in six.iteritems(parent._attributes): if v.indexed: model_class._indices.append(k) - for k, v in parent._lists.iteritems(): + for k, v in six.iteritems(parent._lists): if v.indexed: model_class._indices.append(k) - for k, v in attrs.iteritems(): + for k, v in six.iteritems(attrs): if isinstance(v, (Attribute, ListField)) and v.indexed: model_class._indices.append(k) if model_class._meta['indices']: @@ -142,7 +150,7 @@ def _initialize_counters(model_class, name, bases, attrs): for c in parent._counters: model_class._counters.append(c) - for k, v in attrs.iteritems(): + for k, v in six.iteritems(attrs): if isinstance(v, Counter): # When subclassing, we want to override the attributes if k in model_class._counters: @@ -167,7 +175,7 @@ def _initialize_manager(model_class, name, bases, attrs): """ model_class.objects = ManagerDescriptor(Manager(model_class)) - for key, val in attrs.iteritems(): + for key, val in six.iteritems(attrs): if isinstance(val, type) and issubclass(val, Manager): attr_name = getattr(val, "__attr_name__", key.lower()) descriptor = ManagerDescriptor(val(model_class)) @@ -188,6 +196,7 @@ class ModelOptions(object): ... db = redis.Redis(host='localhost', port=29909) """ + def __init__(self, meta): self.meta = meta @@ -198,11 +207,13 @@ def get_field(self, field_name): return self.meta.__dict__[field_name] except KeyError: return None + __getitem__ = get_field _deferred_refs = [] + class ModelBase(type): """ Metaclass of the Model. @@ -230,9 +241,8 @@ def __init__(cls, name, bases, attrs): def __getitem__(self, id): return self.objects.get_by_id(id) -class Model(object): - __metaclass__ = ModelBase +class Model(six.with_metaclass(ModelBase, object)): def __init__(self, **kwargs): self.update_attributes(**kwargs) @@ -309,8 +319,8 @@ def update_attributes(self, **kwargs): >>> f.name 'Tesla' """ - attrs = self.attributes.values() + self.lists.values() \ - + self.references.values() + attrs = list(self.attributes.values()) + list(self.lists.values()) \ + + list(self.references.values()) for att in attrs: if att.name in kwargs: att.__set__(self, kwargs[att.name]) @@ -418,7 +428,6 @@ def decr(self, att, val=1): """ self.incr(att, -1 * val) - @property def attributes_dict(self): """ @@ -445,11 +454,10 @@ def attributes_dict(self): h[k] = getattr(self, k) for k in self.references.keys(): h[k] = getattr(self, k) - if 'id' not in self.attributes.keys() and not self.is_new(): + if 'id' not in list(self.attributes.keys()) and not self.is_new(): h['id'] = self.id return h - @property def id(self): """Returns the id of the instance. @@ -467,7 +475,7 @@ def id(self, val): """ self._id = str(val) stored_attrs = self.db.hgetall(self.key()) - attrs = self.attributes.values() + attrs = list(self.attributes.values()) for att in attrs: if att.name in stored_attrs and not isinstance(att, Counter): att.__set__(self, att.typecast_for_read(stored_attrs[att.name])) @@ -507,7 +515,8 @@ def references(self): @property def db(self): """Returns the Redis client used by the model.""" - return redisco.get_client() if not self._meta['db'] else self._meta['db'] + return redisco.get_client() if not self._meta['db'] else self._meta[ + 'db'] @property def errors(self): @@ -519,8 +528,8 @@ def errors(self): @property def fields(self): """Returns the list of field names of the model.""" - return (self.attributes.values() + self.lists.values() - + self.references.values()) + return (list(self.attributes.values()) + list(self.lists.values()) + + list(self.references.values())) @property def counters(self): @@ -534,8 +543,10 @@ def counters(self): @classmethod def exists(cls, id): """Checks if the model with id exists.""" - return bool((cls._meta['db'] or redisco.get_client()).exists(cls._key[str(id)]) or - (cls._meta['db'] or redisco.get_client()).sismember(cls._key['all'], str(id))) + return bool((cls._meta['db'] or redisco.get_client()).exists( + cls._key[str(id)]) or + (cls._meta['db'] or redisco.get_client()).sismember( + cls._key['all'], str(id))) ################### # Private methods # @@ -556,7 +567,7 @@ def _write(self, _new=False): self._update_indices(pipeline) h = {} # attributes - for k, v in self.attributes.iteritems(): + for k, v in six.iteritems(self.attributes): if isinstance(v, DateTimeField): if v.auto_now: setattr(self, k, datetime.now(tz=tzutc())) @@ -578,15 +589,15 @@ def _write(self, _new=False): v = v() if v: try: - h[index] = unicode(v) + h[index] = six.text_type(v) except UnicodeError: - h[index] = unicode(v.decode('utf-8')) + h[index] = six.text_type(v.decode('utf-8')) pipeline.delete(self.key()) if h: pipeline.hmset(self.key(), h) # lists - for k, v in self.lists.iteritems(): + for k, v in six.iteritems(self.lists): l = List(self.key()[k], pipeline=pipeline) l.clear() values = getattr(self, k) @@ -726,7 +737,6 @@ def __repr__(self): return "<%s %s>" % (self.__class__.__name__, self.attributes_dict) - def get_model_from_key(key): """Gets the model from a given key.""" _known_models = {} @@ -775,7 +785,8 @@ def lock(self): while True: try: pipe.watch(_lock_key) - if o.db.exists(_lock_key) and not self.lock_has_expired(o.db.get(_lock_key)): + if o.db.exists(_lock_key) and not self.lock_has_expired( + o.db.get(_lock_key)): continue pipe.multi() diff --git a/redisco/models/basetests.py b/redisco/models/basetests.py index 0c9de4a72..f59629c8f 100644 --- a/redisco/models/basetests.py +++ b/redisco/models/basetests.py @@ -1,14 +1,18 @@ # -*- coding: utf-8 -*- +from __future__ import absolute_import + import time -from threading import Thread -import redis -import redisco import unittest from datetime import date +from threading import Thread + +import six +from dateutil.tz import tzlocal + +import redisco from redisco import models from redisco.models import managers from redisco.models.base import Mutex -from dateutil.tz import tzlocal class Person(models.Model): @@ -81,7 +85,7 @@ def test_unicode(self): p = Person.objects.filter(first_name=u"Niña").first() self.assert_(p) - self.assert_(isinstance(p.full_name(), unicode)) + self.assert_(isinstance(p.full_name(), six.text_type)) self.assertEqual(u"Niña Jose", p.full_name()) def test_repr(self): diff --git a/redisco/models/exceptions.py b/redisco/models/exceptions.py index bf482742e..9f3d3c0fd 100755 --- a/redisco/models/exceptions.py +++ b/redisco/models/exceptions.py @@ -1,22 +1,27 @@ ########## # ERRORS # ########## +from __future__ import absolute_import from redis import WatchError + class Error(Exception): pass + class ValidationError(Error): pass + class MissingID(Error): pass + class AttributeNotIndexed(Error): pass -class FieldValidationError(Error): +class FieldValidationError(Error): def __init__(self, errors, *args, **kwargs): super(FieldValidationError, self).__init__(*args, **kwargs) self._errors = errors @@ -25,5 +30,6 @@ def __init__(self, errors, *args, **kwargs): def errors(self): return self._errors + class BadKeyError(Error): pass diff --git a/redisco/models/key.py b/redisco/models/key.py index 31325d8bf..a9c3c3e60 100644 --- a/redisco/models/key.py +++ b/redisco/models/key.py @@ -1,9 +1,14 @@ +from __future__ import absolute_import + +import six + try: - unicode + six.text_type except NameError: # Python 3 - basestring = unicode = str + six.string_types = six.text_type = str + -class Key(unicode): +class Key(six.text_type): def __getitem__(self, key): return Key(u"%s:%s" % (self, key)) diff --git a/redisco/models/managers.py b/redisco/models/managers.py index cac091629..1b923c322 100644 --- a/redisco/models/managers.py +++ b/redisco/models/managers.py @@ -1,5 +1,6 @@ from .modelset import ModelSet + ############ # Managers # ############ @@ -15,7 +16,6 @@ def __get__(self, instance, owner): class Manager(object): - def __init__(self, model_class): self.model_class = model_class @@ -45,5 +45,3 @@ def order(self, field): def zfilter(self, **kwargs): return self.get_model_set().zfilter(**kwargs) - - diff --git a/redisco/models/modelset.py b/redisco/models/modelset.py index 87e542901..6bfadf565 100644 --- a/redisco/models/modelset.py +++ b/redisco/models/modelset.py @@ -1,11 +1,15 @@ """ Handles the queries. """ -from .attributes import IntegerField, DateTimeField +from __future__ import absolute_import + +import six + import redisco -from redisco.containers import SortedSet, Set, List, NonPersistentList -from .exceptions import AttributeNotIndexed +from redisco.containers import SortedSet, Set, List from .attributes import ZINDEXABLE +from .exceptions import AttributeNotIndexed + # Model Set class ModelSet(Set): @@ -31,7 +35,7 @@ def __getitem__(self, index): Will look in _set to get the id and simply return the instance of the model. """ if isinstance(index, slice): - return map(lambda id: self._get_item_with_id(id), self._set[index]) + return [self._get_item_with_id(id) for id in self._set[index]] else: id = self._set[index] if id: @@ -44,7 +48,7 @@ def __repr__(self): m = self._set[:30] else: m = self._set - s = map(lambda id: self._get_item_with_id(id), m) + s = [self._get_item_with_id(id) for id in m] return "%s" % s def __iter__(self): @@ -257,7 +261,7 @@ def get_or_create(self, **kwargs): [...] """ opts = {} - for k, v in kwargs.iteritems(): + for k, v in six.iteritems(kwargs): if k in self.model_class._indices: opts[k] = v o = self.filter(**opts).first() @@ -308,7 +312,7 @@ def _add_set_filter(self, s): :return: the new Set """ indices = [] - for k, v in self._filters.iteritems(): + for k, v in six.iteritems(self._filters): index = self._build_key_from_filter_item(k, v) if k not in self.model_class._indices: raise AttributeNotIndexed( @@ -332,7 +336,7 @@ def _add_set_exclusions(self, s): :return: the new Set """ indices = [] - for k, v in self._exclusions.iteritems(): + for k, v in six.iteritems(self._exclusions): index = self._build_key_from_filter_item(k, v) if k not in self.model_class._indices: raise AttributeNotIndexed( @@ -354,7 +358,7 @@ def _add_zfilters(self, s): :return: a SortedSet with the ids. """ - k, v = self._zfilters[0].items()[0] + k, v = list(self._zfilters[0].items())[0] try: att, op = k.split('__') except ValueError: diff --git a/redisco/tests/__init__.py b/redisco/tests/__init__.py index 4868d4d3d..3685a5814 100644 --- a/redisco/tests/__init__.py +++ b/redisco/tests/__init__.py @@ -1,18 +1,27 @@ +from __future__ import absolute_import import os import unittest -from redisco.containerstests import (SetTestCase, ListTestCase, TypedListTestCase, - SortedSetTestCase, HashTestCase) -from redisco.models.basetests import (ModelTestCase, DateFieldTestCase, FloatFieldTestCase, - BooleanFieldTestCase, ListFieldTestCase, ReferenceFieldTestCase, - TimeDeltaFieldTestCase, DateTimeFieldTestCase, CounterFieldTestCase, - CharFieldTestCase, MutexTestCase) import redisco -REDIS_DB = int(os.environ.get('REDIS_DB', 15)) # WARNING TESTS FLUSHDB!!! +from redisco.containerstests import (SetTestCase, ListTestCase, + TypedListTestCase, + SortedSetTestCase, HashTestCase) +from redisco.models.basetests import (ModelTestCase, DateFieldTestCase, + FloatFieldTestCase, + BooleanFieldTestCase, ListFieldTestCase, + ReferenceFieldTestCase, + TimeDeltaFieldTestCase, + DateTimeFieldTestCase, + CounterFieldTestCase, + CharFieldTestCase, MutexTestCase) + +REDIS_DB = int(os.environ.get('REDIS_DB', 15)) # WARNING TESTS FLUSHDB!!! REDIS_PORT = int(os.environ.get('REDIS_PORT', 6379)) redisco.connection_setup(host="localhost", port=REDIS_PORT, db=REDIS_DB) -typed_list_suite = unittest.TestLoader().loadTestsFromTestCase(TypedListTestCase) +typed_list_suite = unittest.TestLoader().loadTestsFromTestCase( + TypedListTestCase) + def all_tests(): suite = unittest.TestSuite() From e4cb897c4e29f2558a761167d5e0bb46e213e7ab Mon Sep 17 00:00:00 2001 From: chan Date: Mon, 11 Sep 2017 15:19:51 +0800 Subject: [PATCH 06/10] Update tests for python3 --- redisco/__init__.py | 3 ++- redisco/containers.py | 45 ++++++++++++++++++------------------ redisco/containerstests.py | 2 +- redisco/models/attributes.py | 3 ++- redisco/models/basetests.py | 4 ++-- redisco/models/modelset.py | 6 ++--- requirements.txt | 1 - 7 files changed, 32 insertions(+), 32 deletions(-) diff --git a/redisco/__init__.py b/redisco/__init__.py index d7b507f16..26b110deb 100644 --- a/redisco/__init__.py +++ b/redisco/__init__.py @@ -7,7 +7,8 @@ default_connection_settings = { 'host': 'localhost', 'port': 6379, - 'db': 0 + 'db': 0, + 'decode_responses': True, } diff --git a/redisco/containers.py b/redisco/containers.py index fd27a61b9..37efd9333 100644 --- a/redisco/containers.py +++ b/redisco/containers.py @@ -3,7 +3,6 @@ from __future__ import absolute_import import collections -from functools import partial from . import default_expire_time import six from six.moves import range @@ -38,7 +37,7 @@ def clear(self): 1 >>> s.clear() >>> s.members - set([]) + set() """ @@ -105,8 +104,8 @@ def sadd(self, *values): 3 >>> s.add(["4"]) 1 - >>> print s - + >>> s.members == {'4', '2', '1', '3'} + True >>> s.clear() """ @@ -141,7 +140,7 @@ def spop(self): >>> s.spop() '1' >>> s.members - set([]) + set() """ return self.db.spop(self.key) @@ -259,9 +258,9 @@ def union(self, key, *other_sets): 2 >>> s3 = s1.union('key3', s2) >>> s3.key - u'key3' - >>> s3.members - set(['a', 'c', 'b', 'e', 'd']) + 'key3' + >>> s3.members == {'e', 'd', 'b', 'a', 'c'} + True >>> s1.clear() >>> s2.clear() >>> s3.clear() @@ -290,9 +289,9 @@ def intersection(self, key, *other_sets): 2 >>> s3 = s1.intersection('key3', s2) >>> s3.key - u'key3' + 'key3' >>> s3.members - set(['c']) + {'c'} >>> s1.clear() >>> s2.clear() >>> s3.clear() @@ -322,9 +321,9 @@ def difference(self, key, *other_sets): 2 >>> s3 = s1.difference('key3', s2) >>> s3.key - u'key3' - >>> s3.members - set(['a', 'b']) + 'key3' + >>> s3.members == {'a', 'b'} + True >>> s1.clear() >>> s2.clear() >>> s3.clear() @@ -508,7 +507,7 @@ def lrange(self, start, stop): >>> l = List("test") >>> l.push(['a', 'b', 'c', 'd']) - 4L + 4 >>> l.lrange(1, 2) ['b', 'c'] >>> l.clear() @@ -525,7 +524,7 @@ def lpush(self, *values): >>> l = List("test") >>> l.lpush(['a', 'b']) - 2L + 2 >>> l.clear() """ return self.db.lpush(self.key, *_parse_values(values)) @@ -539,9 +538,9 @@ def rpush(self, *values): >>> l = List("test") >>> l.lpush(['a', 'b']) - 2L + 2 >>> l.rpush(['c', 'd']) - 4L + 4 >>> l.members ['b', 'a', 'c', 'd'] >>> l.clear() @@ -592,7 +591,7 @@ def rpoplpush(self, key): >>> l = List('list1') >>> l.push(['a', 'b', 'c']) - 3L + 3 >>> l.rpoplpush('list2') 'c' >>> l2 = List('list2') @@ -659,7 +658,7 @@ def lset(self, idx, value=0): >>> l = List('test') >>> l.push(['a', 'b', 'c']) - 3L + 3 >>> l.lset(0, 'e') True >>> l.members @@ -1214,7 +1213,7 @@ def hset(self, member, value): >>> h = Hash("foo") >>> h.hset("bar", "value") - 1L + 1 >>> h.clear() """ return self.db.hset(self.key, member, value) @@ -1228,7 +1227,7 @@ def hdel(self, *members): >>> h = Hash("foo") >>> h.hset("bar", "value") - 1L + 1 >>> h.hdel("bar") 1 >>> h.clear() @@ -1276,9 +1275,9 @@ def hincrby(self, field, increment=1): >>> h = Hash("foo") >>> h.hincrby("bar", 10) - 10L + 10 >>> h.hincrby("bar", 2) - 12L + 12 >>> h.clear() """ return self.db.hincrby(self.key, field, increment) diff --git a/redisco/containerstests.py b/redisco/containerstests.py index ec2fdbd42..18c24eb7b 100644 --- a/redisco/containerstests.py +++ b/redisco/containerstests.py @@ -349,7 +349,7 @@ def tearDown(self): self.client.flushdb() def test_basic_types(self): - alpha = cont.TypedList('alpha', six.text_type, type_args=('UTF-8',)) + alpha = cont.TypedList('alpha', six.text_type) monies = u'\u0024\u00a2\u00a3\u00a5' alpha.append(monies) val = alpha[-1] diff --git a/redisco/models/attributes.py b/redisco/models/attributes.py index f527192f4..12f351091 100644 --- a/redisco/models/attributes.py +++ b/redisco/models/attributes.py @@ -69,7 +69,8 @@ def __set__(self, instance, value): def typecast_for_read(self, value): """Typecasts the value for reading from Redis.""" # The redis client encodes all unicode data to utf-8 by default. - return value.decode('utf-8') + + return six.text_type(value) def typecast_for_storage(self, value): """Typecasts the value for storing to Redis.""" diff --git a/redisco/models/basetests.py b/redisco/models/basetests.py index f59629c8f..0a3cdb924 100644 --- a/redisco/models/basetests.py +++ b/redisco/models/basetests.py @@ -90,11 +90,11 @@ def test_unicode(self): def test_repr(self): person1 = Person(first_name="Granny", last_name="Goose") - self.assertEqual("", + self.assertEqual("", repr(person1)) self.assert_(person1.save()) - self.assertEqual("", + self.assertEqual("", repr(person1)) def test_update(self): diff --git a/redisco/models/modelset.py b/redisco/models/modelset.py index 6bfadf565..043959529 100644 --- a/redisco/models/modelset.py +++ b/redisco/models/modelset.py @@ -156,7 +156,7 @@ def exclude(self, **kwargs): >>> Foo(name="Edison", exclude_me=True).save() True >>> Foo.objects.exclude(exclude_me=True).first().name - u'Einstein' + 'Einstein' >>> [f.delete() for f in Foo.objects.all()] # doctest: +ELLIPSIS [...] """ @@ -190,9 +190,9 @@ def order(self, field): >>> Foo(name="Zztop").save() True >>> Foo.objects.all().order("-name").first().name - u'Zztop' + 'Zztop' >>> Foo.objects.all().order("name").first().name - u'Abba' + 'Abba' >>> [f.delete() for f in Foo.objects.all()] # doctest: +ELLIPSIS [...] """ diff --git a/requirements.txt b/requirements.txt index ed402347d..65e8e30fb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,3 @@ DateUtils==0.6.6 hiredis==0.1.1 redis>=2.7.5 -redislite>=1.0.228 \ No newline at end of file From d1b6543d8dcc2e5cde2d031ba5a789b72fabc9ec Mon Sep 17 00:00:00 2001 From: chan Date: Mon, 11 Sep 2017 15:26:02 +0800 Subject: [PATCH 07/10] Update travis config --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 77968275d..684dd6a7d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,7 @@ language: python python: - "2.6" - "2.7" + - "3.6" services: - redis-server # command to install redisco with dependencies From fc2f7a74169cb779b8de9d2bfcf774e8b2e39b5a Mon Sep 17 00:00:00 2001 From: chan Date: Wed, 13 Sep 2017 16:20:46 +0800 Subject: [PATCH 08/10] Update 0.3.0 --- .travis.yml | 2 +- requirements.txt | 2 +- setup.py | 5 +---- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 684dd6a7d..e74884e5a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,6 @@ services: - redis-server # command to install redisco with dependencies install: - - pip install . --use-mirrors + - pip install -r requirements.txt # command to run tests script: nosetests --with-doctest diff --git a/requirements.txt b/requirements.txt index 65e8e30fb..112c9c69e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ DateUtils==0.6.6 -hiredis==0.1.1 +hiredis==0.1.3 redis>=2.7.5 diff --git a/setup.py b/setup.py index 2467e0560..83b3ea3e8 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python import os -version = '0.2.9' +version = '0.3.0' try: from setuptools import setup @@ -18,9 +18,6 @@ def read(fname): download_url='', long_description=read('README.rst'), install_requires=read('requirements.txt').splitlines(), - extras_require = { - 'redislite': ["redislite>=1.0.228"] - }, author='Tim Medina', author_email='iamteem@gmail.com', maintainer='Sebastien Requiem', From 27f30c2484c89b200153cee12ea7d8bded73d6db Mon Sep 17 00:00:00 2001 From: chan Date: Wed, 13 Sep 2017 16:31:44 +0800 Subject: [PATCH 09/10] :green_heart: Update travis conf --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index e74884e5a..eaf6738dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,14 @@ language: python python: - "2.6" - "2.7" + - "3.4" + - "3.5" - "3.6" services: - redis-server # command to install redisco with dependencies install: + - pip install . - pip install -r requirements.txt # command to run tests script: nosetests --with-doctest From 20a2e42f1ef34ef2986ff4ab50311da6e8ab2410 Mon Sep 17 00:00:00 2001 From: chan Date: Wed, 13 Sep 2017 16:48:09 +0800 Subject: [PATCH 10/10] :white_check_mark: Update tests --- redisco/models/base.py | 4 ++-- redisco/models/basetests.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/redisco/models/base.py b/redisco/models/base.py index e2ea985e1..551571971 100644 --- a/redisco/models/base.py +++ b/redisco/models/base.py @@ -440,8 +440,8 @@ def attributes_dict(self): ... title = models.Attribute() ... >>> f = Foo(name="Einstein", title="Mr.") - >>> f.attributes_dict - {'name': 'Einstein', 'title': 'Mr.'} + >>> f.attributes_dict == {'name': 'Einstein', 'title': 'Mr.'} + True .. NOTE: the key ``id`` is present *only if* the object has been saved before. diff --git a/redisco/models/basetests.py b/redisco/models/basetests.py index 0a3cdb924..3cf29a57d 100644 --- a/redisco/models/basetests.py +++ b/redisco/models/basetests.py @@ -90,12 +90,12 @@ def test_unicode(self): def test_repr(self): person1 = Person(first_name="Granny", last_name="Goose") - self.assertEqual("", - repr(person1)) + self.assertEqual('Person', person1.__class__.__name__) + self.assertDictEqual({'first_name': 'Granny', 'last_name': 'Goose', 'active': False}, person1.attributes_dict) self.assert_(person1.save()) - self.assertEqual("", - repr(person1)) + self.assertEqual('Person:1', person1.key()) + self.assertDictEqual({'first_name': 'Granny', 'last_name': 'Goose', 'active': False, 'id': '1'}, person1.attributes_dict) def test_update(self): person1 = Person(first_name="Granny", last_name="Goose")