Skip to content

Commit

Permalink
improving null verificatio and introducing __getitem__
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrielfalcao committed Sep 5, 2015
1 parent bf0ac65 commit 5a09390
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 21 deletions.
19 changes: 19 additions & 0 deletions docs/source/tutorial.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,25 @@ Retrieving an item by its id
}


Manipulating in-memory data
^^^^^^^^^^^^^^^^^^^^^^^^^^^

You can get the valus of an instance with either ``.attribute``` notation or ``["attribute"]``.

::

>>> harry = User.objects.get(id='970773fa-4de1-11e5-86f4-6c4008a70392')
>>> harry.id
UUID('970773fa-4de1-11e5-86f4-6c4008a70392')


::

>>> harry['id']
UUID('970773fa-4de1-11e5-86f4-6c4008a70392')



Deleting a record from redis
^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
49 changes: 31 additions & 18 deletions repocket/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from __future__ import unicode_literals
import json
import importlib

import logging
import dateutil.parser

from uuid import UUID as PythonsUUID
Expand All @@ -13,10 +13,23 @@
from repocket._cache import MODELS


logger = logging.getLogger("repocket.attributes")


def get_current_time(field):
return datetime.utcnow()


def is_null(value):
if not value:
return True

if isinstance(value, basestring) and value.lower() in ['none', json.dumps(None)]:
return True

return False


class Attribute(object):
"""Repocket treats its models and attributes as fully serializable.
Every attribute contains a ``to_python`` method that knows how to
Expand All @@ -33,7 +46,11 @@ def __init__(self, null=False, default=None, encoding='utf-8'):

def to_string(self, value):
"""Utility method that knows how to safely convert the value into a string"""
return bytes(self.cast(value))
converted = self.cast(value)
if isinstance(converted, unicode):
converted = converted.encode(self.encoding)

return bytes(converted)

def from_string(self, value):
return self.cast(value)
Expand Down Expand Up @@ -91,7 +108,7 @@ def to_json(self, value, simple=False):
return json.dumps(data, default=bytes)


class AutoUUID(Attribute):
class UUID(Attribute):
"""Automatically assigns a uuid1 as the value.
``__base_type__ = uuid.UUID``
"""
Expand All @@ -102,28 +119,21 @@ def cast(cls, value):
if isinstance(value, PythonsUUID):
return value

if not value:
if is_null(value):
return

return super(AutoUUID, cls).cast(value)
try:
return cls.__base_type__(value)
except ValueError as e:
raise ValueError(": ".join([str(e), repr(value)]))


class UUID(Attribute):
class AutoUUID(UUID):
"""Automatically assigns a uuid1 as the value.
``__base_type__ = uuid.UUID``
"""
__base_type__ = PythonsUUID

@classmethod
def cast(cls, value):
if isinstance(value, PythonsUUID):
return value

if not value:
return

return super(UUID, cls).cast(value)


class Unicode(Attribute):
"""Handles unicode-safe values
Expand All @@ -132,6 +142,9 @@ class Unicode(Attribute):
__base_type__ = unicode
__empty_value__ = u''

def to_string(self, value):
return self.__base_type__(value)


class Bytes(Attribute):
"""Handles raw byte strings
Expand Down Expand Up @@ -188,7 +201,7 @@ def __init__(self, auto_now=False, null=False):

@classmethod
def cast(cls, value):
if not value or value == json.dumps(None):
if is_null(value):
return

if isinstance(value, datetime):
Expand Down Expand Up @@ -228,7 +241,7 @@ def to_string(self, value):
@classmethod
def cast(cls, value):
"""this method uses a redis connection to retrieve the referenced item"""
if value == json.dumps(None):
if is_null(value):
return

try:
Expand Down
14 changes: 12 additions & 2 deletions repocket/model.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import uuid
import logging

from repocket import attributes
from repocket.connections import configure
from repocket.registry import ActiveRecordRegistry


logger = logging.getLogger("repocket.model")

class ActiveRecord(object):
"""base model class, this is how you declare your active record.
Expand Down Expand Up @@ -44,6 +47,13 @@ def __repr__(self):
attributes = ', '.join(['{0}={1}'.format(k, v) for k, v in self.to_dict().items()])
return '{0}({1})'.format(self.__compound_name__, attributes)

def __getitem__(self, name):
options = self.__fields__.keys()
if name not in options:
raise KeyError("{0} is not a valid field in {1}, options are {2}".format(name, self, options))

return getattr(self, name)

def __eq__(self, other):
if not isinstance(other, self.__class__):
raise TypeError('Cannot compare {0} with {1}'.format(self, other))
Expand Down Expand Up @@ -172,8 +182,8 @@ def to_dict(self, simple=False):
try:
serialized_value = field.to_json(value)

except (AttributeError, TypeError) as e:
raise TypeError('Failed to serialize field {0}.{1} of type {2} with value: {3} - {4}'.format(
except Exception as e:
logger.error('Failed to serialize field {0}.{1} of type {2} with value: {3} - {4}'.format(
self.__class__.__name__,
name,
type(value),
Expand Down
2 changes: 1 addition & 1 deletion tests/unit/test_attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def test_unicode_to_string():
result = instance.to_string(str(test_uuid))

# Then the result should be a string
result.should.be.a(bytes)
result.should.be.a(unicode)


def test_unicode_from_string():
Expand Down
8 changes: 8 additions & 0 deletions tests/unit/test_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,11 @@ def test_equality_failed():
' "repocket.attributes"}\'}, '
'strings={\'contents\': \'123\'})'
)


def test_getitem():
('ActiveRecord should behave like a dict by letting you retrieve values using [] notation')

item1 = UnitModelOne(id='059f3270-9e73-4d53-9970-443f83e412a0', contents=b'123')
item1['id'].should.equal('059f3270-9e73-4d53-9970-443f83e412a0')
item1['contents'].should.equal('123')

0 comments on commit 5a09390

Please sign in to comment.