Navigation Menu

Skip to content

Commit

Permalink
devilry|devilry_rest: Moved rest stuff from devilry.utils to devilry_…
Browse files Browse the repository at this point in the history
…rest.

Kept the modules in devilry.utils, with deprecation warnings.
  • Loading branch information
espenak committed Jun 12, 2013
1 parent db7db65 commit 1c400e8
Show file tree
Hide file tree
Showing 8 changed files with 187 additions and 172 deletions.
46 changes: 3 additions & 43 deletions src/devilry/devilry/utils/rest_testclient.py
@@ -1,43 +1,3 @@
from django.test import Client
import json


class RestClient(Client):
"""
Extends the ``django.test.Client`` with methods for the REST verbs and
application/json.
"""

def _load_json(self, content):
if content.strip() == '':
return None
try:
return json.loads(content)
except ValueError, e:
raise ValueError('{0}: {1}'.format(e, content))

def rest_post(self, url, data):
response = self.post(url,
data=json.dumps(data),
content_type="application/json",
HTTP_ACCEPT="application/json")
return self._load_json(response.content), response

def rest_put(self, url, data, **extra):
response = self.put(url,
data=json.dumps(data),
content_type="application/json",
HTTP_ACCEPT="application/json",
**extra)
return self._load_json(response.content), response

def rest_get(self, url, **data):
response = self.get(url,
data=data,
HTTP_ACCEPT="application/json")
return self._load_json(response.content), response

def rest_delete(self, url):
response = self.delete(url,
HTTP_ACCEPT="application/json")
return self._load_json(response.content), response
import warnings
warnings.warn("devilry.utils.rest_testclient is deprecated. Use devilry_rest.testclient instead.", DeprecationWarning)
from devilry_rest.testclient import RestClient
24 changes: 5 additions & 19 deletions src/devilry/devilry/utils/restformat.py
@@ -1,19 +1,5 @@
def format_datetime(datetime):
return datetime.strftime('%Y-%m-%d %H:%M:%S')

def format_timedelta(timedelta_obj):
total_seconds = abs(timedelta_obj.total_seconds())
days, remainder = divmod(total_seconds, 86400)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
return {'days': int(days),
'hours': int(hours),
'minutes': int(minutes),
'seconds': int(seconds)}

def serialize_user(user):
return {'id': user.id,
'username': user.username,
'email': user.email,
'displayname': user.devilryuserprofile.full_name or user.username,
'full_name': user.devilryuserprofile.full_name}
import warnings
warnings.warn("devilry.utils.restformat is deprecated. Use devilry_rest.serializehelpers instead.", DeprecationWarning)
from devilry_rest.serializehelpers import format_datetime
from devilry_rest.serializehelpers import format_timedelta
from devilry_rest.serializehelpers import serialize_user
114 changes: 5 additions & 109 deletions src/devilry/devilry/utils/restformfields.py
@@ -1,109 +1,5 @@
"""
Form fields that are useful only for REST APIs.
"""
from django import forms
from django.core.exceptions import ValidationError


class ListOfDictField(forms.Field):

def validate_to_python(self, value):
"""
Validate and clean data.
"""
super(ListOfDictField, self).validate(value)
if value == None:
return []
if not isinstance(value, (list, tuple)):
raise ValidationError('Must be a list or tuple, got {0}'.format(type(value).__name__))
cleaned = []
for index, dct in enumerate(value):
if not isinstance(dct, dict):
raise ValidationError('Item {0}: Must be a list of dicts, got {1}'.format(index, type(value)))
form = self.Form(dct)
if form.is_valid():
cleaned.append(form.cleaned_data)
else:
errors = form.errors.as_text()
raise ValidationError('Item {0}: Invalid format:\n{1}'.format(index, errors))
return cleaned

def clean(self, value):
"""
Validates the given value and returns its "cleaned" value as an
appropriate Python object.
Raises ValidationError for any errors.
"""
value = self.validate_to_python(value)
self.run_validators(value)
return value

