pull in markos changes, minor tweaks to yaml stuff

This commit is contained in:
Tom Christie 2011-07-01 17:44:08 +01:00
commit f7b7778a79
15 changed files with 172 additions and 28 deletions

View File

@ -156,6 +156,7 @@ except ImportError:
def head(self, request, *args, **kwargs):
return self.get(request, *args, **kwargs)
# Markdown is optional
try:
import markdown
import re
@ -204,3 +205,9 @@ try:
except ImportError:
apply_markdown = None
# Yaml is optional
try:
import yaml
except ImportError:
yaml = None

View File

@ -16,15 +16,18 @@ from django.http.multipartparser import MultiPartParser as DjangoMultiPartParser
from django.http.multipartparser import MultiPartParserError
from django.utils import simplejson as json
from djangorestframework import status
from djangorestframework.compat import yaml
from djangorestframework.response import ErrorResponse
from djangorestframework.utils.mediatypes import media_type_matches
__all__ = (
'BaseParser',
'JSONParser',
'PlainTextParser',
'FormParser',
'MultiPartParser',
'YAMLParser',
)
@ -85,6 +88,27 @@ class JSONParser(BaseParser):
{'detail': 'JSON parse error - %s' % unicode(exc)})
if yaml:
class YAMLParser(BaseParser):
"""
Parses YAML-serialized data.
"""
media_type = 'application/yaml'
def parse(self, stream):
"""
Returns a 2-tuple of `(data, files)`.
`data` will be an object which is the parsed content of the response.
`files` will always be `None`.
"""
try:
return (yaml.safe_load(stream), None)
except ValueError, exc:
raise ErrorResponse(status.HTTP_400_BAD_REQUEST,
{'detail': 'YAML parse error - %s' % unicode(exc)})
class PlainTextParser(BaseParser):
"""

View File

@ -11,16 +11,14 @@ from django.core.serializers.json import DateTimeAwareJSONEncoder
from django.template import RequestContext, loader
from django.utils import simplejson as json
from djangorestframework import status
from djangorestframework.compat import apply_markdown
from djangorestframework.compat import apply_markdown, yaml
from djangorestframework.utils import dict2xml, url_resolves
from djangorestframework.utils.breadcrumbs import get_breadcrumbs
from djangorestframework.utils.description import get_name, get_description
from djangorestframework.utils.mediatypes import get_media_type_params, add_media_type_param, media_type_matches
from djangorestframework import VERSION
from decimal import Decimal
import re
import string
from urllib import quote_plus
@ -31,7 +29,8 @@ __all__ = (
'DocumentingHTMLRenderer',
'DocumentingXHTMLRenderer',
'DocumentingPlainTextRenderer',
'XMLRenderer'
'XMLRenderer',
'YAMLRenderer'
)
@ -131,6 +130,27 @@ class XMLRenderer(BaseRenderer):
return dict2xml(obj)
if yaml:
class YAMLRenderer(BaseRenderer):
"""
Renderer which serializes to YAML.
"""
media_type = 'application/yaml'
format = 'yaml'
def render(self, obj=None, media_type=None):
"""
Renders *obj* into serialized YAML.
"""
if obj is None:
return ''
return yaml.dump(obj)
else:
YAMLRenderer = None
class TemplateRenderer(BaseRenderer):
"""
A Base class provided for convenience.
@ -361,4 +381,5 @@ DEFAULT_RENDERERS = ( JSONRenderer,
DocumentingPlainTextRenderer,
XMLRenderer )
if YAMLRenderer:
DEFAULT_RENDERERS += (YAMLRenderer,)

View File

