Remove examples (to be moved to a seperate project)

This commit is contained in:
Tom Christie 2012-08-29 19:54:38 +01:00
parent ecd3733c5e
commit eea2aa0437
49 changed files with 0 additions and 1271 deletions

View File

@ -1 +0,0 @@
rest

View File

View File

@ -1,41 +0,0 @@
from django.db import models
from django.template.defaultfilters import slugify
import uuid
def uuid_str():
return str(uuid.uuid1())
RATING_CHOICES = ((0, 'Awful'),
(1, 'Poor'),
(2, 'OK'),
(3, 'Good'),
(4, 'Excellent'))
MAX_POSTS = 10
class BlogPost(models.Model):
key = models.CharField(primary_key=True, max_length=64, default=uuid_str, editable=False)
title = models.CharField(max_length=128)
content = models.TextField()
created = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(editable=False, default='')
def save(self, *args, **kwargs):
"""
For the purposes of the sandbox, limit the maximum number of stored models.
"""
self.slug = slugify(self.title)
super(self.__class__, self).save(*args, **kwargs)
for obj in self.__class__.objects.order_by('-created')[MAX_POSTS:]:
obj.delete()
class Comment(models.Model):
blogpost = models.ForeignKey(BlogPost, editable=False, related_name='comments')
username = models.CharField(max_length=128)
comment = models.TextField()
rating = models.IntegerField(blank=True, null=True, choices=RATING_CHOICES, help_text='How did you rate this post?')
created = models.DateTimeField(auto_now_add=True)

View File

@ -1,36 +0,0 @@
from djangorestframework.resources import ModelResource
from djangorestframework.reverse import reverse
from blogpost.models import BlogPost, Comment
class BlogPostResource(ModelResource):
"""
A Blog Post has a *title* and *content*, and can be associated with zero or more comments.
"""
model = BlogPost
fields = ('created', 'title', 'slug', 'content', 'url', 'comments')
ordering = ('-created',)
def url(self, instance):
return reverse('blog-post',
kwargs={'key': instance.key},
request=self.request)
def comments(self, instance):
return reverse('comments',
kwargs={'blogpost': instance.key},
request=self.request)
class CommentResource(ModelResource):
"""
A Comment is associated with a given Blog Post and has a *username* and *comment*, and optionally a *rating*.
"""
model = Comment
fields = ('username', 'comment', 'created', 'rating', 'url', 'blogpost')
ordering = ('-created',)
def blogpost(self, instance):
return reverse('blog-post',
kwargs={'key': instance.blogpost.key},
request=self.request)

View File

