Permalink
Browse files

Refactor serialization

  • Loading branch information...
1 parent 31370a4 commit e7fb9bcd8fd950c0fb2c4caea0549ee21f631997 @klen committed Sep 28, 2012
View
@@ -7,3 +7,4 @@ dist
*.egg
.vimrc
.tags
+._
View
@@ -4,29 +4,42 @@ ALLSPHINXOPTS= -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
BUILDDIR=_build
+.PHONY: help
+# target: help - Display callable targets
+help:
+ @egrep "^# target:" [Mm]akefile
+
.PHONY: clean
+# target: clean - Display callable targets
clean:
- sudo rm -rf build dist docs/_build
- find . -name "*.pyc" -delete
- find . -name "*.orig" -delete
+ @rm -rf build dist docs/_build
+ @rm -f *.py[co]
+ @rm -f *.orig
+ @rm -f */*.py[co]
+ @rm -f */*.orig
.PHONY: register
+# target: register - Register module on PyPi
register:
- python setup.py register
+ @python setup.py register
.PHONY: upload
+# target: upload - Upload module on PyPi
upload: doc
- python setup.py sdist upload || echo 'Upload already'
+ @python setup.py sdist upload || echo 'Upload already'
.PHONY: test
-test:
- python setup.py test
+# target: test - Runs tests
+test: clean
+ @python setup.py test
.PHONY: audit
+# target: audit - Audit code
audit:
- pylama $(MODULE) -i E501
+ @pylama $(MODULE) -i E501
-.PHONY: doc
-doc:
+.PHONY: docs
+# target: docs - Compile and upload docs
+docs:
python setup.py build_sphinx --source-dir=docs/ --build-dir=docs/_build --all-files
python setup.py upload_sphinx --upload-dir=docs/_build/html
View
@@ -12,14 +12,22 @@
class Api(object):
+
""" Implements a registry to tie together the various resources that make up
an API.
- Especially useful for navigation, HATEOAS and for providing multiple
- versions of your API.
+ Especially useful for navigation, providing multiple versions of your API.
+
+ :param version: Version info as string or iterable.
+ :param api_map: Enable API map (true by default)
+ :param api_prefix: API Url prefix ('api' by default)
+ :param api_rpc: Enable automatic Json RPC (default false)
+
+ Additional params will be putted in self resources.
+
"""
def __init__(self, version=None, api_map=True, api_prefix='api', api_rpc=False, **params):
- self.version = version
+ self.version = self.str_version = version
self.prefix = api_prefix
self.params = params
self.resources = dict()
@@ -32,13 +40,22 @@ def __init__(self, version=None, api_map=True, api_prefix='api', api_rpc=False,
if api_rpc:
self.resources[RPCResource.meta.url_name] = RPCResource
- try:
- self.str_version = '.'.join(map(str, version or list()))
- except TypeError:
- self.str_version = str(version)
+ if not isinstance(self.str_version, basestring):
+ try:
+ self.str_version = '.'.join(map(str, version or list()))
+ except TypeError:
+ self.str_version = str(version)
+
+ def __str__(self):
+ return self.str_version
def register(self, resource, **params):
- " Registers resource subclass for the API. "
+ """ Registers resource for the API.
+
+ :param resource: Resource class for registration
+
+ Additional params will be putted in the resource.
+ """
# Must be instance of ResourceView
assert issubclass(resource, ResourceView), "%s not subclass of ResourceView" % resource
@@ -73,6 +90,3 @@ def urls(self):
))
return patterns(self.prefix, *urls)
-
- def __str__(self):
- return self.str_version
View
@@ -1,4 +1,5 @@
from django.db import models
+from django.utils.encoding import smart_unicode
from adrest import settings
from adrest.signals import api_request_finished
@@ -51,19 +52,14 @@ def save_log(sender, response=None, request=None, **resources):
if not resource.log:
return
- try:
- content = response.content.decode('utf-8')[:5000]
- except (UnicodeDecodeError, UnicodeEncodeError):
- content = response.content[:5000]
-
Access.objects.create(
uri=request.path_info,
method=request.method,
version=str(resource.api),
status_code=response.status_code,
request='%s\n\n%s' % (str(request.META), str(getattr(request, 'data', ''))),
identifier=resource.identifier or request.META.get('REMOTE_ADDR', 'anonymous'),
- response=content,
+ response=smart_unicode(response.content)[:5000],
)
api_request_finished.connect(save_log)
View
@@ -17,7 +17,8 @@ class MapResource(ResourceView):
url_regex = r'^map$'
def get(self, *args, **Kwargs):
- return self.api.str_version, list(self.gen_apimap())
+ selfmap = list(self.gen_apimap())
+ return self.api.str_version, selfmap
def gen_apimap(self):
for url_name in sorted(self.api.resources.iterkeys()):
View
@@ -1,5 +1,12 @@
" Adrest API settings. "
-from django.conf import settings
+try:
+ from django.conf import settings
+
+ getattr(settings, 'DEBUG')
+
+except ImportError:
+
+ settings.configure()
from .utils.tools import as_tuple
View
@@ -37,9 +37,10 @@ def adrest_include(parser, token):
adrest_include = register.tag(adrest_include)
-def adrest_jsonify(content, **kwargs):
+def adrest_jsonify(content, **options):
" Serialize to JSON any object. "
- from adrest.utils.serializer import json_dumps
- return json_dumps(content)
+ from adrest.utils.serializer import JSONSerializer
+ worker = JSONSerializer(**options)
+ return worker.serialize(content)
adrest_jsonify = register.simple_tag(adrest_jsonify)
View
@@ -3,8 +3,6 @@
from django.contrib.auth import authenticate
-from ..models import AccessKey
-
class AbstractAuthenticator(object):
" Abstract base authenticator "
@@ -97,17 +95,23 @@ def get_fields(cls):
return [(cls.username_fieldname, dict(required=True)), (cls.password_fieldname, dict(required=True))]
-class AccessKeyAuthenticator(UserLoggedInAuthenticator):
- " Authorization by API token. "
+try:
+ from ..models import AccessKey
- def authenticate(self, request=None):
- """ Authenticate user using AccessKey from HTTP Header or GET params.
- """
- try:
- token = request.META.get('HTTP_AUTHORIZATION') or request.REQUEST['key']
- accesskey = AccessKey.objects.select_related('user').get(key=token)
- request.user = accesskey.user
- return request.user and request.user.is_active
+ class AccessKeyAuthenticator(UserLoggedInAuthenticator):
+ " Authorization by API token. "
- except(KeyError, AccessKey.DoesNotExist):
- return False
+ def authenticate(self, request=None):
+ """ Authenticate user using AccessKey from HTTP Header or GET params.
+ """
+ try:
+ token = request.META.get('HTTP_AUTHORIZATION') or request.REQUEST['key']
+ accesskey = AccessKey.objects.select_related('user').get(key=token)
+ request.user = accesskey.user
+ return request.user and request.user.is_active
+
+ except(KeyError, AccessKey.DoesNotExist):
+ return False
+
+except ImportError:
+ pass
View
@@ -9,7 +9,7 @@
from ..utils import UpdatedList
from .paginator import Paginator
from .response import SerializedHttpResponse
-from .serializer import json_dumps, xml_dumps
+from .serializer import JSONSerializer, XMLSerializer
from .status import HTTP_200_OK
@@ -64,17 +64,24 @@ def serialize(content):
class JSONEmitter(BaseEmitter):
media_type = 'application/json'
- @staticmethod
- def serialize(content):
- return json_dumps(content)
+ def serialize(self, content):
+ worker = JSONSerializer(
+ _fields=getattr(self.resource, 'fields', None),
+ _include=getattr(self.resource, 'include', None),
+ _exclude=getattr(self.resource, 'exclude', None),
+ **getattr(self.resource, 'related', dict())
+ )
+ return worker.serialize(content)
-class JSONPEmitter(BaseEmitter):
+class JSONPEmitter(JSONEmitter):
media_type = 'text/javascript'
def serialize(self, content):
+ content = super(JSONPEmitter, self).serialize(content)
+
callback = self.request.GET.get('callback', 'callback')
- return '%s(%s)' % (callback, json_dumps(content))
+ return u'%s(%s)' % (callback, content)
class XMLEmitter(BaseEmitter):
@@ -83,11 +90,17 @@ class XMLEmitter(BaseEmitter):
xmldoc_tpl = '<?xml version="1.0" encoding="utf-8"?>\n<response success="%s" version="%s" timestamp="%s">%s</response>'
def serialize(self, content):
+ worker = XMLSerializer(
+ _fields=getattr(self.resource, 'fields', None),
+ _include=getattr(self.resource, 'include', None),
+ _exclude=getattr(self.resource, 'exclude', None),
+ **getattr(self.resource, 'related', dict())
+ )
return self.xmldoc_tpl % (
'true' if self.response.status_code == HTTP_200_OK else 'false',
self.resource.version,
int(mktime(datetime.now().timetuple())),
- xml_dumps(content)
+ worker.serialize(content)
)
Oops, something went wrong.

0 comments on commit e7fb9bc

Please sign in to comment.