Minor bit of tidy up (all the stuff I noticed when demoing to francis)

This commit is contained in:
Tom Christie 2011-01-28 17:42:57 +00:00
parent 2e9fd9c6b9
commit 40f47a9fb3
8 changed files with 47 additions and 62 deletions

View File

@ -1,8 +1,6 @@
:mod:`emitters` :mod:`emitters`
=============== ===============
.. module:: emitters
The emitters module provides a set of emitters that can be plugged in to a :class:`.Resource`. An emitter is responsible for taking the output of a and serializing it to a given media type. A :class:`.Resource` can have a number of emitters, allow the same content to be serialized in a number of different formats depending on the requesting client's preferences, as specified in the HTTP Request's Accept header. The emitters module provides a set of emitters that can be plugged in to a :class:`.Resource`. An emitter is responsible for taking the output of a and serializing it to a given media type. A :class:`.Resource` can have a number of emitters, allow the same content to be serialized in a number of different formats depending on the requesting client's preferences, as specified in the HTTP Request's Accept header.
.. automodule:: emitters .. automodule:: emitters

View File

@ -13,8 +13,30 @@ Some of FlyWheel's features:
* Optional support for forms as input validation. * Optional support for forms as input validation.
* Modular architecture - Easy to extend and modify. * Modular architecture - Easy to extend and modify.
Installation & Setup
--------------------
blah di blah
Getting Started
---------------
Blah di blah
Examples
--------
Blah blah blah, examples here.
Add a toctree for examples
Library Reference
-----------------
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 2
resource resource
modelresource modelresource

View File

@ -15,57 +15,11 @@ class PygmentsForm(forms.Form):
The code to be highlighted can be specified either in a text field, or by URL. 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.""" We do some additional form validation to ensure clients see helpful error responses."""
code_url = forms.URLField(required=False, label='Code URL', code = forms.CharField(widget=forms.Textarea, label='Code Text', max_length=1000000,
help_text='eg. https://bitbucket.org/tomchristie/flywheel/raw/cc266285d879/flywheel/resource.py') help_text='(Copy and paste the code text here.)')
code_text = forms.CharField(widget=forms.Textarea, required=False, label='Code Text', title = forms.CharField(required=False, help_text='(Optional)', max_length=100)
help_text='Either supply a URL for the code to be highlighted or copy and paste the code text here.')
title = forms.CharField(required=False, help_text='(Optional)')
linenos = forms.BooleanField(label='Show Line Numbers', required=False) linenos = forms.BooleanField(label='Show Line Numbers', required=False)
lexer = forms.ChoiceField(choices=LEXER_CHOICES, initial='python') lexer = forms.ChoiceField(choices=LEXER_CHOICES, initial='python')
style = forms.ChoiceField(choices=STYLE_CHOICES, initial='friendly') style = forms.ChoiceField(choices=STYLE_CHOICES, initial='friendly')
def clean_code_url(self):
"""Custom field validation.
Ensure that code URLs really are valid, and return the content they point to in the cleaned_data,
rather than returning the URL itself."""
cleaned_data = self.cleaned_data
url = cleaned_data.get('code_url')
if not url:
return ''
try:
http = httplib.Http('.cache')
resp, content = http.request(url)
except:
raise forms.ValidationError('The URL supplied cannot be reached')
if int(resp.status/100) != 2:
raise forms.ValidationError('The URL supplied does not return successfully')
if not content:
raise forms.ValidationError('The URL supplied returns no content')
return content
def clean(self):
"""Custom form validation.
Ensure that only one of code_url and code_text is set, and return the content of whichever is set in 'code'."""
cleaned_data = self.cleaned_data
code_url = cleaned_data.get('code_url')
code_text = cleaned_data.get('code_text')
if not code_url and not code_text:
raise forms.ValidationError('Either the URL or the code text must be supplied')
if code_url and code_text:
raise forms.ValidationError('You may not specify both the URL and the code text')
if code_url:
cleaned_data['code'] = code_url
del cleaned_data['code_url']
else:
cleaned_data['code'] = code_text
del cleaned_data['code_text']
return cleaned_data

View File

@ -24,7 +24,7 @@ class HTMLEmitter(BaseEmitter):
class PygmentsRoot(Resource): class PygmentsRoot(Resource):
"""This example demonstrates a simple RESTful Web API aound the awesome pygments library. """This example demonstrates a simple RESTful Web API aound the awesome pygments library.
This top level resource is used to create """ This top level resource is used to create highlighted code snippets."""
form = PygmentsForm form = PygmentsForm
allowed_methods = anon_allowed_methods = ('POST',) allowed_methods = anon_allowed_methods = ('POST',)

View File