@ -1,210 +0,0 @@
"""Test a range of REST API usage of the example application.
"""
from django.test import TestCase
from django.utils import simplejson as json
from djangorestframework.compat import RequestFactory
from djangorestframework.reverse import reverse
from djangorestframework.views import InstanceModelView, ListOrCreateModelView
from blogpost import models, urls
#import blogpost
# class AcceptHeaderTests(TestCase):
# """Test correct behaviour of the Accept header as specified by RFC 2616:
#
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1"""
#
# def assert_accept_mimetype(self, mimetype, expect=None):
# """Assert that a request with given mimetype in the accept header,
# gives a response with the appropriate content-type."""
# if expect is None:
# expect = mimetype
#
# resp = self.client.get(reverse(views.RootResource), HTTP_ACCEPT=mimetype)
#
# self.assertEquals(resp['content-type'], expect)
#
#
# def dont_test_accept_json(self):
# """Ensure server responds with Content-Type of JSON when requested."""
# self.assert_accept_mimetype('application/json')
#
# def dont_test_accept_xml(self):
# """Ensure server responds with Content-Type of XML when requested."""
# self.assert_accept_mimetype('application/xml')
#
# def dont_test_accept_json_when_prefered_to_xml(self):
# """Ensure server responds with Content-Type of JSON when it is the client's prefered choice."""
# self.assert_accept_mimetype('application/json;q=0.9, application/xml;q=0.1', expect='application/json')
#
# def dont_test_accept_xml_when_prefered_to_json(self):
# """Ensure server responds with Content-Type of XML when it is the client's prefered choice."""
# self.assert_accept_mimetype('application/json;q=0.1, application/xml;q=0.9', expect='application/xml')
#
# def dont_test_default_json_prefered(self):
# """Ensure server responds with JSON in preference to XML."""
# self.assert_accept_mimetype('application/json,application/xml', expect='application/json')
#
# def dont_test_accept_generic_subtype_format(self):
# """Ensure server responds with an appropriate type, when the subtype is left generic."""
# self.assert_accept_mimetype('text/*', expect='text/html')
#
# def dont_test_accept_generic_type_format(self):
# """Ensure server responds with an appropriate type, when the type and subtype are left generic."""
# self.assert_accept_mimetype('*/*', expect='application/json')
#
# def dont_test_invalid_accept_header_returns_406(self):
# """Ensure server returns a 406 (not acceptable) response if we set the Accept header to junk."""
# resp = self.client.get(reverse(views.RootResource), HTTP_ACCEPT='invalid/invalid')
# self.assertNotEquals(resp['content-type'], 'invalid/invalid')
# self.assertEquals(resp.status_code, 406)
#
# def dont_test_prefer_specific_over_generic(self): # This test is broken right now
# """More specific accept types have precedence over less specific types."""
# self.assert_accept_mimetype('application/xml, */*', expect='application/xml')
# self.assert_accept_mimetype('*/*, application/xml', expect='application/xml')
#
#
# class AllowedMethodsTests(TestCase):
# """Basic tests to check that only allowed operations may be performed on a Resource"""
#
# def dont_test_reading_a_read_only_resource_is_allowed(self):
# """GET requests on a read only resource should default to a 200 (OK) response"""
# resp = self.client.get(reverse(views.RootResource))
# self.assertEquals(resp.status_code, 200)
#
# def dont_test_writing_to_read_only_resource_is_not_allowed(self):
# """PUT requests on a read only resource should default to a 405 (method not allowed) response"""
# resp = self.client.put(reverse(views.RootResource), {})
# self.assertEquals(resp.status_code, 405)
#
# def test_reading_write_only_not_allowed(self):
# resp = self.client.get(reverse(views.WriteOnlyResource))
# self.assertEquals(resp.status_code, 405)
#
# def test_writing_write_only_allowed(self):
# resp = self.client.put(reverse(views.WriteOnlyResource), {})
# self.assertEquals(resp.status_code, 200)
#
#
#class EncodeDecodeTests(TestCase):
# def setUp(self):
# super(self.__class__, self).setUp()
# self.input = {'a': 1, 'b': 'example'}
#
# def test_encode_form_decode_json(self):
# content = self.input
# resp = self.client.put(reverse(views.WriteOnlyResource), content)
# output = json.loads(resp.content)
# self.assertEquals(self.input, output)
#
# def test_encode_json_decode_json(self):
# content = json.dumps(self.input)
# resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json')
# output = json.loads(resp.content)
# self.assertEquals(self.input, output)
#
# #def test_encode_xml_decode_json(self):
# # content = dict2xml(self.input)
# # resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json', HTTP_ACCEPT='application/json')
# # output = json.loads(resp.content)
# # self.assertEquals(self.input, output)
#
# #def test_encode_form_decode_xml(self):
# # content = self.input
# # resp = self.client.put(reverse(views.WriteOnlyResource), content, HTTP_ACCEPT='application/xml')
# # output = xml2dict(resp.content)
# # self.assertEquals(self.input, output)
#
# #def test_encode_json_decode_xml(self):
# # content = json.dumps(self.input)
# # resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json', HTTP_ACCEPT='application/xml')
# # output = xml2dict(resp.content)
# # self.assertEquals(self.input, output)
#
# #def test_encode_xml_decode_xml(self):
# # content = dict2xml(self.input)
# # resp = self.client.put(reverse(views.WriteOnlyResource), content, 'application/json', HTTP_ACCEPT='application/xml')
# # output = xml2dict(resp.content)
# # self.assertEquals(self.input, output)
#
#class ModelTests(TestCase):
# def test_create_container(self):
# content = json.dumps({'name': 'example'})
# resp = self.client.post(reverse(views.ContainerFactory), content, 'application/json')
# output = json.loads(resp.content)
# self.assertEquals(resp.status_code, 201)
# self.assertEquals(output['name'], 'example')
# self.assertEquals(set(output.keys()), set(('absolute_uri', 'name', 'key')))
#
#class CreatedModelTests(TestCase):
# def setUp(self):
# content = json.dumps({'name': 'example'})
# resp = self.client.post(reverse(views.ContainerFactory), content, 'application/json', HTTP_ACCEPT='application/json')
# self.container = json.loads(resp.content)
#
# def test_read_container(self):
# resp = self.client.get(self.container["absolute_uri"])
# self.assertEquals(resp.status_code, 200)
# container = json.loads(resp.content)
# self.assertEquals(container, self.container)
#
# def test_delete_container(self):
# resp = self.client.delete(self.container["absolute_uri"])
# self.assertEquals(resp.status_code, 204)
# self.assertEquals(resp.content, '')
#
# def test_update_container(self):
# self.container['name'] = 'new'
# content = json.dumps(self.container)
# resp = self.client.put(self.container["absolute_uri"], content, 'application/json')
# self.assertEquals(resp.status_code, 200)
# container = json.loads(resp.content)
# self.assertEquals(container, self.container)
#above testcases need to probably moved to the core
class TestRotation(TestCase):
"""For the example the maximum amount of Blogposts is capped off at views.MAX_POSTS.
Whenever a new Blogpost is posted the oldest one should be popped."""
def setUp(self):
self.factory = RequestFactory()
models.BlogPost.objects.all().delete()
def test_get_to_root(self):
'''Simple get to the *root* url of blogposts'''
request = self.factory.get('/blog-post')
view = ListOrCreateModelView.as_view(resource=urls.BlogPostResource)
response = view(request)
self.assertEqual(response.status_code, 200)
def test_blogposts_not_exceed_MAX_POSTS(self):
'''Posting blog-posts should not result in more than MAX_POSTS items stored.'''
for post in range(models.MAX_POSTS + 5):
form_data = {'title': 'This is post #%s' % post, 'content': 'This is the content of post #%s' % post}
request = self.factory.post('/blog-post', data=form_data)
view = ListOrCreateModelView.as_view(resource=urls.BlogPostResource)
view(request)
self.assertEquals(len(models.BlogPost.objects.all()),models.MAX_POSTS)
def test_fifo_behaviour(self):
'''It's fine that the Blogposts are capped off at MAX_POSTS. But we want to make sure we see FIFO behaviour.'''
for post in range(15):
form_data = {'title': '%s' % post, 'content': 'This is the content of post #%s' % post}
request = self.factory.post('/blog-post', data=form_data)
view = ListOrCreateModelView.as_view(resource=urls.BlogPostResource)
view(request)
request = self.factory.get('/blog-post')
view = ListOrCreateModelView.as_view(resource=urls.BlogPostResource)
response = view(request)
response_posts = json.loads(response.content)
response_titles = [d['title'] for d in response_posts]
response_titles.reverse()
self.assertEquals(response_titles, ['%s' % i for i in range(models.MAX_POSTS - 5, models.MAX_POSTS + 5)])

