Skip to content

adeel/berry

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

91 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

                                     berry
                  a minimal DSL for building WSGI applications


INTRODUCTION.  Berry is meant to be analogous to Ruby's Rack::Builder [1] for
WSGI.  It simply takes a mapping of routes to functions and constructs a WSGI
app.  It is not a framework or even a microframework.  You can add in your
favorite ORM, template engine, and so on (Elixir [2] and Jinja2 [3] are good
ones).  There is a fairly rich collection of middlewares for WSGI [4] which you
should take advantage of (Beaker [5], Static [6] and Memento [7] are especially
useful).  Serve your app with any of the many WSGI servers [8].

Berry is about 250 lines of code.  It has been used in production in several
applications since 2009.

  [1]  Rack::Builder <http://rack.rubyforge.org/doc/classes/Rack/Builder.html>
  [2]  Elixir <http://elixir.ematia.de>
  [3]  Jinja2 <http://jinja.pocoo.org>
  [4]  WSGI middlewares <http://wsgi.org/wsgi/Middleware_and_Utilities>
  [5]  Beaker <http://beaker.groovie.org>
  [6]  Static <http://lukearno.com/projects/static/>
  [7]  Memento <http://lukearno.com/projects/memento/>
  [8]  WSGI servers <http://wsgi.org/wsgi/Servers>

EXAMPLE.  Here is a simple example that uses the wsgiref server included in
Python's stdlib [9].

  import berry
  from wsgiref.simple_server import make_server

  @berry.get('^$')
  def index(req):
    return "Welcome to the home page."

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

  # generate your WSGI app
  wsgi_app = berry.app

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

That's it.

  [9]  wsgiref.simple_server <http://docs.python.org/library/wsgiref.html#module-wsgiref.simple_server>.

INSTALLATION.

  Method 1.

    $ git clone git://github.com/adeel/berry.git
    $ cd berry
    # python setup.py install

  Method 2.

    # pip install berry

  Method 3.  Download it from PyPI [10] and build:

    # python setup.py install

  [10]  http://pypi.python.org/pypi/berry

MANUAL.

  § 1  BASICS.  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."

  You can map multiple routes to the same function.

  § 2  THE REQUEST OBJECT.  Useful attributes of Request objects are:

    - method:
        The request method ('GET' or 'POST').
    - params:
        A dict containing parameters passed through both GET and POST.
    - query:
        The query string.
    - path:
        The path requested, minus the initial '/' and the query string.
    - fullpath:
        The full path requested, including the initial '/' and the query
        string.
    - env:
        The WSGI environ variable (a dict) [11].

    § 2.1  PARSING PARAMETERS.

      Example:

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

      If you have a field like 'a[b]' with value 'c', Berry will parse it into
      a dictionary.  For example, if you send the params

        {'person[name]': "James",
         'person[age]': "20"},

      then Request.params will be:

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

      Additionally,

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

      will be parsed as:

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

      (Obviously as stated this example is incorrect as dicts don't take
       multiple values for keys.  Technically, Request.params is a
       cgi.FieldStorage instance [12], which is a dict-like object.)

    § 2.2  THE ENVIRON VARIABLE.  Among other things [11], it is used by
    middleware to get data to your application (e.g. env['beaker.session']).

  § 3  ERROR HANDLING.  You can customize the error pages by using the
  berry.error decorator.  For example:

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

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

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

    To add an exception for a different status code:

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

      § 3.1  APPLICATION (INTERNAL) ERRORS.  When an exception is encountered
      in your application, the traceback will be written to stderr.  If you set
      berry.debug = True, the traceback will also be shown on the error page.

      § 3.2  REDIRECTS.  Raise the berry.Redirect exception:

        raise berry.Redirect(url)

  § 4  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 'text/html'.

  [11]  WSGI environ <http://www.python.org/dev/peps/pep-0333/#environ-variables>
  [12]  cgi.FieldStorage <http://docs.python.org/library/cgi.html#higher-level-interface>

AUTHOR.  Adeel Ahmad Khan <adeel at adeel dot ru>.