Skip to content

Commit

Permalink
Making the response of a view a Response
Browse files Browse the repository at this point in the history
  • Loading branch information
trollfot committed Mar 17, 2011
1 parent 717e666 commit 9302177
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 63 deletions.
6 changes: 5 additions & 1 deletion buildout.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ parts =
interpreter
test
versions = versions
extensions = buildout.dumppickedversions
extensions = mr.developer buildout.dumppickedversions
auto-checkout = cromlech.io

[sources]
cromlech.io = git gitosis@devel.dolmen-project.org:cromlech.io.git

[versions]
grokcore.view =
Expand Down
2 changes: 2 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ def read(*rnames):
'zope.publisher',
'zope.security',
'zope.traversing',
'cromlech.io',
]

tests_require = [
'WebOb',
'zope.container',
'zope.securitypolicy',
'zope.site',
Expand Down
81 changes: 38 additions & 43 deletions src/grokcore/view/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import sys
import os
import webob
import warnings
import fnmatch

Expand All @@ -25,30 +26,45 @@
from zope.pagetemplate.engine import TrustedAppPT

import martian.util
from cromlech.io import IResponse
from grokcore.view import interfaces, util


class Response(webob.Response):
interface.implements(IResponse)

def setBody(self, value):
if isinstance(value, unicode):
self.unicode_body = value
else:
self.body = value

def getStatus(self, as_int=True):
"""returns the status of the response
"""
if not as_int:
return self.status
return self.status_int

def redirect(self, url, status=302, trusted=False):
"""Sets the response for a redirect.
"""
self.location = url
self.status = status


class ViewSupport(object):
"""Mixin class providing methods and properties generally
useful for view-ish components.
"""

@property
def response(self):
"""The HTTP Response object that is associated with the request.
This is also available as self.request.response, but the
response attribute is provided as a convenience.
"""
return IResponse(self.request)

@property
def body(self):
"""The text of the request body.
"""
return self.request.body

def redirect(self, url, status=None, trusted=False):
def redirect(self, url, status=302, trusted=False):
"""Redirect to `url`.
The headers of the :attr:`response` are modified so that the
Expand Down Expand Up @@ -109,9 +125,12 @@ def url(self, obj=None, name=None, data=None):
class View(Location, ViewSupport):
interface.implements(interfaces.IGrokView)

responseFactory = Response

def __init__(self, context, request):
self.context = context
self.request = request
self.response = self.responseFactory()

self.__name__ = getattr(self, '__view_name__', None)

Expand All @@ -125,15 +144,19 @@ def __init__(self, context, request):

def __call__(self):
self.update()
if self.response.getStatus() in [301, 302]:
return None
template = getattr(self, 'template', None)
if template is not None:
return self._render_template()
return self.render()
self.response.setBody(self._render_template())
else:
self.response.setBody(self.render())
return self.response

def _render_template(self):
return self.template.render(self)

def default_namespace(self):
def namespace(self):
"""Returns a dictionary of namespaces that the template implementation
expects to always be available.
Expand All @@ -147,29 +170,6 @@ def default_namespace(self):
namespace['view'] = self
return namespace

def namespace(self):
"""Returns a dictionary that is injected in the template namespace in
addition to the default namespace.
This method **is** intended to be overridden by the application
developer.
"""
return {}

def __getitem__(self, key):
# This is BBB code for Zope page templates only:
if not isinstance(self.template, PageTemplate):
raise AttributeError("View has no item %s" % key)

value = self.template._template.macros[key]
# When this deprecation is done with, this whole __getitem__ can
# be removed.
warnings.warn("Calling macros directly on the view is deprecated. "
"Please use context/@@viewname/macros/macroname\n"
"View %r, macro %s" % (self, key),
DeprecationWarning, 1)
return value

def update(self, **kwargs):
"""This method is meant to be implemented by subclasses. It
will be called before the view's associated template is
Expand Down Expand Up @@ -262,12 +262,7 @@ def _initFactory(self, factory):
def namespace(self, view):
# By default use the namespaces that are defined as the
# default by the view implementation.
return view.default_namespace()

def getNamespace(self, view):
namespace = self.namespace(view)
namespace.update(view.namespace())
return namespace
return view.namespace()


class TrustedPageTemplate(TrustedAppPT, pagetemplate.PageTemplate):
Expand Down Expand Up @@ -301,8 +296,8 @@ def _get_macros(self):
factory.macros = property(_get_macros)

def render(self, view):
namespace = self.getNamespace(view)
template = self._template
namespace = view.namespace()
namespace.update(template.pt_getContext())
return template.pt_render(namespace)

Expand Down
20 changes: 3 additions & 17 deletions src/grokcore/view/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@

class IBaseClasses(Interface):
View = Attribute("Base class for browser views.")
DirectoryResource = Attribute("Base class to create new "
"directory resource.")


class IDirectives(Interface):
Expand Down Expand Up @@ -87,9 +85,6 @@ class IGrokView(Interface):

request = Attribute('request', "Request that the view was looked up with.")

response = Attribute('response', "Response object that is "
"associated with the current request.")

static = Attribute('static', "Directory resource containing "
"the static files of the view's package.")

Expand All @@ -113,20 +108,9 @@ def url(obj=None, name=None, data=None):
as a cgi query string.
"""

def default_namespace():
"""Returns a dictionary of namespaces that the template
implementation expects to always be available.
This method is *not* intended to be overridden by application
developers.
"""

def namespace():
"""Returns a dictionary that is injected in the template
namespace in addition to the default namespace.
This method *is* intended to be overridden by the application
developer.
namespace.
"""

def update(**kw):
Expand Down Expand Up @@ -171,9 +155,11 @@ def _initFactory(factory):
def render(view):
"""Renders the template"""


class TemplateLookupError(Exception):
pass


class ITemplateRegAPI(Interface):
"""Public API for the templatereg module.
"""
Expand Down
2 changes: 1 addition & 1 deletion src/grokcore/view/tests/template/pluggability.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def namespace(self, view):
return {'middle_text': 'is in'}

def render(self, view):
return self._template.render(**self.getNamespace(view))
return self._template.render(**self.namespace(view))

class MyPageTemplateFactory(grok.GlobalUtility):

Expand Down
2 changes: 1 addition & 1 deletion src/grokcore/view/tests/view/update_redirect.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
None
>>> print view.response.getStatus()
302
>>> print view.response.headers('Location')
>>> print view.response.headers.get('Location')
somewhere-else
"""
Expand Down

0 comments on commit 9302177

Please sign in to comment.