View File

@ -1,11 +0,0 @@
from django.conf.urls.defaults import patterns, url
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
from blogpost.resources import BlogPostResource, CommentResource
urlpatterns = patterns('',
url(r'^$', ListOrCreateModelView.as_view(resource=BlogPostResource), name='blog-posts-root'),
url(r'^(?P<key>[^/]+)/$', InstanceModelView.as_view(resource=BlogPostResource), name='blog-post'),
url(r'^(?P<blogpost>[^/]+)/comments/$', ListOrCreateModelView.as_view(resource=CommentResource), name='comments'),
url(r'^(?P<blogpost>[^/]+)/comments/(?P<id>[^/]+)/$', InstanceModelView.as_view(resource=CommentResource)),
)

View File

@ -1,62 +0,0 @@
# This is an example epio.ini file.
# We suggest you edit it to fit your application's needs.
# Documentation for the options is available at www.ep.io/docs/epioini/
[wsgi]
# Location of your requirements file
requirements = requirements-epio.txt
[static]
# Serve the static directory directly as /static
/static/admin = ../shortcuts/django-admin-media/
[services]
# Uncomment to enable the PostgreSQL service.
postgres = true
# Uncomment to enable the Redis service
# redis = true
[checkout]
# By default your code is put in a directory called 'app'.
# You can change that here.
# directory_name = my_project
[env]
# Set any additional environment variables here. For example:
# IN_PRODUCTION = true
[symlinks]
# Any symlinks you'd like to add. As an example, link the symlink 'config.py'
# to the real file 'configs/epio.py':
# config.py = configs/epio.py
media/ = %(data_directory)s/
# #### If you're using Django, you'll want to uncomment some or all of these lines ####
# [django]
# # Path to your project root, relative to this directory.
# base = .
#
# [static]
# Serve the admin media
# # Django 1.3
# /static/admin = ../shortcuts/django-admin-media/
# # Django 1.2 and below
# /media = ../shortcuts/django-admin-media/
#
# [env]
# # Use a different settings module for ep.io (i.e. with DEBUG=False)
# DJANGO_SETTINGS_MODULE = production_settings

View File

@ -1,11 +0,0 @@
#!/usr/bin/env python
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
if __name__ == "__main__":
execute_manager(settings)

View File

@ -1 +0,0 @@
Force media/objectstore directory to created

View File

@ -1 +0,0 @@
Force media/pygments directory to created

View File

@ -1,25 +0,0 @@
from djangorestframework.compat import View # Use Django 1.3's django.views.generic.View, or fall back to a clone of that if Django < 1.3
from djangorestframework.mixins import ResponseMixin
from djangorestframework.renderers import DEFAULT_RENDERERS
from djangorestframework.response import Response
from djangorestframework.reverse import reverse
from django.conf.urls.defaults import patterns, url
class ExampleView(ResponseMixin, View):
"""An example view using Django 1.3's class based views.
Uses djangorestframework's RendererMixin to provide support for multiple
output formats."""
renderers = DEFAULT_RENDERERS
def get(self, request):
url = reverse('mixin-view', request=request)
response = Response(200, {'description': 'Some example content',
'url': url})
return self.render(response)
urlpatterns = patterns('',
url(r'^$', ExampleView.as_view(), name='mixin-view'),
)

View File

@ -1,18 +0,0 @@
from django.db import models
MAX_INSTANCES = 10
class MyModel(models.Model):
foo = models.BooleanField()
bar = models.IntegerField(help_text='Must be an integer.')
baz = models.CharField(max_length=32, help_text='Free text. Max length 32 chars.')
created = models.DateTimeField(auto_now_add=True)
def save(self, *args, **kwargs):
"""
For the purposes of the sandbox limit the maximum number of stored models.
"""
super(MyModel, self).save(*args, **kwargs)
while MyModel.objects.all().count() > MAX_INSTANCES:
MyModel.objects.all().order_by('-created')[0].delete()