@ -8,6 +8,8 @@
#site-name a {color: #F4F379 !important;}
.errorlist {display: inline !important}
.errorlist li {display: inline !important; background: white !important; color: black !important; border: 0 !important;}
/* Custom styles */
.version{font-size:8px;}
</style>
<link rel="stylesheet" type="text/css" href='{{ADMIN_MEDIA_PREFIX}}css/base.css'/>
<link rel="stylesheet" type="text/css" href='{{ADMIN_MEDIA_PREFIX}}css/forms.css'/>
@ -18,7 +20,7 @@
<div id="header">
<div id="branding">
<h1 id="site-name"><a href='http://django-rest-framework.org'>Django REST framework</a> <small>{{ version }}</small></h1>
<h1 id="site-name"><a href='http://django-rest-framework.org'>Django REST framework</a> <span class="version"> v {{ version }}</span></h1>
</div>
<div id="user-tools">
{% if user.is_active %}Welcome, {{ user }}.{% if logout_url %} <a href='{{ logout_url }}'>Log out</a>{% endif %}{% else %}Anonymous {% if login_url %}<a href='{{ login_url }}'>Log in</a>{% endif %}{% endif %}
@ -58,8 +60,8 @@
</form>
{% endif %}
{# Only display the POST/PUT/DELETE forms if method tunneling via POST forms is enabled. #}
{% if METHOD_PARAM %}
{# Only display the POST/PUT/DELETE forms if method tunneling via POST forms is enabled and the user has permissions on this view. #}
{% if METHOD_PARAM and response.status != 403 %}
{% if 'POST' in view.allowed_methods %}
<form action="{{ request.get_full_path }}" method="post" {% if post_form.is_multipart %}enctype="multipart/form-data"{% endif %}>

View File

@ -4,8 +4,8 @@ from django.test import TestCase
from djangorestframework import status
from djangorestframework.compat import View as DjangoView
from djangorestframework.renderers import BaseRenderer, JSONRenderer
from djangorestframework.parsers import JSONParser
from djangorestframework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer
from djangorestframework.parsers import JSONParser, YAMLParser
from djangorestframework.mixins import ResponseMixin
from djangorestframework.response import Response
from djangorestframework.utils.mediatypes import add_media_type_param
@ -189,3 +189,38 @@ class JSONRendererTests(TestCase):
content = renderer.render(obj, 'application/json')
(data, files) = parser.parse(StringIO(content))
self.assertEquals(obj, data)
if YAMLRenderer:
_yaml_repr = 'foo: [bar, baz]\n'
class YAMLRendererTests(TestCase):
"""
Tests specific to the JSON Renderer
"""
def test_render(self):
"""
Test basic YAML rendering.
"""
obj = {'foo':['bar','baz']}
renderer = YAMLRenderer(None)
content = renderer.render(obj, 'application/yaml')
self.assertEquals(content, _yaml_repr)
def test_render_and_parse(self):
"""
Test rendering and then parsing returns the original object.
IE obj -> render -> parse -> obj.
"""
obj = {'foo':['bar','baz']}
renderer = YAMLRenderer(None)
parser = YAMLParser(None)
content = renderer.render(obj, 'application/yaml')
(data, files) = parser.parse(StringIO(content))
self.assertEquals(obj, data)

View File

@ -44,7 +44,8 @@ class View(ResourceMixin, RequestMixin, ResponseMixin, AuthMixin, DjangoView):
renderers.DocumentingHTMLRenderer,
renderers.DocumentingXHTMLRenderer,
renderers.DocumentingPlainTextRenderer,
renderers.XMLRenderer )
renderers.XMLRenderer,
renderers.YAMLRenderer )
"""
List of parsers the resource can parse the request with.

View File

@ -0,0 +1,12 @@
- fields:
first_name: ''
groups: []
is_active: true
is_staff: true
is_superuser: true
last_name: ''
password: sha1$b3dff$671b4ab97f2714446da32670d27576614e176758
user_permissions: []
username: test
model: auth.user
pk: 2

View File

@ -0,0 +1 @@
#for fixture loading

View File

@ -1,6 +1,8 @@
from django.conf.urls.defaults import patterns, url
from permissionsexample.views import ThrottlingExampleView
from permissionsexample.views import PermissionsExampleView, ThrottlingExampleView, LoggedInExampleView
urlpatterns = patterns('',
url(r'^$', ThrottlingExampleView.as_view(), name='throttled-resource'),
url(r'^$', PermissionsExampleView.as_view(), name='permissions-example'),
url(r'^throttling$', ThrottlingExampleView.as_view(), name='throttled-resource'),
url(r'^loggedin$', LoggedInExampleView.as_view(), name='loggedin-resource'),
)

View File

@ -1,6 +1,16 @@
from djangorestframework.views import View
from djangorestframework.permissions import PerUserThrottling
from djangorestframework.permissions import PerUserThrottling, IsAuthenticated
from django.core.urlresolvers import reverse
class PermissionsExampleView(View):
"""
A container view for permissions examples.
"""
def get(self, request):
return [{'name': 'Throttling Example', 'url': reverse('throttled-resource')},
{'name': 'Logged in example', 'url': reverse('loggedin-resource')},]
class ThrottlingExampleView(View):
"""
@ -17,4 +27,12 @@ class ThrottlingExampleView(View):
"""
Handle GET requests.
"""
return "Successful response to GET request because throttle is not yet active."
return "Successful response to GET request because throttle is not yet active."
class LoggedInExampleView(View):
"""
You can login with **'test', 'test'.**
"""
permissions = (IsAuthenticated, )
def get(self, request):
return 'Logged in or not?'