class DictField(forms.Field):

def validate_to_python(self, value):
"""
Validate and clean data.
"""
super(DictField, self).validate(value)
if value == None:
return {}
if not isinstance(value, dict):
raise ValidationError('Must be a dict, got {0}'.format(type(value).__name__))
form = self.Form(value)
if form.is_valid():
return form.cleaned_data
else:
errors = form.errors.as_text()
raise ValidationError(errors)

def clean(self, value):
"""
Validates the given value and returns its "cleaned" value as an
appropriate Python object.
Raises ValidationError for any errors.
"""
value = self.validate_to_python(value)
self.run_validators(value)
return value


class ListOfTypedField(forms.Field):
def __init__(self, *args, **kwargs):
"""
A field similar to TypedChoiceField that takes a list of items and a
``coerce`` function that is applied to all items in the given list.
"""
self.coerce = kwargs.pop('coerce', id)
super(ListOfTypedField, self).__init__(*args, **kwargs)

def validate_to_python(self, valuelist):
"""
Validate and clean data.
"""
super(ListOfTypedField, self).validate(valuelist)
if valuelist == None:
return []
if not isinstance(valuelist, (list, tuple)):
raise ValidationError('Must be a list or tuple, got {0}'.format(type(valuelist).__name__))
cleaned = []
for index, value in enumerate(valuelist):
try:
cleaned_value = self.coerce(value)
except ValueError, e:
raise ValidationError('Item {0}: {1}', index, e)
else:
cleaned.append(cleaned_value)
return cleaned

def clean(self, value):
"""
Validates the given value and returns its "cleaned" value as an
appropriate Python object.
Raises ValidationError for any errors.
"""
value = self.validate_to_python(value)
self.run_validators(value)
return value
import warnings
warnings.warn("devilry.utils.restformfields is deprecated. Use devilry_rest.formfields instead.", DeprecationWarning)
from devilry_rest.formfields import ListOfDictField
from devilry_rest.formfields import DictField
from devilry_rest.formfields import ListOfTypedField
1 change: 1 addition & 0 deletions src/devilry/setup.py
Expand Up @@ -16,5 +16,6 @@
#'flup',
#'PyYAML',
'django-celery',
'devilry_rest', # NOTE: We only need this until all modules importing from ``devilry.utils.rest*`` is updated
'gunicorn']
)
2 changes: 1 addition & 1 deletion src/devilry_examiner/setup.py
Expand Up @@ -14,7 +14,7 @@
'devilry_extjsextras',
'django_seleniumhelpers', 'django_extjs4',
'djangosenchatools',
'django-simple-rest',
'devilry_rest',
],
include_package_data=True,
long_description = open(join(this_dir, 'README.rst')).read().strip(),
Expand Down
110 changes: 110 additions & 0 deletions src/devilry_rest/devilry_rest/formfields.py
@@ -0,0 +1,110 @@
"""
Form fields that are useful only for REST APIs.
"""
from django import forms
from django.core.exceptions import ValidationError


class ListOfDictField(forms.Field):

def validate_to_python(self, value):
"""
Validate and clean data.
"""
super(ListOfDictField, self).validate(value)
if value == None:
return []
if not isinstance(value, (list, tuple)):
raise ValidationError('Must be a list or tuple, got {0}'.format(type(value).__name__))
cleaned = []
for index, dct in enumerate(value):
if not isinstance(dct, dict):
raise ValidationError('Item {0}: Must be a list of dicts, got {1}'.format(index, type(value)))
form = self.Form(dct)
if form.is_valid():
cleaned.append(form.cleaned_data)
else:
errors = form.errors.as_text()
raise ValidationError('Item {0}: Invalid format:\n{1}'.format(index, errors))
return cleaned