View File

@ -1,14 +0,0 @@
from djangorestframework.resources import ModelResource
from djangorestframework.reverse import reverse
from modelresourceexample.models import MyModel
class MyModelResource(ModelResource):
model = MyModel
fields = ('foo', 'bar', 'baz', 'url')
ordering = ('created',)
def url(self, instance):
return reverse('model-resource-instance',
kwargs={'id': instance.id},
request=self.request)

View File

@ -1,11 +0,0 @@
from django.conf.urls.defaults import patterns, url
from djangorestframework.views import ListOrCreateModelView, InstanceModelView
from modelresourceexample.resources import MyModelResource
my_model_list = ListOrCreateModelView.as_view(resource=MyModelResource)
my_model_instance = InstanceModelView.as_view(resource=MyModelResource)
urlpatterns = patterns('',
url(r'^$', my_model_list, name='model-resource-root'),
url(r'^(?P<id>[0-9]+)/$', my_model_instance, name='model-resource-instance'),
)

View File

@ -1,7 +0,0 @@
from django.conf.urls.defaults import patterns, url
from objectstore.views import ObjectStoreRoot, StoredObject
urlpatterns = patterns('objectstore.views',
url(r'^$', ObjectStoreRoot.as_view(), name='object-store-root'),
url(r'^(?P<key>[A-Za-z0-9_-]{1,64})/$', StoredObject.as_view(), name='stored-object'),
)

View File

@ -1,109 +0,0 @@
from django.conf import settings
from djangorestframework.reverse import reverse
from djangorestframework.views import View
from djangorestframework.response import Response
from djangorestframework import status
import pickle
import os
import uuid
import operator
OBJECT_STORE_DIR = os.path.join(settings.MEDIA_ROOT, 'objectstore')
MAX_FILES = 10
if not os.path.exists(OBJECT_STORE_DIR):
os.makedirs(OBJECT_STORE_DIR)
def remove_oldest_files(dir, max_files):
"""
Remove the oldest files in a directory 'dir', leaving at most 'max_files' remaining.
We use this to limit the number of resources in the sandbox.
"""
filepaths = [os.path.join(dir, file) for file in os.listdir(dir) if not file.startswith('.')]
ctime_sorted_paths = [item[0] for item in sorted([(path, os.path.getctime(path)) for path in filepaths],
key=operator.itemgetter(1), reverse=True)]
[os.remove(path) for path in ctime_sorted_paths[max_files:]]
def get_filename(key):
"""
Given a stored object's key returns the file's path.
"""
return os.path.join(OBJECT_STORE_DIR, key)
def get_file_url(key, request):
"""
Given a stored object's key returns the URL for the object.
"""
return reverse('stored-object', kwargs={'key': key}, request=request)
class ObjectStoreRoot(View):
"""
Root of the Object Store API.
Allows the client to get a complete list of all the stored objects, or to create a new stored object.
"""
def get(self, request):
"""
Return a list of all the stored object URLs. (Ordered by creation time, newest first)
"""
filepaths = [os.path.join(OBJECT_STORE_DIR, file)
for file in os.listdir(OBJECT_STORE_DIR)
if not file.startswith('.')]
ctime_sorted_basenames = [item[0] for item in sorted([(os.path.basename(path), os.path.getctime(path)) for path in filepaths],
key=operator.itemgetter(1), reverse=True)]
content = [get_file_url(key, request)
for key in ctime_sorted_basenames]
return Response(content)
def post(self, request):
"""
Create a new stored object, with a unique key.
"""
key = str(uuid.uuid1())
filename = get_filename(key)
pickle.dump(self.CONTENT, open(filename, 'wb'))
remove_oldest_files(OBJECT_STORE_DIR, MAX_FILES)
url = get_file_url(key, request)
return Response(self.CONTENT, status.HTTP_201_CREATED, {'Location': url})
class StoredObject(View):
"""
Represents a stored object.
The object may be any picklable content.
"""
def get(self, request, key):
"""
Return a stored object, by unpickling the contents of a locally
stored file.
"""
filename = get_filename(key)
if not os.path.exists(filename):
return Response(status=status.HTTP_404_NOT_FOUND)
return Response(pickle.load(open(filename, 'rb')))
def put(self, request, key):
"""
Update/create a stored object, by pickling the request content to a
locally stored file.
"""
filename = get_filename(key)
pickle.dump(self.CONTENT, open(filename, 'wb'))
return Response(self.CONTENT)
def delete(self, request, key):
"""
Delete a stored object, by removing it's pickled file.
"""
filename = get_filename(key)
if not os.path.exists(filename):
return Response(status=status.HTTP_404_NOT_FOUND)
os.remove(filename)
return Response()

View File

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

View File

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