@ -7,6 +7,7 @@ urlpatterns = patterns('',
(r'^pygments-example/', include('pygments_api.urls')), (r'^pygments-example/', include('pygments_api.urls')),
(r'^blog-post-example/', include('blogpost.urls')), (r'^blog-post-example/', include('blogpost.urls')),
(r'^object-store-example/', include('objectstore.urls')), (r'^object-store-example/', include('objectstore.urls')),
(r'^testarchive-example/', include('testarchive.urls')),
(r'^accounts/login/$', 'django.contrib.auth.views.login'), (r'^accounts/login/$', 'django.contrib.auth.views.login'),
(r'^accounts/logout/$', 'django.contrib.auth.views.logout'), (r'^accounts/logout/$', 'django.contrib.auth.views.logout'),
(r'^admin/doc/', include('django.contrib.admindocs.urls')), (r'^admin/doc/', include('django.contrib.admindocs.urls')),

View File

@ -32,6 +32,8 @@ class BaseEmitter(object):
self.resource = resource self.resource = resource
def emit(self, output=NoContent, verbose=False): def emit(self, output=NoContent, verbose=False):
"""By default emit simply returns the ouput as-is.
Override this method to provide for other behaviour."""
if output is NoContent: if output is NoContent:
return '' return ''
@ -81,7 +83,8 @@ class DocumentingTemplateEmitter(BaseEmitter):
provide a form that can be used to submit arbitrary content.""" provide a form that can be used to submit arbitrary content."""
# Get the form instance if we have one bound to the input # Get the form instance if we have one bound to the input
form_instance = resource.form_instance form_instance = resource.form_instance
print form_instance
# Otherwise if this isn't an error response # Otherwise if this isn't an error response
# then attempt to get a form bound to the response object # then attempt to get a form bound to the response object
if not form_instance and resource.response.has_content_body: if not form_instance and resource.response.has_content_body:
@ -89,6 +92,8 @@ class DocumentingTemplateEmitter(BaseEmitter):
form_instance = resource.get_form(resource.response.raw_content) form_instance = resource.get_form(resource.response.raw_content)
except: except:
pass pass
if form_instance and not form_instance.is_valid():
form_instance = None
# If we still don't have a form instance then try to get an unbound form # If we still don't have a form instance then try to get an unbound form
if not form_instance: if not form_instance:

View File

@ -58,14 +58,19 @@ class Resource(object):
CSRF_PARAM = 'csrfmiddlewaretoken' # Django's CSRF token used in form params CSRF_PARAM = 'csrfmiddlewaretoken' # Django's CSRF token used in form params
def __new__(cls, request, *args, **kwargs): def __new__(cls, *args, **kwargs):
"""Make the class callable so it can be used as a Django view.""" """Make the class callable so it can be used as a Django view."""
self = object.__new__(cls) self = object.__new__(cls)
self.__init__(request) if args:
return self._handle_request(request, *args, **kwargs) request = args[0]
self.__init__(request)
return self._handle_request(request, *args[1:], **kwargs)
else:
self.__init__()
return self
def __init__(self, request): def __init__(self, request=None):
"""""" """"""
# Setup the resource context # Setup the resource context
self.request = request self.request = request

View File

@ -30,9 +30,9 @@
<h1>{{ resource.name }}</h1> <h1>{{ resource.name }}</h1>
<p>{{ resource.description|linebreaksbr }}</p> <p>{{ resource.description|linebreaksbr }}</p>
<pre><b>{{ response.status }} {{ response.status_text }}</b>{% autoescape off %} <pre><b>{{ response.status }} {{ response.status_text }}</b>{% autoescape off %}
{% for key, val in response.headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }} {% for key, val in response.headers.items %}<b>{{ key }}:</b> {{ val|urlize_quoted_links }}
{% endfor %} {% endfor %}
{{ content|urlize_quoted_links }}</pre>{% endautoescape %} {{ content|urlize_quoted_links }}</pre>{% endautoescape %}
{% if 'GET' in resource.allowed_methods %} {% if 'GET' in resource.allowed_methods %}
<div class='action'> <div class='action'>
@ -40,7 +40,7 @@
<ul class="accepttypes"> <ul class="accepttypes">
{% for media_type in resource.emitted_media_types %} {% for media_type in resource.emitted_media_types %}
{% with resource.ACCEPT_QUERY_PARAM|add:"="|add:media_type as param %} {% with resource.ACCEPT_QUERY_PARAM|add:"="|add:media_type as param %}
<li>[<a href='{{ request.path|add_query_param:param }} rel="nofollow"'>{{ media_type }}</a>]</li> <li>[<a href='{{ request.path|add_query_param:param }}' rel="nofollow">{{ media_type }}</a>]</li>
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}
</ul> </ul>