Modules

weblayer.auth

weblayer.auth provides TrivialAuthenticationManager, an implementation of IAuthenticationManager.

The implementation is deliberately trivial as it’s envisaged that a bespoke application that requires authentication will:

  • use WSGI middleware (for example AuthKit or repoze.who) to handle authentication; and / or
  • override the IAuthenticationManager implementation to work with the individual application’s persistence and caching layers.
class weblayer.auth.TrivialAuthenticationManager(request)[source]

A very simple IAuthenticationManager implementation that uses the webob.Request request.remote_user attribute which, under the WebOb hood, is derived from request.environ['REMOTE_USER'], which is the standard place for authentication middleware to put a user id.

TrivialAuthenticationManager is thus perfectly usable in many cases with is_authenticated returning True or False appropriately and current_user returning a user id if present.

current_user[source]

Returns request.remote_user:

>>> from mock import Mock
>>> request = Mock()
>>> request.remote_user = 'joe'
>>> am = TrivialAuthenticationManager(request)
>>> am.current_user

‘joe’

is_authenticated[source]

Is there a remote_user in the request?

>>> from mock import Mock
>>> request = Mock()

If remote_user is None, returns False:

>>> request.remote_user = None
>>> am = TrivialAuthenticationManager(request)
>>> am.is_authenticated
False

Otherwise returns True:

>>> request.remote_user = 'foo'
>>> am = TrivialAuthenticationManager(request)
>>> am.is_authenticated
True

weblayer.base

weblayer.base provides default IRequest and IResponse implementations, based purely on webob.Request and webob.Response.

The two implementations, Request and Response, add no functionality to their WebOb superclasses beyond declaring that they implement the IRequest and IResponse interfaces.

class weblayer.base.Request(environ=None, environ_getter=None, charset=(No Default), unicode_errors=(No Default), decode_param_names=(No Default), **kw)[source]

IRequest implementation using webob.Request.

GET

Like .str_GET, but may decode values and keys

POST

Like .str_POST, but may decode values and keys

ResponseClass

alias of Response

accept

Gets and sets the ‘HTTP_ACCEPT’ key in the environment. For more information on Accept see section 14.1. Converts it as a MIME Accept.

accept_charset

Gets and sets the ‘HTTP_ACCEPT_CHARSET’ key in the environment. For more information on Accept-Charset see section 14.2. Converts it as a accept header.

accept_encoding

Gets and sets the ‘HTTP_ACCEPT_ENCODING’ key in the environment. For more information on Accept-Encoding see section 14.3. Converts it as a accept header.

accept_language

Gets and sets the ‘HTTP_ACCEPT_LANGUAGE’ key in the environment. For more information on Accept-Language see section 14.4. Converts it as a accept header.

application_url

The URL including SCRIPT_NAME (no PATH_INFO or query string)

authorization

Gets and sets the ‘HTTP_AUTHORIZATION’ key in the environment. For more information on Authorization see section 14.8. Converts it as a <function parse_auth at 0x27e95f0> and <function serialize_auth at 0x27e9630>.

classmethod blank(path, environ=None, base_url=None, headers=None, POST=None, **kw)

Create a blank request environ (and Request wrapper) with the given path (path should be urlencoded), and any keys from environ.

The path will become path_info, with any query string split off and used.

All necessary keys will be added to the environ, but the values you pass in will take precedence. If you pass in base_url then wsgi.url_scheme, HTTP_HOST, and SCRIPT_NAME will be filled in from that value.

Any extra keyword will be passed to __init__ (e.g., decode_param_names).

body

Return the content of the request body.

body_file

Access the body of the request (wsgi.input) as a file-like object.

If you set this value, CONTENT_LENGTH will also be updated (either set to -1, 0 if you delete the attribute, or if you set the attribute to a string then the length of the string).

cache_control

Get/set/modify the Cache-Control header (section 14.9)

call_application(application, catch_exc_info=False)

Call the given WSGI application, returning (status_string, headerlist, app_iter)

Be sure to call app_iter.close() if it’s there.

If catch_exc_info is true, then returns (status_string, headerlist, app_iter, exc_info), where the fourth item may be None, but won’t be if there was an exception. If you don’t do this and there was an exception, the exception will be raised directly.

charset

Get the charset of the request.

If the request was sent with a charset parameter on the Content-Type, that will be used. Otherwise if there is a default charset (set during construction, or as a class attribute) that will be returned. Otherwise None.

Setting this property after request instantiation will always update Content-Type. Deleting the property updates the Content-Type to remove any charset parameter (if none exists, then deleting the property will do nothing, and there will be no error).

content_length

Gets and sets the ‘CONTENT_LENGTH’ key in the environment. For more information on CONTENT_LENGTH see section 14.13. Converts it as a int.

content_type

Return the content type, but leaving off any parameters (like charset, but also things like the type in application/atom+xml; type=entry)

If you set this property, you can include parameters, or if you don’t include any parameters in the value then existing parameters will be preserved.

cookies

Like .str_cookies, but may decode values and keys

copy()

Copy the request and environment object.

This only does a shallow copy, except of wsgi.input

copy_body()

Copies the body, in cases where it might be shared with another request object and that is not desired.

This copies the body in-place, either into a StringIO object or a temporary file.

copy_get()

Copies the request and environment object, but turning this request into a GET along the way. If this was a POST request (or any other verb) then it becomes GET, and the request body is thrown away.

date

Gets and sets the ‘HTTP_DATE’ key in the environment. For more information on Date see section 14.8. Converts it as a HTTP date.

classmethod from_file(fp)

Reads a request from a file-like object (it must implement .read(size) and .readline()).

It will read up to the end of the request, not the end of the file.

This reads the request as represented by str(req); it may not read every valid HTTP request properly.

get_response(application, catch_exc_info=False)

Like .call_application(application), except returns a response object with .status, .headers, and .body attributes.

This will use self.ResponseClass to figure out the class of the response object to return.

headers

All the request headers as a case-insensitive dictionary-like object.

host

Host name provided in HTTP_HOST, with fall-back to SERVER_NAME

host_url

The URL through the host (no path)

if_match

Gets and sets the ‘HTTP_IF_MATCH’ key in the environment. For more information on If-Match see section 14.24. Converts it as a Etag.

if_modified_since

Gets and sets the ‘HTTP_IF_MODIFIED_SINCE’ key in the environment. For more information on If-Modified-Since see section 14.25. Converts it as a HTTP date.

if_none_match