View File

@ -1,27 +0,0 @@
from django.test import TestCase
from django.core.urlresolvers import reverse
from django.test.client import Client
class NaviguatePermissionsExamples(TestCase):
"""
Sanity checks for permissions examples
"""
def test_throttled_resource(self):
url = reverse('throttled-resource')
for i in range(0, 10):
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response = self.client.get(url)
self.assertEqual(response.status_code, 503)
def test_loggedin_resource(self):
url = reverse('loggedin-resource')
response = self.client.get(url)
self.assertEqual(response.status_code, 403)
loggedin_client = Client()
loggedin_client.login(username='test', password='test')
response = loggedin_client.get(url)
self.assertEqual(response.status_code, 200)

View File

@ -1,8 +0,0 @@
from django.conf.urls.defaults import patterns, url
from permissionsexample.views import PermissionsExampleView, ThrottlingExampleView, LoggedInExampleView
urlpatterns = patterns('',
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,53 +0,0 @@
from djangorestframework.views import View
from djangorestframework.response import Response
from djangorestframework.permissions import PerUserThrottling, IsAuthenticated
from djangorestframework.reverse import reverse
class PermissionsExampleView(View):
"""
A container view for permissions examples.
"""
def get(self, request):
return Response([
{
'name': 'Throttling Example',
'url': reverse('throttled-resource', request)
},
{
'name': 'Logged in example',
'url': reverse('loggedin-resource', request)
},
])
class ThrottlingExampleView(View):
"""
A basic read-only View that has a **per-user throttle** of 10 requests per minute.
If a user exceeds the 10 requests limit within a period of one minute, the
throttle will be applied until 60 seconds have passed since the first request.
"""
permissions_classes = (PerUserThrottling,)
throttle = '10/min'
def get(self, request):
"""
Handle GET requests.
"""
return Response("Successful response to GET request because throttle is not yet active.")
class LoggedInExampleView(View):
"""
You can login with **'test', 'test'.** or use curl:
`curl -X GET -H 'Accept: application/json' -u test:test http://localhost:8000/permissions-example`
"""
permissions_classes = (IsAuthenticated, )
def get(self, request):
return Response('You have permission to view this resource')

View File

@ -1,27 +0,0 @@
from django import forms
from pygments.lexers import get_all_lexers
from pygments.styles import get_all_styles
LEXER_CHOICES = sorted([(item[1][0], item[0]) for item in get_all_lexers()])
STYLE_CHOICES = sorted((item, item) for item in list(get_all_styles()))
class PygmentsForm(forms.Form):
"""A simple form with some of the most important pygments settings.
The code to be highlighted can be specified either in a text field, or by URL.
We do some additional form validation to ensure clients see helpful error responses."""
code = forms.CharField(widget=forms.Textarea,
label='Code Text',
max_length=1000000,
help_text='(Copy and paste the code text here.)')
title = forms.CharField(required=False,
help_text='(Optional)',
max_length=100)
linenos = forms.BooleanField(label='Show Line Numbers',
required=False)
lexer = forms.ChoiceField(choices=LEXER_CHOICES,
initial='python')
style = forms.ChoiceField(choices=STYLE_CHOICES,
initial='friendly')

View File

@ -1 +0,0 @@
#We need models.py otherwise the test framework complains (http://code.djangoproject.com/ticket/7198)

View File

@ -1,46 +0,0 @@
from django.test import TestCase
from django.utils import simplejson as json
from djangorestframework.compat import RequestFactory
from pygments_api import views
import tempfile, shutil
class TestPygmentsExample(TestCase):
def setUp(self):
self.factory = RequestFactory()
self.temp_dir = tempfile.mkdtemp()
views.HIGHLIGHTED_CODE_DIR = self.temp_dir
def tearDown(self):
try:
shutil.rmtree(self.temp_dir)
except Exception:
pass
def test_get_to_root(self):
'''Just do a get on the base url'''
request = self.factory.get('/pygments')
view = views.PygmentsRoot.as_view()
response = view(request)
self.assertEqual(response.status_code, 200)
def test_snippets_datetime_sorted(self):
'''Pygments examples should be datetime sorted'''
locations = []
for snippet in 'abcdefghij': # String length must not exceed views.MAX_FILES, otherwise test fails
form_data = {'code': '%s' % snippet, 'style':'friendly', 'lexer':'python'}
request = self.factory.post('/pygments', data=form_data)
view = views.PygmentsRoot.as_view()
response = view(request)
locations.append(response.items()[2][1])
import time
time.sleep(.1)
request = self.factory.get('/pygments')
view = views.PygmentsRoot.as_view()
response = view(request)
response_locations = json.loads(response.content)
self.assertEquals(locations, response_locations)

View File

@ -1,7 +0,0 @@
from django.conf.urls.defaults import patterns, url
from pygments_api.views import PygmentsRoot, PygmentsInstance
urlpatterns = patterns('',
url(r'^$', PygmentsRoot.as_view(), name='pygments-root'),
url(r'^([a-zA-Z0-9-]+)/$', PygmentsInstance.as_view(), name='pygments-instance'),
)

View File

@ -1,118 +0,0 @@
from __future__ import with_statement # for python 2.5
from django.conf import settings
from djangorestframework.response import Response
from djangorestframework.renderers import BaseRenderer
from djangorestframework.reverse import reverse
from djangorestframework.views import View
from djangorestframework import status
from pygments.formatters import HtmlFormatter
from pygments.lexers import get_lexer_by_name
from pygments import highlight
from forms import PygmentsForm
import os
import uuid
import operator
# We need somewhere to store the code snippets that we highlight
HIGHLIGHTED_CODE_DIR = os.path.join(settings.MEDIA_ROOT, 'pygments')
MAX_FILES = 10
if not os.path.exists(HIGHLIGHTED_CODE_DIR):
os.makedirs(HIGHLIGHTED_CODE_DIR)
def list_dir_sorted_by_ctime(dir):
"""
Return a list of files sorted by creation time
"""
filepaths = [os.path.join(dir, file)
for file in os.listdir(dir)
if not file.startswith('.')]
ctimes = [(path, os.path.getctime(path)) for path in filepaths]
ctimes = sorted(ctimes, key=operator.itemgetter(1), reverse=False)
return [filepath for filepath, ctime in ctimes]
def remove_oldest_files(dir, max_files):
"""
Remove the oldest files in a directory 'dir', leaving at most 'max_files' remaining.
We use this to limit the number of resources in the sandbox.
"""
[os.remove(path) for path in list_dir_sorted_by_ctime(dir)[max_files:]]
class HTMLRenderer(BaseRenderer):
"""
Basic renderer which just returns the content without any further serialization.
"""
media_type = 'text/html'
class PygmentsRoot(View):
"""
This example demonstrates a simple RESTful Web API around the awesome pygments library.
This top level resource is used to create highlighted code snippets, and to list all the existing code snippets.
"""
form = PygmentsForm
def get(self, request):
"""
Return a list of all currently existing snippets.
"""
unique_ids = [os.path.split(f)[1]
for f in list_dir_sorted_by_ctime(HIGHLIGHTED_CODE_DIR)]
urls = [reverse('pygments-instance', args=[unique_id], request=request)
for unique_id in unique_ids]
return Response(urls)
def post(self, request):
"""
Create a new highlighed snippet and return it's location.
For the purposes of the sandbox example, also ensure we delete the oldest snippets if we have > MAX_FILES.
"""
unique_id = str(uuid.uuid1())
pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id)
lexer = get_lexer_by_name(self.CONTENT['lexer'])
linenos = 'table' if self.CONTENT['linenos'] else False
options = {'title': self.CONTENT['title']} if self.CONTENT['title'] else {}
formatter = HtmlFormatter(style=self.CONTENT['style'], linenos=linenos, full=True, **options)
with open(pathname, 'w') as outfile:
highlight(self.CONTENT['code'], lexer, formatter, outfile)
remove_oldest_files(HIGHLIGHTED_CODE_DIR, MAX_FILES)
location = reverse('pygments-instance', args=[unique_id], request=request)
return Response(status=status.HTTP_201_CREATED, headers={'Location': location})
class PygmentsInstance(View):
"""
Simply return the stored highlighted HTML file with the correct mime type.
This Resource only renders HTML and uses a standard HTML renderer rather than the renderers.DocumentingHTMLRenderer class.
"""
renderers = (HTMLRenderer, )
def get(self, request, unique_id):
"""
Return the highlighted snippet.
"""
pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id)
if not os.path.exists(pathname):
return Response(status=status.HTTP_404_NOT_FOUND)
return Response(open(pathname, 'r').read())
def delete(self, request, unique_id):
"""
Delete the highlighted snippet.
"""
pathname = os.path.join(HIGHLIGHTED_CODE_DIR, unique_id)
if not os.path.exists(pathname):
return Response(status=status.HTTP_404_NOT_FOUND)
os.remove(pathname)
return Response()

