From 8bad0cdc2f78426c0bcd67fcab9f70b6e442be51 Mon Sep 17 00:00:00 2001 From: Vladimir Rudnyh Date: Thu, 9 Oct 2014 15:51:31 +0400 Subject: [PATCH 1/3] Add UTC timezone designator for datetime regex --- json_field/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json_field/fields.py b/json_field/fields.py index d6e172d..2545758 100644 --- a/json_field/fields.py +++ b/json_field/fields.py @@ -29,7 +29,7 @@ TIME_FMT = r'\d{2}:\d{2}:\d{2}(\.\d+)?' DATE_FMT = r'\d{4}-\d{2}-\d{2}' -TIMEZONE_FMT = r'(\+|\-)\d{2}:\d{2}' +TIMEZONE_FMT = r'((\+|\-)\d{2}:\d{2}|Z)' TIME_RE = re.compile(r'^(%s)$' % TIME_FMT) DATE_RE = re.compile(r'^(%s)$' % DATE_FMT) From 1b67651b0c098bab407ce879347ec597386ceed0 Mon Sep 17 00:00:00 2001 From: Vladimir Rudnyh Date: Thu, 9 Oct 2014 15:54:26 +0400 Subject: [PATCH 2/3] Simplify and speedup datetime regexes --- json_field/fields.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/json_field/fields.py b/json_field/fields.py index 2545758..ef498d2 100644 --- a/json_field/fields.py +++ b/json_field/fields.py @@ -27,13 +27,13 @@ except AttributeError: JSON_DECODE_ERROR = ValueError # other -TIME_FMT = r'\d{2}:\d{2}:\d{2}(\.\d+)?' +TIME_FMT = r'\d{2}:\d{2}:\d{2}(?:\.\d+)?' DATE_FMT = r'\d{4}-\d{2}-\d{2}' -TIMEZONE_FMT = r'((\+|\-)\d{2}:\d{2}|Z)' +TIMEZONE_FMT = r'(?:[+-]\d{2}:\d{2}|Z)' -TIME_RE = re.compile(r'^(%s)$' % TIME_FMT) -DATE_RE = re.compile(r'^(%s)$' % DATE_FMT) -DATETIME_RE = re.compile(r'^(%s)T(%s)(%s)?$' % (DATE_FMT, TIME_FMT, TIMEZONE_FMT)) +TIME_RE = re.compile(r'^%s$' % TIME_FMT) +DATE_RE = re.compile(r'^%s$' % DATE_FMT) +DATETIME_RE = re.compile(r'^%sT%s(?:%s)?$' % (DATE_FMT, TIME_FMT, TIMEZONE_FMT)) class JSONEncoder(json.JSONEncoder): """ From b5648aa47c87e258729078f421aa074f5614314f Mon Sep 17 00:00:00 2001 From: Vladimir Rudnyh Date: Thu, 9 Oct 2014 15:56:52 +0400 Subject: [PATCH 3/3] PEP8 --- json_field/fields.py | 45 ++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/json_field/fields.py b/json_field/fields.py index ef498d2..5acf25c 100644 --- a/json_field/fields.py +++ b/json_field/fields.py @@ -9,7 +9,6 @@ from django.utils import simplejson as json from django.db import models -from django.core import exceptions from django.utils.translation import ugettext_lazy as _ from django.core.exceptions import ImproperlyConfigured @@ -20,20 +19,23 @@ try: from dateutil import parser as date_parser except ImportError: - raise ImproperlyConfigured('The "dateutil" library is required and was not found.') + raise ImproperlyConfigured( + 'The "dateutil" library is required and was not found.' + ) try: - JSON_DECODE_ERROR = json.JSONDecodeError # simplejson + JSON_DECODE_ERROR = json.JSONDecodeError # simplejson except AttributeError: - JSON_DECODE_ERROR = ValueError # other + JSON_DECODE_ERROR = ValueError # other TIME_FMT = r'\d{2}:\d{2}:\d{2}(?:\.\d+)?' DATE_FMT = r'\d{4}-\d{2}-\d{2}' -TIMEZONE_FMT = r'(?:[+-]\d{2}:\d{2}|Z)' +TIMEZONE_FMT = r'(?:[+-]\d{2}:\d{2}|Z)?' TIME_RE = re.compile(r'^%s$' % TIME_FMT) DATE_RE = re.compile(r'^%s$' % DATE_FMT) -DATETIME_RE = re.compile(r'^%sT%s(?:%s)?$' % (DATE_FMT, TIME_FMT, TIMEZONE_FMT)) +DATETIME_RE = re.compile(r'^%sT%s%s$' % (DATE_FMT, TIME_FMT, TIMEZONE_FMT)) + class JSONEncoder(json.JSONEncoder): """ @@ -62,6 +64,7 @@ def default(self, o): else: return super(JSONEncoder, self).default(o) + class JSONDecoder(json.JSONDecoder): """ Recursive JSON to Python deserialization. """ @@ -100,6 +103,7 @@ def decode(self, obj, *args, **kwargs): pass return obj + class Creator(object): """ Taken from django.db.models.fields.subclassing. @@ -133,7 +137,11 @@ def __get__(self, obj, type=None): return value def __set__(self, obj, value): - obj.__dict__[self.field.name] = value if self.lazy else self.field.to_python(value) + if self.lazy: + obj.__dict__[self.field.name] = value + else: + obj.__dict__[self.field.name] = self.field.to_python(value) + class JSONField(models.TextField): """ Stores and loads valid JSON objects. """ @@ -153,14 +161,19 @@ def __init__(self, *args, **kwargs): encoder_kwargs = kwargs.pop('encoder_kwargs', {}) decoder_kwargs = kwargs.pop('decoder_kwargs', {}) if not encoder_kwargs and encoder: - encoder_kwargs.update({'cls':encoder}) + encoder_kwargs.update({'cls': encoder}) if not decoder_kwargs and decoder: - decoder_kwargs.update({'cls':decoder, 'parse_float':decimal.Decimal}) + decoder_kwargs.update({ + 'cls': decoder, + 'parse_float': decimal.Decimal, + }) self.encoder_kwargs = encoder_kwargs self.decoder_kwargs = decoder_kwargs kwargs['default'] = kwargs.get('default', 'null') - kwargs['help_text'] = kwargs.get('help_text', self.default_error_messages['invalid']) + kwargs['help_text'] = kwargs.get( + 'help_text', self.default_error_messages['invalid'] + ) super(JSONField, self).__init__(*args, **kwargs) @@ -170,7 +183,7 @@ def db_type(self, *args, **kwargs): return super(JSONField, self).db_type(*args, **kwargs) def to_python(self, value): - if value is None: # allow blank objects + if value is None: # allow blank objects return None if isinstance(value, six.string_types): try: @@ -188,7 +201,8 @@ def value_to_string(self, obj): return self.get_db_prep_value(self._get_val_from_obj(obj)) def value_from_object(self, obj): - return json.dumps(super(JSONField, self).value_from_object(obj), **self.encoder_kwargs) + return json.dumps(super(JSONField, self).value_from_object(obj), + **self.encoder_kwargs) def formfield(self, **kwargs): defaults = { @@ -204,14 +218,17 @@ def contribute_to_class(self, cls, name): super(JSONField, self).contribute_to_class(cls, name) def get_json(model_instance): - return self.get_db_prep_value(getattr(model_instance, self.attname, None), force=True) + return self.get_db_prep_value( + getattr(model_instance, self.attname, None), force=True + ) setattr(cls, 'get_%s_json' % self.name, get_json) def set_json(model_instance, value): return setattr(model_instance, self.attname, self.to_python(value)) setattr(cls, 'set_%s_json' % self.name, set_json) - setattr(cls, name, Creator(self, lazy=self.lazy)) # deferred deserialization + # deferred deserialization + setattr(cls, name, Creator(self, lazy=self.lazy)) try: # add support for South migrations