Gets and sets the ‘HTTP_IF_NONE_MATCH’ key in the environment. For more information on If-None-Match see section 14.26. Converts it as a Etag.

if_range

Gets and sets the ‘HTTP_IF_RANGE’ key in the environment. For more information on If-Range see section 14.27. Converts it as a IfRange object.

if_unmodified_since

Gets and sets the ‘HTTP_IF_UNMODIFIED_SINCE’ key in the environment. For more information on If-Unmodified-Since see section 14.28. Converts it as a HTTP date.

is_xhr

Returns a boolean if X-Requested-With is present and XMLHttpRequest

Note: this isn’t set by every XMLHttpRequest request, it is only set if you are using a Javascript library that sets it (or you set the header yourself manually). Currently Prototype and jQuery are known to set this header.

make_body_seekable()

This forces environ['wsgi.input'] to be seekable. That is, if it doesn’t have a seek method already, the content is copied into a StringIO or temporary file.

The choice to copy to StringIO is made from self.request_body_tempfile_limit

max_forwards

Gets and sets the ‘HTTP_MAX_FORWARDS’ key in the environment. For more information on Max-Forwards see section 14.31. Converts it as a int.

method

Gets and sets the ‘REQUEST_METHOD’ key in the environment.

params

Like .str_params, but may decode values and keys

path

The path of the request, without host or query string

path_info

Gets and sets the ‘PATH_INFO’ key in the environment.

path_info_peek()

Returns the next segment on PATH_INFO, or None if there is no next segment. Doesn’t modify the environment.

path_info_pop(pattern=None)

‘Pops’ off the next segment of PATH_INFO, pushing it onto SCRIPT_NAME, and returning the popped segment. Returns None if there is nothing left on PATH_INFO.