View File

@ -1,3 +0,0 @@
from django.db import models
# Create your models here.

View File

@ -1,9 +0,0 @@
from django.conf.urls.defaults import patterns, url
from requestexample.views import RequestExampleView, EchoRequestContentView
from examples.views import ProxyView
urlpatterns = patterns('',
url(r'^$', RequestExampleView.as_view(), name='request-example'),
url(r'^content$', ProxyView.as_view(view_class=EchoRequestContentView), name='request-content'),
)

View File

@ -1,43 +0,0 @@
from djangorestframework.compat import View
from django.http import HttpResponse
from django.core.urlresolvers import reverse
from djangorestframework.mixins import RequestMixin
from djangorestframework.views import View as DRFView
from djangorestframework import parsers
from djangorestframework.response import Response
class RequestExampleView(DRFView):
"""
A container view for request examples.
"""
def get(self, request):
return Response([{'name': 'request.DATA Example', 'url': reverse('request-content')},])
class MyBaseViewUsingEnhancedRequest(RequestMixin, View):
"""
Base view enabling the usage of enhanced requests with user defined views.
"""
parsers = parsers.DEFAULT_PARSERS
def dispatch(self, request, *args, **kwargs):
self.request = request = self.create_request(request)
return super(MyBaseViewUsingEnhancedRequest, self).dispatch(request, *args, **kwargs)
class EchoRequestContentView(MyBaseViewUsingEnhancedRequest):
"""
A view that just reads the items in `request.DATA` and echoes them back.
"""
def post(self, request, *args, **kwargs):
return HttpResponse(("Found %s in request.DATA, content : %s" %
(type(request.DATA), request.DATA)))
def put(self, request, *args, **kwargs):
return HttpResponse(("Found %s in request.DATA, content : %s" %
(type(request.DATA), request.DATA)))