def clean(self, value):
"""
Validates the given value and returns its "cleaned" value as an
appropriate Python object.
Raises ValidationError for any errors.
"""
value = self.validate_to_python(value)
self.run_validators(value)
return value

class DictField(forms.Field):

def validate_to_python(self, value):
"""
Validate and clean data.
"""
super(DictField, self).validate(value)
if value == None:
return {}
if not isinstance(value, dict):
raise ValidationError('Must be a dict, got {0}'.format(type(value).__name__))
form = self.Form(value)
if form.is_valid():
return form.cleaned_data
else:
errors = form.errors.as_text()
raise ValidationError(errors)

def clean(self, value):
"""
Validates the given value and returns its "cleaned" value as an
appropriate Python object.
Raises ValidationError for any errors.
"""
value = self.validate_to_python(value)
self.run_validators(value)
return value


class ListOfTypedField(forms.Field):
def __init__(self, *args, **kwargs):
"""
A field similar to TypedChoiceField that takes a list of items and a
``coerce`` function that is applied to all items in the given list.
"""
self.coerce = kwargs.pop('coerce', id)
super(ListOfTypedField, self).__init__(*args, **kwargs)

def validate_to_python(self, valuelist):
"""
Validate and clean data.
"""
super(ListOfTypedField, self).validate(valuelist)
if valuelist == None:
return []
if not isinstance(valuelist, (list, tuple)):
raise ValidationError('Must be a list or tuple, got {0}'.format(type(valuelist).__name__))
cleaned = []
for index, value in enumerate(valuelist):
try:
cleaned_value = self.coerce(value)
except ValueError, e:
raise ValidationError('Item {0}: {1}', index, e)
else:
cleaned.append(cleaned_value)
return cleaned

def clean(self, value):
"""
Validates the given value and returns its "cleaned" value as an
appropriate Python object.
Raises ValidationError for any errors.
"""
value = self.validate_to_python(value)
self.run_validators(value)
return value

19 changes: 19 additions & 0 deletions src/devilry_rest/devilry_rest/serializehelpers.py
@@ -0,0 +1,19 @@
def format_datetime(datetime):
return datetime.strftime('%Y-%m-%d %H:%M:%S')

def format_timedelta(timedelta_obj):
total_seconds = abs(timedelta_obj.total_seconds())
days, remainder = divmod(total_seconds, 86400)
hours, remainder = divmod(remainder, 3600)
minutes, seconds = divmod(remainder, 60)
return {'days': int(days),
'hours': int(hours),
'minutes': int(minutes),
'seconds': int(seconds)}

def serialize_user(user):
return {'id': user.id,
'username': user.username,
'email': user.email,
'displayname': user.devilryuserprofile.full_name or user.username,
'full_name': user.devilryuserprofile.full_name}
43 changes: 43 additions & 0 deletions src/devilry_rest/devilry_rest/testclient.py
@@ -0,0 +1,43 @@
from django.test import Client
import json


class RestClient(Client):
"""
Extends the ``django.test.Client`` with methods for the REST verbs and
application/json.
"""

def _load_json(self, content):
if content.strip() == '':
return None
try:
return json.loads(content)
except ValueError, e:
raise ValueError('{0}: {1}'.format(e, content))

def rest_post(self, url, data):
response = self.post(url,
data=json.dumps(data),
content_type="application/json",
HTTP_ACCEPT="application/json")
return self._load_json(response.content), response

def rest_put(self, url, data, **extra):
response = self.put(url,
data=json.dumps(data),
content_type="application/json",
HTTP_ACCEPT="application/json",
**extra)
return self._load_json(response.content), response

def rest_get(self, url, **data):
response = self.get(url,
data=data,
HTTP_ACCEPT="application/json")
return self._load_json(response.content), response

def rest_delete(self, url):
response = self.delete(url,
HTTP_ACCEPT="application/json")
return self._load_json(response.content), response

0 comments on commit 1c400e8

Please sign in to comment.