Does not return '' when there’s an empty segment (like /path//path); these segments are just ignored.

Optional pattern argument is a regexp to match the return value before returning. If there is no match, no changes are made to the request and None is returned.

path_qs

The path of the request, without host but with query string

path_url

The URL including SCRIPT_NAME and PATH_INFO, but not QUERY_STRING

postvars

Wraps a descriptor, with a deprecation warning or error

pragma

Gets and sets the ‘HTTP_PRAGMA’ key in the environment. For more information on Pragma see section 14.32.

query_string

Gets and sets the ‘QUERY_STRING’ key in the environment.

queryvars

Wraps a descriptor, with a deprecation warning or error

range

Gets and sets the ‘HTTP_RANGE’ key in the environment. For more information on Range see section 14.35. Converts it as a Range object.

referer

Gets and sets the ‘HTTP_REFERER’ key in the environment. For more information on Referer see section 14.36.

referrer

Gets and sets the ‘HTTP_REFERER’ key in the environment. For more information on Referer see section 14.36.

relative_url(other_url, to_application=False)

Resolve other_url relative to the request URL.

If to_application is True, then resolve it relative to the URL with only SCRIPT_NAME

remote_addr

Gets and sets the ‘REMOTE_ADDR’ key in the environment.

remote_user

Gets and sets the ‘REMOTE_USER’ key in the environment.

remove_conditional_headers(remove_encoding=True, remove_range=True, remove_match=True, remove_modified=True)

Remove headers that make the request conditional.

These headers can cause the response to be 304 Not Modified, which in some cases you may not want to be possible.

This does not remove headers like If-Match, which are used for conflict detection.

scheme

Gets and sets the ‘wsgi.url_scheme’ key in the environment.

script_name

Gets and sets the ‘SCRIPT_NAME’ key in the environment.

server_name

Gets and sets the ‘SERVER_NAME’ key in the environment.

server_port

Gets and sets the ‘SERVER_PORT’ key in the environment. Converts it as a int.

str_GET

Return a MultiDict containing all the variables from the QUERY_STRING.

str_POST

Return a MultiDict containing all the variables from a form request. Returns an empty dict-like object for non-form requests.

Form requests are typically POST requests, however PUT requests with an appropriate Content-Type are also supported.

str_cookies

Return a plain dictionary of cookies as found in the request.

str_params

A dictionary-like object containing both the parameters from the query string and request body.

str_postvars

Wraps a descriptor, with a deprecation warning or error

str_queryvars

Wraps a descriptor, with a deprecation warning or error

upath_info

upath_property(‘PATH_INFO’)

url

The full request URL, including QUERY_STRING

urlargs

Return any positional variables matched in the URL.

Takes values from environ['wsgiorg.routing_args']. Systems like routes set this value.

urlvars

Return any named variables matched in the URL.

Takes values from environ['wsgiorg.routing_args']. Systems like routes set this value.

uscript_name

upath_property(‘SCRIPT_NAME’)

user_agent

Gets and sets the ‘HTTP_USER_AGENT’ key in the environment. For more information on User-Agent see section 14.43.

class weblayer.base.Response(body=None, status=None, headerlist=None, app_iter=None, request=None, content_type=None, conditional_response=None, **kw)[source]

IResponse implementation using webob.Response.

RequestClass

alias of Request

accept_ranges

Gets and sets and deletes the Accept-Ranges header. For more information on Accept-Ranges see section 14.5.

age

Gets and sets and deletes the Age header. For more information on Age see section 14.6. Converts it as a int.

allow

Gets and sets and deletes the Allow header. For more information on Allow see section 14.7. Converts it as a list.

app_iter

Returns the app_iter of the response.

If body was set, this will create an app_iter from that body (a single-item list)

app_iter_range(start, stop)

Return a new app_iter built from the response app_iter, that serves up only the given start:stop range.

body

The body of the response, as a str. This will read in the entire app_iter if necessary.

body_file

A file-like object that can be used to write to the body. If you passed in a list app_iter, that app_iter will be modified by writes.

cache_control

Get/set/modify the Cache-Control header (section 14.9)

charset

Get/set the charset (in the Content-Type)

conditional_response_app(environ, start_response)

Like the normal __call__ interface, but checks conditional headers:

  • If-Modified-Since (304 Not Modified; only on GET, HEAD)
  • If-None-Match (304 Not Modified; only on GET, HEAD)
  • Range (406 Partial Content; only on GET, HEAD)
content_disposition

Gets and sets and deletes the Content-Disposition header. For more information on Content-Disposition see section 19.5.1.

content_encoding

Gets and sets and deletes the Content-Encoding header. For more information on Content-Encoding see section 14.11.

content_language

Gets and sets and deletes the Content-Language header. For more information on Content-Language see section 14.12. Converts it as a list.

content_length

Gets and sets and deletes the Content-Length header. For more information on Content-Length see section 14.17. Converts it as a int.

content_location

Gets and sets and deletes the Content-Location header. For more information on Content-Location see section 14.14.

content_md5

Gets and sets and deletes the Content-MD5 header. For more information on Content-MD5 see section 14.14.

content_range

Gets and sets and deletes the Content-Range header. For more information on Content-Range see section 14.16. Converts it as a ContentRange object.

content_type

Get/set the Content-Type header (or None), without the charset or any parameters.

If you include parameters (or ; at all) when setting the content_type, any existing parameters will be deleted; otherwise they will be preserved.

content_type_params

A dictionary of all the parameters in the content type.

(This is not a view, set to change, modifications of the dict would not be applied otherwise)

copy()

Makes a copy of the response

date

Gets and sets and deletes the Date header. For more information on Date see section 14.18. Converts it as a HTTP date.

Delete a cookie from the client. Note that path and domain must match how the cookie was originally set.

This sets the cookie to the empty string, and max_age=0 so that it should expire immediately.

encode_content(encoding='gzip', lazy=False)

Encode the content with the given encoding (only gzip and identity are supported).

environ

Get/set the request environ associated with this response, if any.

etag

Gets and sets and deletes the ETag header. For more information on ETag see section 14.19. Converts it as a Entity tag.

expires

Gets and sets and deletes the Expires header. For more information on Expires see section 14.21. Converts it as a HTTP date.

classmethod from_file(fp)

Reads a response from a file-like object (it must implement .read(size) and .readline()).

It will read up to the end of the response, not the end of the file.

This reads the response as represented by str(resp); it may not read every valid HTTP response properly. Responses must have a Content-Length

headerlist

The list of response headers

headers

The headers in a dictionary-like object

last_modified

Gets and sets and deletes the Last-Modified header. For more information on Last-Modified see section 14.29. Converts it as a HTTP date.

location

Gets and sets and deletes the Location header. For more information on Location see section 14.30.

md5_etag(body=None, set_content_md5=False)

Generate an etag for the response object using an MD5 hash of the body (the body parameter, or self.body if not given)

Sets self.etag If set_content_md5 is True sets self.content_md5 as well

merge_cookies(resp)

Merge the cookies that were set on this response with the given resp object (which can be any WSGI application).

If the resp is a webob.Response object, then the other object will be modified in-place.

pragma

Gets and sets and deletes the Pragma header. For more information on Pragma see section 14.32.

request

Return the request associated with this response if any.

retry_after

Gets and sets and deletes the Retry-After header. For more information on Retry-After see section 14.37. Converts it as a HTTP date or delta seconds.

server

Gets and sets and deletes the Server header. For more information on Server see section 14.38.

Set (add) a cookie for the response

status

The status string

status_code

Wraps a descriptor, with a deprecation warning or error

status_int

The status as an integer

ubody

Alias for unicode_body

unicode_body

Get/set the unicode value of the body (using the charset of the Content-Type)

Unset a cookie with the given name (remove it from the response).

vary

Gets and sets and deletes the Vary header. For more information on Vary see section 14.44. Converts it as a list.

www_authenticate

Gets and sets and deletes the WWW-Authenticate header. For more information on WWW-Authenticate see section 14.47. Converts it as a <function parse_auth at 0x27e95f0> and <function serialize_auth at 0x27e9630>.

weblayer.bootstrap

weblayer.bootstrap provides Bootstrapper, a helper class that simplifies setting up and registering weblayer components. To bootstrap a default configuration, pass a dictionary of settings and list of url mappings to the Bootstrapper constructor:

>>> bootstrapper = Bootstrapper(settings={}, url_mapping=[])

Then call the bootstrapper instance to register components and get ISettings and IPathRouter utilities. By default, the bootstrapper uses RequirableSettings as its ISettings implementation and performs a venusian scan of the weblayer package to require settings declared explicitly with require_setting(). This means that you must pass the required settings into the Bootstrapper constructor when instantiating the bootstrapper or get a KeyError:

>>> settings, path_router = bootstrapper() 
Traceback (most recent call last):
...
KeyError: u'Required setting `template_directories` () is missing, 
          Required setting `static_files_path` () is missing, 
          Required setting `cookie_secret` (a long, random sequence 
          of bytes) is missing'

Whereas if the required settings are provided, all is well:

>>> config = {
...     'cookie_secret': '...', 
...     'static_files_path': '/var/www/static',
...     'template_directories': ['templates']
... }
>>> bootstrapper = Bootstrapper(settings=config, url_mapping=[])
>>> settings, path_router = bootstrapper()

If you require your own settings (see the settings module for more information), pass in the dotted names of the modules or packages they are required in:

>>> bootstrapper = Bootstrapper(settings=config, url_mapping=[])
>>> settings, path_router = bootstrapper(packages=['foo', 'baz.bar'])
Traceback (most recent call last):
...
ImportError: No module named foo

To override specific components, either pass in False to skip registering them, e.g.:

>>> bootstrapper = Bootstrapper(settings=config, url_mapping=[])
>>> settings, path_router = bootstrapper(TemplateRenderer=False)

Or pass in your own implementation, e.g.:

>>> from mock import Mock
>>> mock_router = Mock()
>>> bootstrapper = Bootstrapper(settings=config, url_mapping=[])
>>> settings, path_router = bootstrapper(path_router=mock_router)
>>> path_router == mock_router
True
class weblayer.bootstrap.Bootstrapper(settings=None, url_mapping=None)[source]

Simplifies setting up and registering weblayer components.

require_settings(packages=None, scan_framework=True, extra_categories=None)[source]

Init and return a RequirableSettings instance, scanning packages for required settings.

register_components(settings=None, path_router=None, TemplateRenderer=None, AuthenticationManager=None, SecureCookieWrapper=None, StaticURLGenerator=None, MethodSelector=None, ResponseNormaliser=None)[source]

Setup component registrations. Pass in alternative implementations here to override, or pass in False to avoid registering a component.

__call__(packages=None, scan_framework=True, extra_categories=None, require_settings=True, **kwargs)[source]

If require_settings is True and settings isn’t provided as a keyword argument, call require_settings(), register_components() and return settings, path_router.

weblayer.component

weblayer.component provides registry, an instance of a zope.component.registry.Components component management registry.

registry provides methods to register and lookup utilities and adapters against interfaces. For example:

>>> from mock import Mock
>>> from weblayer.interfaces import *
>>> mock_path_router = Mock()
>>> MockTemplateRenderer = Mock()
>>> MockTemplateRenderer.return_value = 'mock_template_renderer'

To register a utility:

>>> registry.registerUtility(mock_path_router, IPathRouter)

To register an adapter:

>>> registry.registerAdapter(
...     MockTemplateRenderer, 
...     required=[ISettings],
...     provided=ITemplateRenderer
... )

To get a registered utility:

>>> path_router = registry.getUtility(IPathRouter)
>>> path_router == mock_path_router
True

To get a registered adapter:

>>> from weblayer.settings import RequirableSettings
>>> settings = RequirableSettings()
>>> template_renderer = registry.getAdapter(
...     settings, 
...     ITemplateRenderer
... )

Note how you register an adapter class and get an instance:

>>> MockTemplateRenderer.assert_called_with(settings)
>>> template_renderer = 'mock_template_renderer'

Tear down:

>>> registry.unregisterUtility(provided=IPathRouter)
True
>>> registry.unregisterAdapter(
...     required=[ISettings], 
...     provided=ITemplateRenderer
... )
True

weblayer.cookie

weblayer.cookie provides SignedSecureCookieWrapper, an implementation of ISecureCookieWrapper.

SignedSecureCookieWrapper provides two key methods, set() and get() to set and get cookies whose value is signed using the required settings['cookie_secret'].

The resulting cookies are secure, in the sense that they can’t be forged (without the forger knowing the settings['cookie_secret']). However, it’s important to note that they are just as vulnerable to sidejacking as normal cookies. The only way to secure cookies against sidejacking is to serve your application over HTTPS and that is a matter for web server configuration, outside the scope of weblayer.

class weblayer.cookie.SignedSecureCookieWrapper(request, response, settings)[source]

Adapts an IRequest, IResponse and ISettings to provide methods to get and set cookies that can’t be forged.

delete(name, path='/', domain=None)[source]

Convenience method to clear a cookie.

get(name, value=None)[source]

Returns the given signed cookie if it validates, or None.

set(name, value, timestamp=None, expires_days=30, **kwargs)[source]

Signs and timestamps a cookie so it cannot be forged.

weblayer.interfaces

weblayer.interfaces provides Interface definitions that show the contracts that weblayer‘s Components implement and are registered against and looked up by through the weblayer.component registry.

interface weblayer.interfaces.IAuthenticationManager[source]

Authentication manager. Default implementation is TrivialAuthenticationManager.

is_authenticated

Boolean – is there an authenticated user?

current_user

The authenticated user, or None

interface weblayer.interfaces.IMethodSelector[source]

Selects request handler methods by name. Default implementation is ExposedMethodSelector.

select_method(method_name)[source]

Return a method using method_name.

interface weblayer.interfaces.IPathRouter[source]

Maps incoming requests to request handlers using the request path. Default implementation is RegExpPathRouter.

match(path)[source]

Return handler, args, kwargs from path.

interface weblayer.interfaces.IRequest[source]

A Request object, based on webob.Request. Default implementation is Request.

This interface details only the attributes of webob.Request that weblayer uses by default, not the full interface webob.Request actually provides.

body

Content of the request body.

application_url

URL w. SCRIPT_NAME no PATH_INFO or QUERY_STRING

url

Full request URL, including QUERY_STRING

cookies

Dictionary of cookies found in the request

path_qs

Path without HOST but with QUERY_STRING

headers

Headers as case-insensitive dictionary-like object

host

HOST provided in HTTP_HOST w. fall-back to SERVER_NAME

params

Dictionary-like obj of params from POST and QUERY_STRING

host_url

The URL through the HOST (no path)

path

Path of the request, without HOST or QUERY_STRING

path_url

URL w. SCRIPT_NAME & PATH_INFO no QUERY_STRING

interface weblayer.interfaces.IRequestHandler[source]

A request handler. Default implementation is RequestHandler.

redirect(url, status=302, content_type=None)[source]

Redirect to url.

render(tmpl_name, **kwargs)[source]

Render the template called tmpl_name.

settings

Settings instance

request

Request instance

cookies

Cookie wrapper

auth

Authentication manager

response

Response instance

static

Static url generator

xsrf_validate()[source]

Validate against XSRF.

error(status=500, body=u'System Error')[source]

Clear response and return an error.

__call__(method_name, *args, **kwargs)[source]

Call the appropriate method to return a response.

xsrf_input

<input/> element to be included in forms.

xsrf_token

XSRF prevention token

interface weblayer.interfaces.IResponse[source]

A Response object, based on webob.Response. Default implementation is Response.

This interface details only the attributes of webob.Response that weblayer uses by default, not the full interface webob.Response actually provides.

body

The body of the response, as a str.

status

The status string

headerlist

The list of response headers

Set value for cookie called key.

unicode_body

The body of the response, as a unicode.

headers

The headers in a dictionary-like object

content_type

The Content-Type header

interface weblayer.interfaces.IResponseNormaliser[source]

Normalise the response provided by a request handler method. Default implementation is DefaultToJSONResponseNormaliser.

normalise(handler_response)[source]

Normalise handler_response.

interface weblayer.interfaces.ISecureCookieWrapper[source]

Get and set cookies that can’t be forged. Default implementation is SignedSecureCookieWrapper.

delete(self, name, path='/', domain=None)[source]

Clear cookie.

set(name, value, expires_days=30, **kwargs)[source]

Set cookie.

get(name, include_name=True, value=None)[source]

Get cookie.

interface weblayer.interfaces.ISettings[source]

Provides dictionary-like access to global application settings. Default implementation is RequirableSettings.

iteritems()[source]

Iter items.

pop(key, *args)[source]

Pop.

has_key(key)[source]

Has key.

__contains__(key)[source]

Return whether contains item.

__cmp__(self, other)[source]

Compare against other.

itervalues()[source]

Iter values.

__call__(items)[source]

Update with items.

__len__(self)[source]

Return number of items.

__getitem__(key)[source]

Get item.

get(key, default=None)[source]

Get item if exists, or return default.

keys()[source]

Keys.

update(other=None, **kwargs)[source]

Update.

__iter__()[source]

Iterate through items.

popitem()[source]

Pop item.

iterkeys()[source]

Iter keys.

__delitem__(key)[source]

Delete item.

setdefault(key, default=None)[source]

Set default.

items()[source]

Items.

clear()[source]

Clear items.

__setitem__(key, value)[source]

Set item.

values()[source]

Values.

__repr__()[source]

Represent as a string.

interface weblayer.interfaces.IStaticURLGenerator[source]

Static url generator. Default implementation is MemoryCachedStaticURLGenerator.

get_url(path)[source]

Get a fully expanded url for the given static resource path.

interface weblayer.interfaces.ITemplateRenderer[source]

A template renderer. Default implementation is MakoTemplateRenderer.

render(tmpl_name, **kwargs)[source]

Render the template called tmpl_name.

interface weblayer.interfaces.IWSGIApplication[source]

A callable WSGI application. Default implementation is WSGIApplication.

__call__(environ, start_response)[source]

Handle a new request.

weblayer.method

weblayer.method provides ExposedMethodSelector, an implementation of IMethodSelector.

ExposedMethodSelector works in tandem with RequestHandler.__all__ to select only explicitly exposed request handler methods to handle incoming requests:

>>> class MockHandler(object):
...     implements(IRequestHandler)
...     
...     __all__ = ('get')
...     
...     def get(self):
...         pass
...         
...     
...     def post(self):
...         pass
...         
...     
... 
>>> handler = MockHandler()
>>> selector = ExposedMethodSelector(handler)
>>> callable(selector.select_method('GET'))
True
>>> callable(selector.select_method('POST'))
False
class weblayer.method.ExposedMethodSelector(context)[source]

Method selector adapter that works in tandem with the RequestHandler.__all__ attribute.

select_method(method_name)[source]

Returns getattr(self, method_name) iff the method exists and is exposed. Otherwise returns None.

Special cases HEAD requests to use GET, iff 'head' is exposed, def get() exists and def head() doesn’t. This allows applications to respond to HEAD requests without writing seperate head methods and takes advantage of the special case in webob.Response.__call__:

def __call__(self, environ, start_response):
    
    # ... code removed for brevity
    
    if environ['REQUEST_METHOD'] == 'HEAD':
        # Special case here...
        return EmptyResponse(self.app_iter)
    return self.app_iter

weblayer.normalise

weblayer.normalise provides DefaultToJSONResponseNormaliser, an implementation of IResponseNormaliser.

DefaultToJSONResponseNormaliser adapts a response object:

>>> from mock import Mock
>>> response = Mock()
>>> normaliser = DefaultToJSONResponseNormaliser(response)
>>> normaliser.response == response
True

Provides a normalise() method that takes a single argument and uses it to update and or replace the original response object before returning it:

>>> class MockResponse(Mock):
...     implements(IResponse)
... 
>>> mock_response = MockResponse()
>>> r = normaliser.normalise(mock_response)
>>> r == mock_response
True
>>> r = normaliser.normalise('a')
>>> r.body == 'a'
True
>>> r = normaliser.normalise(u'a')
>>> r.unicode_body == u'a'
True
>>> r = normaliser.normalise(None)
>>> r == normaliser.response
True

If the argument provided isn’t callable(), a basestring or None, the default implementation tries to JSON encode it:

>>> r = normaliser.normalise({'a': u'b'})
>>> r.content_type
'application/json; charset=UTF-8'
>>> r.unicode_body
u'{"a": "b"}'
class weblayer.normalise.DefaultToJSONResponseNormaliser(response, json_encode=None, json_content_type='application/json; charset=UTF-8')[source]

Adapter to normalise a response.

normalise(handler_response)[source]

Update and return self.response appropriately.

>>> from mock import Mock
>>> response = Mock()
>>> normaliser = DefaultToJSONResponseNormaliser(
...     response,
...     json_encode=None
... )

If handler_response is callable() then just use that. The intention being that the callable() is a WSGI application:

>>> def app(environ, start_response):
...     headers = [('Content-type', 'text/plain')]
...     start_response('200 OK', headers)
...     return ['']
... 
>>> r = normaliser.normalise(app)
>>> r == app
True

But, any old callable() will sneak through:

>>> def foo():
...     pass
... 
>>> r = normaliser.normalise(foo)
>>> r == foo
True

Otherwise if it’s a str or a unicode use that as the response body:

>>> r = normaliser.normalise('a')
>>> r.body == 'a'
True
>>> r = normaliser.normalise(u'a')
>>> r.unicode_body == u'a'
True

If it’s None then just return the origin response:

>>> normaliser = DefaultToJSONResponseNormaliser(
...     42,
...     json_encode=None
... )
>>> normaliser.normalise(None)
42

Otherwise (with this particular implementation) assume we want to encode handler_response as a JSON string as use that as the response body:

>>> response = Mock()
>>> json_encode = Mock()
>>> normaliser = DefaultToJSONResponseNormaliser(
...     response,
...     json_encode=json_encode
... )
>>> json_encode.return_value = '{"a": "b"}'
>>> r = normaliser.normalise({'a': 'b'})
>>> r.content_type == normaliser._json_content_type
True
>>> json_encode.call_args[0][0] == {'a': 'b'}
True
>>> r.body
'{"a": "b"}'
>>> json_encode.return_value = u'{"a": "b"}'
>>> r = normaliser.normalise({'a': u'b'})
>>> r.unicode_body
u'{"a": "b"}'

weblayer.request

weblayer.request provides RequestHandler, an implementation of IRequestHandler.

RequestHandler is designed to be used as a base class in which you can write code that handles incoming requests to a web application, as per:

class Hello(RequestHandler):
    def get(self, world):
        return u'hello %s' % world

The main point being to take advantage of the Request Handler API that the class provides.

class weblayer.request.RequestHandler(request, response, settings, template_renderer_adapter=None, static_url_generator_adapter=None, authentication_manager_adapter=None, secure_cookie_wrapper_adapter=None, method_selector_adapter=None, response_normaliser_adapter=None)[source]

A request handler (aka view class) implementation.

Accepts GET and HEAD requests by default, when used in tandem with an ExposedMethodSelector (or any method selector implementation that checks to see if the request method name is listed in RequestHandler.__all__).

error(exception=None, status=500, **kwargs)

Return a response corresponding to either exception or (if exception is None) status.

kwargs are passed to the appropriate webob_exception_ class constructor.

Note

Override this method to generate error messages that are more user friendly.

handle_method_not_found(method_name)

Log a warning and return “405 Method Not Allowed”.

handle_system_error(err)

Log the error and return “500 Internal Server Error”.

handle_xsrf_error(err)

Log a warning and return “403 Forbidden”.

redirect(location, permanent=False, **kwargs)

Redirect to location. The response status defaults to 302 unless permanent is True.

kwargs (with kwargs['location'] set to location are passed to the appropriate webob_exception class constructor.

render(tmpl_name, **kwargs)

Render the template called tmpl_name, passing through the params and kwargs.

xsrf_input

An HTML <input /> element to be included with all POST forms.

xsrf_token

A token we can check to prevent XSRF attacks.

xsrf_validate()

Raise an XSRFError if the _xsrf argument isn’t present or if it doesn’t match self.xsrf_token.

weblayer.route

weblayer.route provides RegExpPathRouter, an implementation of IPathRouter that uses regular expression patterns. Say, for example, you have some request handlers:

>>> class DummyIndex(object):
...     implements(IRequestHandler)
... 
>>> class Dummy404(object):
...     implements(IRequestHandler)
... 

You can then map request paths to them using a list of two item tuples:

>>> mapping = [(
...         # string or compiled regexp pattern to match
...         # against the request path
...         r'/',
...         # class the request should be handled by
...         DummyIndex
...     ), (
...         r'/(.*)',
...         Dummy404
...     )
... ]
>>> path_router = RegExpPathRouter(mapping)

And use the path router to get handlers for request paths:

>>> path_router.match('/') == (DummyIndex, (), {})
True

Returning the handler and the match groups if any:

>>> path_router.match('/foobar') == (Dummy404, ('foobar',), {})
True

The mapping items are looked up in order:

>>> mapping.reverse()
>>> path_router = RegExpPathRouter(mapping)
>>> path_router.match('/') == (Dummy404, ('',), {})
True

If the path doesn’t match, returns (None, None, None):

>>> path_router = RegExpPathRouter([])
>>> path_router.match('/')
(None, None, None)
class weblayer.route.RegExpPathRouter(raw_mapping, compile_=None)[source]

Routes paths to request handlers using regexp patterns.

match(path)[source]

If the path matches, return the handler class, the regular expression match object’s groups (as args to pass to the handler) and an empty dict (as kwargs to pass to the handler), as per:

>>> path_router = RegExpPathRouter([])
>>> handler_class, args, kwargs = path_router.match('/foo')

Otherwise return (None, None, None).

weblayer.settings

weblayer.settings provides RequirableSettings, an implementation of ISettings that allows you to (optionally) declare the settings that your application requires.

For example, say your application code needs to know the value of a particular webservice api key. You can require it by calling the require_setting() method (by convention at the top of a module, so the requirement is clear):

>>> require_setting('api_key')

Or by decorating a function or method with require():

>>> class Foo(object):
...     @require('api_key')
...     def foo(self):
...         pass
...     
... 
>>> @require('api_key')
... def foo(self): pass
... 

Then, once we’ve executed a venusian scan (which we fake here: see ./tests/test_settings.py for real integration tests):

>>> settings = RequirableSettings()
>>> def mock_require_setting(*args, **kwargs):
...     settings._require(*args, **kwargs) # never call this directly!
... 
>>> def mock_override_setting(*args, **kwargs):
...     settings._override(*args, **kwargs) # never call this directly!
... 
>>> mock_require_setting('api_key')

You can call the RequirableSettings instance with a dictionary of settings provided by the user / your application. If you pass in a value for api_key, great, otherwise, you’ll get a KeyError:

>>> settings({'api_key': '123'})
>>> settings['api_key']
'123'
>>> settings({})
Traceback (most recent call last):
...
KeyError: u'Required setting `api_key` () is missing'

You can specify default values and help strings ala:

>>> mock_require_setting('baz', default='blah', help=u'what is this?')
>>> settings({'api_key': '123'})
>>> settings['baz']
'blah'

You can’t require the same setting twice with different values:

>>> mock_require_setting('baz', default='something else')
Traceback (most recent call last):
...
KeyError: u'baz is already defined'

Unless you explicitly use override_setting() (also available as the override() decorator):

>>> mock_override_setting('baz', default='something else')
>>> settings({'api_key': '123'})
>>> settings['baz']
'something else'
class weblayer.settings.RequirableSettings(packages=None, extra_categories=None)[source]

Utility that provides dictionary-like access to application settings.

Do not use the _require and _override methods directly. Instead, use the require_setting() and override_setting() functions or the require() and override() decorators.

Note that the

keys()[source]

Return keys:

>>> settings = RequirableSettings()
>>> settings({'a': None, 'b': None})
>>> settings.keys()

[‘a’, ‘b’]

weblayer.settings.require_setting(name, default=None, help=u'', category='weblayer')[source]

Require a setting.

weblayer.settings.require(name, default=None, help=u'', category='weblayer')[source]

Decorator to require a setting.

weblayer.settings.override_setting(name, default=None, help=u'', category='weblayer')[source]

Override a setting.

weblayer.settings.override(name, default=None, help=u'', category='weblayer')[source]

Decorator to override a setting.

weblayer.static

weblayer.static provides MemoryCachedStaticURLGenerator, an implementation of IStaticURLGenerator.

The purpose of an IStaticURLGenerator is to generate static urls for use in templates. It does not serve static files.

MemoryCachedStaticURLGenerator adapts an IRequest and requires two settings, settings['static_files_path'] and settings['static_url_prefix'] (which defaults to u'/static/').

>>> from mock import Mock
>>> from os.path import normpath, join as join_path
>>> static_files_path = normpath('/var/www/static')
>>> request = Mock()
>>> request.host_url = 'http://foo.com'
>>> settings = {}
>>> settings['static_files_path'] = static_files_path
>>> settings['static_url_prefix'] = u'/static/'
>>> MemoryCachedStaticURLGenerator._cache = {}
>>> static = MemoryCachedStaticURLGenerator(request, settings)
>>> static._cache_path = Mock()

When get_url() is called, it looks for a file at the path passed in, relative to settings['static_files_path']. If the file exists, it hashes it and appends the first few characters of the hash digest to the returned url.

For example, imagine we’ve hashed and cached /var/www/static/foo.js:

>>> static._cache[join_path(static_files_path, 'foo.js')] = 'abcdefghij'

The static URL returned is:

>>> static.get_url('foo.js')
u'http://foo.com/static/foo.js?v=abcdefg'

Use settings['static_host_url'] to specify the url static files should be requested on (if this is different from the request url):

>>> settings['static_host_url'] = 'http://static.foo.com'
>>> static = MemoryCachedStaticURLGenerator(request, settings)
>>> static.get_url('foo.js')
u'http://static.foo.com/static/foo.js?v=abcdefg'

As the MemoryCachedStaticURLGenerator name suggests, the hash digests are cached in memory using a static class attribute. This means that:

The last two points mean that applications serving static files may incur CPU and memory overhead that could be avoided using a dedicated cache (like memcached or redis). Production systems thus may want to provide their own IStaticURLGenerator implementation, (potentially by subclassing MemoryCachedStaticURLGenerator and overriding the _cache_path() method).

Note

Alternative implementations must consider invalidating the hash digests when files change. One benefit of the default MemoryCachedStaticURLGenerator implementation is that, as hash digests are invalidated when the application restarts, deployment setups that watch for changes to the underlying source code and restart when files change cause the cache to be invalidated.

For example, one way to integrate with paste.reloader so it reloaded your application every time a cached file changed would be to use:

paster serve --reload

With:

def watch_cached_static_files():
    return MemoryCachedStaticURLGenerator._cache.keys()

paste.reloader.add_file_callback(watch_cached_static_files)
class weblayer.static.MemoryCachedStaticURLGenerator(request, settings, join_path_=None, open_file_=None, generate_hash_=None)[source]

Adapter to generate static URLs from a request.

get_url(path, snip_digest_at=7)[source]

Get a fully expanded url for the given static resource path:

>>> from mock import Mock
>>> request = Mock()
>>> request.host_url = 'http://static.foo.com'
>>> settings = {}
>>> settings['static_files_path'] = '/var/www/static'
>>> settings['static_url_prefix'] = u'/static/'
>>> join_path = Mock()
>>> join_path.return_value = '/var/www/static/foo.js'
>>> MemoryCachedStaticURLGenerator._cache = {}
>>> static = MemoryCachedStaticURLGenerator(
...     request, 
...     settings,
...     join_path_=join_path
... )
>>> static._cache_path = Mock()

path is expanded into file_path:

>>> url = static.get_url('foo.js')
>>> join_path.assert_called_with('/var/www/static', 'foo.js')

If path isn’t in self._cache, calls self._cache_path():

>>> static._cache_path.assert_called_with('/var/www/static/foo.js')

If the digest is None, just joins the host url, prefix and path:

>>> static._cache['/var/www/static/foo.js'] = None
>>> static.get_url('foo.js')
u'http://static.foo.com/static/foo.js'

Else also appends '?v=' plus upto the first snip_digest_at chars of the digest, which defaults to 7:

>>> static._cache['/var/www/static/foo.js'] = 'abcdefghijkl'
>>> static.get_url('foo.js')
u'http://static.foo.com/static/foo.js?v=abcdefg'
>>> static.get_url('foo.js', snip_digest_at=4)
u'http://static.foo.com/static/foo.js?v=abcd'

Cleanup:

>>> MemoryCachedStaticURLGenerator._cache = {}

weblayer.template

weblayer.template provides MakoTemplateRenderer, an implementation of ITemplateRenderer that uses Mako templates.

>>> import tempfile, os
>>> from os.path import basename, dirname
>>> fd, abs_path = tempfile.mkstemp()
>>> sock = os.fdopen(fd, 'w')
>>> tmpl_dir = dirname(abs_path)
>>> tmpl_name = basename(abs_path)

MakoTemplateRenderer requires settings['template_directories']:

>>> settings = {'template_directories': [tmpl_dir]}
>>> template_renderer = MakoTemplateRenderer(settings)

And provides a render() method that accepts a tmpl_name which is resolved relative to settings['template_directories'] and passes through a set of built in functions and the keyword arguments provided to render() to the template’s global namespace:

>>> tmpl = u'<h1>${escape(foo)}</h1>'
>>> sock.write(tmpl)
>>> sock.close()
>>> template_renderer.render(tmpl_name, foo='&')
'<h1>&amp;</h1>'

The built ins available by default are:

DEFAULT_BUILT_INS = {
    "escape": utils.xhtml_escape,
    "url_escape": utils.url_escape,
    "json_encode": utils.json_encode,
    "datetime": datetime
}

Cleanup:

>>> os.unlink(abs_path)
class weblayer.template.MakoTemplateRenderer(settings, built_ins=None, template_lookup_class=None, module_directory='/tmp/mako_modules', input_encoding='utf-8', output_encoding='utf-8', encoding_errors='replace', **kwargs)[source]

Mako template renderer.

render(tmpl_name, **kwargs)[source]

Render tmpl_name, unpacking self.built_ins and kwargs into the template’s global namespace.

weblayer.utils

weblayer.utils provides a set of utility functions for converting and encoding.

weblayer.utils.encode_to_utf8(value)[source]

Converts a unicode to a utf-8 encoded str:

>>> a = u'foo'
>>> a
u'foo'
>>> encode_to_utf8(a)
'foo'
>>> b = u'\u817e\u8baf\u9996\u9875'
>>> c = '腾讯首页'
>>> assert encode_to_utf8(b) == c

Regular strings get left alone:

>>> d = 'foo'
>>> encode_to_utf8(d)
'foo'

Other types raise a ValueError:

>>> e = None
>>> encode_to_utf8(e) 
Traceback (most recent call last):
...
ValueError: None must be a `basestring`
weblayer.utils.decode_to_unicode(value)[source]

Converts a (hopefully) utf-8 encoded str to a unicode:

>>> a = 'foo'
>>> decode_to_unicode(a)
u'foo'
>>> b = '腾讯首页'
>>> decode_to_unicode(b)
u'\u817e\u8baf\u9996\u9875'

Unicode values get left alone:

>>> c = u'foo'
>>> decode_to_unicode(c)
u'foo'

Other types raise a ValueError:

>>> d = None
>>> decode_to_unicode(d) 
Traceback (most recent call last):
...
ValueError: None must be a `basestring`
weblayer.utils.xhtml_escape(value)[source]

Escapes a string so it is valid within XML or XHTML:

>>> xhtml_escape('a')
'a'
>>> xhtml_escape('<')
'&lt;'
>>> xhtml_escape('&')
'&amp;'

Including double quotes:

>>> xhtml_escape('"')
'&quot;'

Encoding the result to utf-8:

>>> xhtml_escape(u'a')
'a'
weblayer.utils.url_escape(value)[source]

Returns a URL-encoded version of value.

Runs the value through quote_plus():

>>> url_escape('a')
'a'
>>> url_escape(' ')
'+'

Encoding it first to utf-8:

>>> url_escape(u'a')
'a'
>>> url_escape(u'http://foo.com?bar=baz')
'http%3A%2F%2Ffoo.com%3Fbar%3Dbaz'

Which means the value must be a basestring:

>>> url_escape(None) 
Traceback (most recent call last):
...
ValueError: None must be a `basestring`
weblayer.utils.unicode_urlencode(items)[source]

Ensures all items are encoded to utf-8 and passed to urlencode().

Pass it a dict, comes out like a query string:

>>> r1 = unicode_urlencode({'a': 'b'})
>>> r1
'a=b'

Ditto a list of two item tuples:

>>> r2 = unicode_urlencode([('a', 'b')])
>>> r2 == r1
True

Converting any unicode values to utf8:

>>> unicode_urlencode({'a': u'b'})
'a=b'
>>> r3 = unicode_urlencode({'a': u'\u817e\u8baf\u9996\u9875'})
>>> r3
'a=%E8%85%BE%E8%AE%AF%E9%A6%96%E9%A1%B5'

Before running them through urlencode():

>>> from urllib import urlencode
>>> r4 = urlencode({'a': encode_to_utf8(u'\u817e\u8baf\u9996\u9875')})
>>> r4 == r3
True

All values must be instances of basestring:

>>> unicode_urlencode({'a': object()}) 
Traceback (most recent call last):
...
ValueError: <object object ... must be a `basestring`

Lists must contain at least two values to unpack:

>>> unicode_urlencode(['a', 'b']) 
Traceback (most recent call last):
...
ValueError: need more than 1 value to unpack

And not more than two values to unpack:

>>> unicode_urlencode([('a', 'b', 'c')]) 
Traceback (most recent call last):
...
ValueError: too many values to unpack
weblayer.utils.json_encode(value, ensure_ascii=False, **kwargs)[source]

JSON encodes the given value:

>>> json_encode({'a': 'b'}) == json.dumps({'a': 'b'})
True
>>> json_encode({'a': 'b'})
'{"a": "b"}'
>>> json_encode({'a': None})
'{"a": null}'
>>> json_encode([])
'[]'

With ensure_ascii False by default:

>>> json_encode({'a': u'\u817e\u8baf\u9996\u9875'})
u'{"a": "\u817e\u8baf\u9996\u9875"}'
>>> result = json_encode({'a': u'\u817e\u8baf'}, ensure_ascii=True)
>>> result == '{"a": "\u817e\u8baf"}'
True

Raises a TypeError if the value isn’t serializable:

>>> json_encode([object()]) 
Traceback (most recent call last):
...
TypeError: <object object ... is not JSON serializable
weblayer.utils.json_decode(value, **kwargs)[source]

If value is valid JSON, parses it into a Python object:

>>> json_decode('{}') == json.loads('{}')
True
>>> json_decode('{}')
{}
>>> json_decode('[null]')
[None]

Passing the value through decode_to_unicode() to start with:

>>> json_decode('{"a": "b"}')
{u'a': u'b'}
>>> json_decode('{"a": "\u817e\u8baf\u9996\u9875"}')
{u'a': u'\u817e\u8baf\u9996\u9875'}

Raises a ValueError if the decoded value can’t be parsed:

>>> json_decode('{"a": object()}') 
Traceback (most recent call last):
...
ValueError: No JSON object could be decoded
weblayer.utils.generate_hash(s=None, algorithm='sha512', block_size=512)[source]

Generates a hexdigest() string, either randomly or from a string or file like object (like an open file or a buffer).

By default, the hash is randomly generated and uses the sha512 algorithm:

>>> s1 = generate_hash()
>>> isinstance(s1, str)
True
>>> len(s1) == 128
True
>>> s2 = generate_hash()
>>> s1 == s2
False
>>> s3 = generate_hash(algorithm='sha512')
>>> len(s1) == len(s3)
True

The hash can be generated from a seed:

>>> generate_hash(s='a')
'1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75'

Using None as the seed (which is the default) will, as we’ve seen, generate a random value:

>>> s6 = generate_hash(s=None)
>>> s7 = generate_hash(s=None)
>>> s6 == s7
False

Using a file like object (anything with a read() method) will use the contents of the file like object:

>>> from StringIO import StringIO
>>> sock = StringIO()
>>> sock.write('abc')
>>> sock.seek(0)
>>> s8 = generate_hash(s=sock)
>>> s9 = generate_hash(s='abc')
>>> s8 == s9
True

Reading the contents into memory in blocks of block_size, which defaults to 512:

>>> from mock import Mock
>>> sock = Mock()
>>> sock.read.return_value = None
>>> s10 = generate_hash(s=sock)
>>> sock.read.assert_called_with(512)
>>> s10 = generate_hash(s=sock, block_size=1024)
>>> sock.read.assert_called_with(1024)

Using other types as a seed (anything that hashlib doesn’t like) will raise a TypeError:

>>> generate_hash(s=[]) 
Traceback (most recent call last):
...
TypeError: ...

The algorithm name can also be passed in:

>>> s4 = generate_hash(algorithm='md5')
>>> s5 = generate_hash(algorithm='sha224')
>>> len(s4) == 32 and len(s5) == 56
True

As long as it’s available in hashlib:

>>> generate_hash(algorithm='foo')
Traceback (most recent call last):
...
AttributeError: 'module' object has no attribute 'foo'

weblayer.wsgi

weblayer.wsgi provides WSGIApplication, an implementation of IWSGIApplication that adapts ISettings and an IPathRouter:

>>> settings = {}
>>> path_router = object()

To provide a callable WSGI application:

>>> application = WSGIApplication(settings, path_router)
class weblayer.wsgi.WSGIApplication(settings, path_router, request_class=None, response_class=None, default_content_type='text/html; charset=UTF-8')[source]
__call__(environ, start_response)[source]

Checks self._path_router for a match() against the incoming path:

handler_class, args, kwargs = self._path_router.match(request.path)

If handler_class is not None, instantiates the IRequestHandler:

handler = handler_class(request, response, self._settings)

And calls it with environ['REQUEST_METHOD'] and the args and kwargs from match():

response = handler(environ['REQUEST_METHOD'], *args, **kwargs)

Note

If calling the handler errors (which is shouldn’t normally do, as the handler should catch the error), returns a minimalist 500 response.

Note

If no match is found, returns a minimalist 404 response. To handle 404 responses more elegantly, define a catch all URL handler.