View File

@ -1,3 +0,0 @@
Pygments==1.4
Markdown==2.0.3
git+git://github.com/tomchristie/django-rest-framework.git

View File

@ -1,7 +0,0 @@
# Pygments for the code highlighting example,
# markdown for the docstring -> auto-documentation
Pygments==1.4
Markdown==2.0.3

View File

@ -1,7 +0,0 @@
from django import forms
class MyForm(forms.Form):
foo = forms.BooleanField(required=False)
bar = forms.IntegerField(help_text='Must be an integer.')
baz = forms.CharField(max_length=32, help_text='Free text. Max length 32 chars.')

View File

@ -1,7 +0,0 @@
from django.conf.urls.defaults import patterns, url
from resourceexample.views import ExampleView, AnotherExampleView
urlpatterns = patterns('',
url(r'^$', ExampleView.as_view(), name='example-resource'),
url(r'^(?P<num>[0-9]+)/$', AnotherExampleView.as_view(), name='another-example'),
)

View File

@ -1,49 +0,0 @@
from djangorestframework.reverse import reverse
from djangorestframework.views import View
from djangorestframework.response import Response
from djangorestframework import status
from resourceexample.forms import MyForm
class ExampleView(View):
"""
A basic read-only view that points to 3 other views.
"""
def get(self, request):
"""
Handle GET requests, returning a list of URLs pointing to
three other views.
"""
resource_urls = [reverse('another-example',
kwargs={'num': num},
request=request)
for num in range(3)]
return Response({"Some other resources": resource_urls})
class AnotherExampleView(View):
"""
A basic view, that can handle GET and POST requests.
Applies some simple form validation on POST requests.
"""
form = MyForm
def get(self, request, num):
"""
Handle GET requests.
Returns a simple string indicating which view the GET request was for.
"""
if int(num) > 2:
return Response(status=status.HTTP_404_NOT_FOUND)
return Response("GET request to AnotherExampleResource %s" % num)
def post(self, request, num):
"""
Handle POST requests, with form validation.
Returns a simple string indicating what content was supplied.
"""
if int(num) > 2:
return Response(status=status.HTTP_404_NOT_FOUND)
return Response("POST request to AnotherExampleResource %s, with content: %s" % (num, repr(self.CONTENT)))

View File

@ -1,44 +0,0 @@
import os
import sys
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from django.conf import settings
from django.test.utils import get_runner
from coverage import coverage
def main():
"""Run the tests for the examples and generate a coverage report."""
# Discover the list of all modules that we should test coverage for
project_dir = os.path.dirname(__file__)
cov_files = []
for (path, dirs, files) in os.walk(project_dir):
# Drop tests and runtests directories from the test coverage report
if os.path.basename(path) == 'tests' or os.path.basename(path) == 'runtests':
continue
cov_files.extend([os.path.join(path, file) for file in files if file.endswith('.py')])
TestRunner = get_runner(settings)
cov = coverage()
cov.erase()
cov.start()
if hasattr(TestRunner, 'func_name'):
# Pre 1.2 test runners were just functions,
# and did not support the 'failfast' option.
import warnings
warnings.warn(
'Function-based test runners are deprecated. Test runners should be classes with a run_tests() method.',
DeprecationWarning
)
failures = TestRunner(None)
else:
test_runner = TestRunner()
failures = test_runner.run_tests(['blogpost', 'pygments_api'])
cov.stop()
cov.report(cov_files)
cov.xml_report(cov_files)
sys.exit(failures)
if __name__ == '__main__':
main()

View File