View File

@ -4,3 +4,4 @@
Pygments==1.4
Markdown==2.0.3

View File

@ -22,6 +22,7 @@ class Sandbox(View):
4. A generic object store API.
5. A code highlighting API.
6. A blog posts and comments API.
7. A basic example using permissions.
Please feel free to browse, create, edit and delete the resources in these examples."""
@ -32,5 +33,5 @@ class Sandbox(View):
{'name': 'Object store API', 'url': reverse('object-store-root')},
{'name': 'Code highlighting API', 'url': reverse('pygments-root')},
{'name': 'Blog posts API', 'url': reverse('blog-posts-root')},
{'name': 'Permissions example', 'url': reverse('throttled-resource')}
{'name': 'Permissions example', 'url': reverse('permissions-example')}
]

View File

@ -89,6 +89,12 @@ TEMPLATE_DIRS = (
# Don't forget to use absolute paths, not relative paths.
)
# for loading initial data
##SERIALIZATION_MODULES = {
# 'yml': "django.core.serializers.pyyaml"
#}
INSTALLED_APPS = (
'django.contrib.auth',
@ -104,6 +110,7 @@ INSTALLED_APPS = (
'objectstore',
'pygments_api',
'blogpost',
'permissionsexample',
)
import os

View File

@ -1,6 +1,6 @@
# We need Django. Duh.
# coverage isn't strictly a requirement, but it's useful.
Django==1.2.4
wsgiref==0.1.2
coverage==3.4

32
tox.ini
View File

@ -29,6 +29,7 @@ deps=
django==1.2.4
coverage==3.4
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py26-django12]
basepython=python2.6
@ -36,6 +37,7 @@ deps=
django==1.2.4
coverage==3.4
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py27-django12]
basepython=python2.7
@ -43,28 +45,32 @@ deps=
django==1.2.4
coverage==3.4
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py25-django13]
basepython=python2.5
deps=
django==1.3
coverage==3.4
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py26-django13]
basepython=python2.6
deps=
django==1.3
coverage==3.4
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py27-django13]
basepython=python2.7
deps=
django==1.3
coverage==3.4
unittest-xml-reporting==1.2
Pyyaml==3.10
####################################### EXAMPLES ################################################
[testenv:py25-django12e]
@ -79,7 +85,8 @@ deps=
httplib2==0.6.0
Markdown==2.0.3
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py26-django12e]
basepython=python2.6
commands=
@ -92,7 +99,8 @@ deps=
httplib2==0.6.0
Markdown==2.0.3
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py27-django12e]
basepython=python2.7
commands=
@ -105,7 +113,8 @@ deps=
httplib2==0.6.0
Markdown==2.0.3
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py25-django13e]
basepython=python2.5
commands=
@ -118,7 +127,8 @@ deps=
httplib2==0.6.0
Markdown==2.0.3
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py26-django13e]
basepython=python2.6
commands=
@ -131,7 +141,8 @@ deps=
httplib2==0.6.0
Markdown==2.0.3
unittest-xml-reporting==1.2
Pyyaml==3.10
[testenv:py27-django13e]
basepython=python2.7
commands=
@ -143,4 +154,5 @@ deps=
Pygments==1.4
httplib2==0.6.0
Markdown==2.0.3
unittest-xml-reporting==1.2
unittest-xml-reporting==1.2
Pyyaml==3.10