Skip to content

Commit

Permalink
Ship v0.1.8
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxim Avanov committed Jan 8, 2014
2 parents a5b422e + 7171b84 commit 1682304
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 10 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,6 @@ docs/_build
*node_modules*
# but keep the .coveragerc (for TravisCI/Coveralls services)
!.coveragerc

# test data
*.sqlite3
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Changelog
================
* 0.1.8

* Added support for the ``request.response`` API.

* 0.1.7

* Added support for the ``api_version`` predicate.
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
# The short X.Y version.
version = '0.1'
# The full version, including alpha/beta/rc tags.
release = '0.1.7'
release = '0.1.8'

# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
Expand Down
59 changes: 59 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,65 @@ used, the view must return a HttpResponse object or a Python *dictionary*. The
dictionary items will then be used as the template context objects.


Varying Attributes of Rendered Responses
----------------------------------------

.. note:: This section is partly copied from the
`Pyramid Renderers documentation <http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/renderers.html#varying-attributes-of-rendered-responses>`_,
since Rhetoric provides almost the same API.

.. versionadded:: 0.1.8

Before a response constructed by a :term:`renderer` is returned to
:app:`Django`, several attributes of the request are examined which have the
potential to influence response behavior.

View callables that don't directly return a response should use the API of
the :class:`django.http.HttpResponse` attribute available as
``request.response`` during their execution, to influence associated response
behavior.

For example, if you need to change the response status from within a view
callable that uses a renderer, assign the ``status_code`` attribute to the
``response`` attribute of the request before returning a result:

.. code-block:: python
:linenos:
from rhetoric import view_config
@view_config(name='dashboard', renderer='dashboard.html')
def myview(request):
request.response.status_code = 404
return {'URL': request.get_full_path()}
Note that mutations of ``request.response`` in views which return a HttpResponse
object directly will have no effect unless the response object returned *is*
``request.response``. For example, the following example calls
``request.response.set_cookie``, but this call will have no effect, because a
different Response object is returned.

.. code-block:: python
:linenos:
from django.http import HttpResponse
def view(request):
request.response.set_cookie('abc', '123') # this has no effect
return HttpResponse('OK') # because we're returning a different response
If you mutate ``request.response`` and you'd like the mutations to have an
effect, you must return ``request.response``:

.. code-block:: python
:linenos:
def view(request):
request.response.set_cookie('abc', '123')
return request.response
Predicates
============================

Expand Down
17 changes: 14 additions & 3 deletions rhetoric/config/rendering.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,34 @@ def __init__(self, name):
self.name = name

def __call__(self, request, view_response):
return HttpResponse(json_encode(view_response), content_type='application/json; charset=utf-8')
response = request.response
response.content_type = 'application/json; charset=utf-8'
response.content = json_encode(view_response)
return response


class StringRendererFactory(object):
def __init__(self, name):
self.name = name

def __call__(self, request, view_response):
return HttpResponse(view_response, content_type='text/plain; charset=utf-8')
response = request.response
response.content_type = 'text/plain; charset=utf-8'
response.content = view_response
return response


class DjangoTemplateRendererFactory(object):
def __init__(self, name):
self.name = name

def __call__(self, request, context_dict):
return render(request, self.name, context_dict)
response = request.response
httpresponse_kwargs = {
'content_type': response['Content-Type'],
'status': response.status_code
}
return render(request, self.name, context_dict, **httpresponse_kwargs)


BUILTIN_RENDERERS = {
Expand Down
15 changes: 13 additions & 2 deletions rhetoric/middleware.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
from django.http import HttpResponse
from django.middleware.csrf import CsrfViewMiddleware

from rhetoric.view import ViewCallback


class CsrfProtectedViewDispatchMiddleware(CsrfViewMiddleware):

def process_request(self, request):
# We assume here that CsrfViewMiddleware doesn't have the process_request method
# which should be called via super().
# -------------------------------------------------
# set request.response object as in
# http://docs.pylonsproject.org/projects/pyramid/en/latest/api/request.html#pyramid.request.Request.response
setattr(request, 'response', HttpResponse())


def process_view(self, request, callback, callback_args, callback_kwargs):
if isinstance(callback, ViewCallback):
view_settings = callback.find_view_settings(request, callback_args, callback_kwargs)
Expand All @@ -12,7 +23,7 @@ def process_view(self, request, callback, callback_args, callback_kwargs):
request, view_settings['view'], callback_args, callback_kwargs
)

# The callable is not a part of Rhetoric
# The callable is a regular django view
return super(CsrfProtectedViewDispatchMiddleware, self).process_view(
request, callback, callback_args, callback_kwargs
)
)
3 changes: 2 additions & 1 deletion rhetoric/view.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.core.urlresolvers import RegexURLPattern as DjangoRegexURLPattern
from django.http import HttpResponse, Http404
from django.http import HttpResponse
from django.http import Http404

import venusian

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def run_tests(self):

setup(
name='Rhetoric',
version='0.1.7',
version='0.1.8',
packages=find_packages(exclude=['tests']),
install_requires=[
'Django>=1.4',
Expand Down
2 changes: 2 additions & 0 deletions tests/testapp/testapp/blog/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ def api_v1_submit_form_view(request):

@view_config(route_name='blog.page', request_method='GET', renderer='json')
def blog_page(request, page_slug):
# test custom response status api
request.response.status_code = 201
return {
'page_slug': page_slug
}
Expand Down
1 change: 1 addition & 0 deletions tests/testapp/testapp/index/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def dashboard(request):
# is explicitly set
decorator=require_http_methods(["GET", "POST"]))
def post_on_dashboard(request):
request.response.status_code = 201
return {'method': 'POST'}


Expand Down
8 changes: 6 additions & 2 deletions tests/url_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def test_blog_requests(self):
assert response.status_code == 200

response = self.client.get('/blog/page/page-slug')
assert response.status_code == 200
assert response.status_code == 201
json_data = response.content.decode('utf-8')
assert {'page_slug':'page-slug'} == json.loads(json_data)

Expand All @@ -24,7 +24,7 @@ def test_dashboard_requests(self):

# Test POST to the same URL
response = self.client.post('/dashboard')
assert response.status_code == 200
assert response.status_code == 201
assert response.content.decode('utf-8').strip() == 'Dashboard POST'

# Test PUT to the same URL
Expand All @@ -39,3 +39,7 @@ def test_non_rhetoric_urls(self):
def test_route_path(self):
url = self.rhetoric.url.route_path('index.dashboard')
assert url == '/dashboard'

def test_custom_response_attributes(self):
response = self.client.get('/blog/page/page-slug')
assert response.content_type == 'application/json; charset=utf-8'

0 comments on commit 1682304

Please sign in to comment.