@ -1,65 +0,0 @@
"""The root view for the examples provided with Django REST framework"""
from djangorestframework.reverse import reverse
from djangorestframework.views import View
from djangorestframework.response import Response
class Sandbox(View):
"""
This is the sandbox for the examples provided with
[Django REST framework][1].
These examples are provided to help you get a better idea of some of the
features of RESTful APIs created using the framework.
All the example APIs allow anonymous access, and can be navigated either
through the browser or from the command line.
For example, to get the default representation using curl:
bash: curl -X GET http://rest.ep.io/
Or, to get the plaintext documentation represention:
bash: curl -X GET http://rest.ep.io/ -H 'Accept: text/plain'
The examples provided:
1. A basic example using the [Resource][2] class.
2. A basic example using the [ModelResource][3] class.
3. An basic example using Django 1.3's [class based views][4] and
djangorestframework's [RendererMixin][5].
4. A generic object store API.
5. A code highlighting API.
6. A blog posts and comments API.
7. A basic example using permissions.
8. A basic example using enhanced request.
Please feel free to browse, create, edit and delete the resources in
these examples.
[1]: http://django-rest-framework.org
[2]: http://django-rest-framework.org/library/resource.html
[3]: http://django-rest-framework.org/library/modelresource.html
[4]: http://docs.djangoproject.com/en/dev/topics/class-based-views/
[5]: http://django-rest-framework.org/library/renderers.html
"""
def get(self, request):
return Response([
{'name': 'Simple Resource example',
'url': reverse('example-resource', request=request)},
{'name': 'Simple ModelResource example',
'url': reverse('model-resource-root', request=request)},
{'name': 'Simple Mixin-only example',
'url': reverse('mixin-view', request=request)},
{'name': 'Object store API',
'url': reverse('object-store-root', request=request)},
{'name': 'Code highlighting API',
'url': reverse('pygments-root', request=request)},
{'name': 'Blog posts API',
'url': reverse('blog-posts-root', request=request)},
{'name': 'Permissions example',
'url': reverse('permissions-example', request=request)},
])

View File

@ -1,117 +0,0 @@
# Settings for djangorestframework examples project
import django
import os
DEBUG = True
TEMPLATE_DEBUG = DEBUG
ADMINS = (
# ('Your Name', 'your_email@domain.com'),
)
MANAGERS = ADMINS
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'sqlite3.db', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '', # Set to empty string for default. Not used with sqlite3.
}
}
# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be available on all operating systems.
# On Unix systems, a value of None will cause Django to use the same
# timezone as the operating system.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'Europe/London'
# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-uk'
SITE_ID = 1
# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True
# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True
# Absolute filesystem path to the directory that will hold user-uploaded files.
# Example: "/home/media/media.lawrence.com/"
# NOTE: Some of the djangorestframework examples use MEDIA_ROOT to store content.
MEDIA_ROOT = os.path.join(os.getenv('EPIO_DATA_DIRECTORY', '.'), 'media')
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
# NOTE: None of the djangorestframework examples serve media content via MEDIA_URL.
MEDIA_URL = '/uploads/'
STATIC_URL = '/static/'
# Make this unique, and don't share it with anybody.
SECRET_KEY = 't&9mru2_k$t8e2-9uq-wu2a1)9v*us&j3i#lsqkt(lbx*vh1cu'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
# 'django.template.loaders.eggs.Loader',
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
ROOT_URLCONF = 'urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
if django.VERSION < (1, 3):
staticfiles = 'staticfiles'
else:
staticfiles = 'django.contrib.staticfiles'
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
staticfiles,
'django.contrib.messages',
'djangorestframework',
'resourceexample',
'modelresourceexample',
'objectstore',
'pygments_api',
'blogpost',
'permissionsexample',
'requestexample',
)
import os
if os.environ.get('HUDSON_URL', None):
TEST_RUNNER = 'xmlrunner.extra.djangotestrunner.XMLTestRunner'
TEST_OUTPUT_VERBOSE = True
TEST_OUTPUT_DESCRIPTIONS = True
TEST_OUTPUT_DIR = 'xmlrunner'

View File

@ -1,21 +0,0 @@
from django.conf.urls.defaults import patterns, include, url
from sandbox.views import Sandbox
try:
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
except ImportError: # Django <= 1.2
from staticfiles.urls import staticfiles_urlpatterns
urlpatterns = patterns('',
(r'^$', Sandbox.as_view()),
(r'^resource-example/', include('resourceexample.urls')),
(r'^model-resource-example/', include('modelresourceexample.urls')),
(r'^mixin/', include('mixin.urls')),
(r'^object-store/', include('objectstore.urls')),
(r'^pygments/', include('pygments_api.urls')),
(r'^blog-post/', include('blogpost.urls')),
(r'^permissions-example/', include('permissionsexample.urls')),
url(r'^restframework/', include('djangorestframework.urls', namespace='djangorestframework')),
)
urlpatterns += staticfiles_urlpatterns()

View File

@ -1,32 +0,0 @@
from djangorestframework.views import View
from djangorestframework.response import Response
class ProxyView(View):
"""
A view that just acts as a proxy to call non-djangorestframework views, while still
displaying the browsable API interface.
"""
view_class = None
def dispatch(self, request, *args, **kwargs):
self.request = request = self.create_request(request)
if request.method in ['PUT', 'POST']:
self.response = self.view_class.as_view()(request, *args, **kwargs)
return super(ProxyView, self).dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return Response()
def put(self, request, *args, **kwargs):
return Response(self.response.content)
def post(self, request, *args, **kwargs):
return Response(self.response.content)
def get_name(self):
return self.view_class.__name__
def get_description(self, html):
return self.view_class.__doc__