Skip to main content

a minimal DSL for building a WSGI app

Project description

Berry is a minimal DSL for building a WSGI application.

Basically, you map some routes to functions. Berry takes this mapping and
generates a WSGI app, which you can serve however you like.

Example
-------

Here is an example using the wsgiref server, included in Python's stdlib
and ideal for development use.

import berry
from wsgiref.simple_server import make_server

@berry.get('^)defindex(req):return"Welcometothehomepage."@berry.get(hello/(.+)/?')
def hello(req, name):
return "Hello, %s!" % name

# generate a WSGI app
wsgi_app = berry.app

# start a WSGI server
make_server('127.0.0.1', 8000, wsgi_app).serve_forever()

How to use it
-------------

Decorate a function with berry.get(route) or berry.post(route) to serve
GET/POST requests that match a route. Routes must be regular expressions.
Your function will be passed a Request object as the first argument.

Example:

@berry.get('^)@berry.get(home')
def home(req):
return 'This is the home page.'

As above, you can map multiple routes to the same function.

Request objects
---------------

Useful attributes of Request objects are:

- env: the WSGI environ variable.
- params: parameters passed through both GET and POST.
- path: the path requested, minus the initial '/' and the query string
- query: the query string, if any
- fullpath: the full path requested, including the initial '/' and the
query string
- method: the method (GET or POST)

Example:

@berry.post('^login$')
def login(req):
username = req.params.get('username')
password = req.params.get('password')
# ...

Note: if you have a field like 'a[b]' with value 'c', Berry will parse it
into a dictionary. For example:

<input name="person[name]" value="James" />
<input name="person[age]" value="20" />

will result in req.params being:

{'person': {'name': 'James', 'age': '20'}}.

Also,

<input name="person[friends][]" value="James" />
<input name="person[friends][]" value="John" />

will result in req.params being:

{'person': {'friends': ['James', 'John']}}.

Handling errors
---------------

Using the berry.error(code) decorator, you can make custom error pages.

Example:

@berry.error(404)
def notfound(req):
return "%s was not found." % req.fullpath

Berry has Redirect, Forbidden, NotFound, and AppError classes, which
are exceptions that inherit berry.HTTPError. Just raise one of them:

if not user.is_logged_in():
raise berry.Forbidden()

To add an exception for a new HTTP status code you can do something like:

class Unauthorized(berry.HTTPError):
status = (401, 'Unauthorized')
content = "<h1>401 Unauthorized</h1>"

Application errors
------------------

If you set berry.debug = True, tracebacks will be outputted when there
is an exception in your code. Otherwise they will only be written to
stderr.

Redirecting
-----------

To redirect, raise the berry.Redirect exception:

raise berry.Redirect(url)


Headers
-------

To add HTTP headers, use the berry.header decorator:

@berry.header('Content-Type', 'text/plain')
def download_as_txt(req, id):
# ...

By default the Content-Type is set to 'text/html'.


How to install
--------------

If you have setuptools just do:

easy_install berry

Otherwise, you can get the latest release from:

http://pypi.python.org/pypi/berry

Or get the latest development snapshot with git:

git clone git://github.com/adeel/berry.git

Then:

python setup.py install

If you try Berry, please write me at adeel2@umbc.edu and let me know what
you think.

Latest changes
--------------

- Not logging requests anymore (this should be done by a middleware).

- Berry simply generates a WSGI app for you to serve yourself, instead of
serving it for you.

- The convenience function redirect() was removed.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page