Documentation

Table of Contents

Morepath: Super Powered Python Web Framework

Morepath is a Python web microframework, with super powers.

Morepath is an Python WSGI microframework. It uses routing, but the routing is to models. Morepath is model-driven and flexible, which makes it expressive.

  • Morepath does not get in your way.
  • It lets you express what you want, easily. See Quickstart.
  • It’s extensible, with a simple, coherent and universal extension and override mechanism, supporting reusable code. See App Reuse.
  • It understands about generating hyperlinks. The web is about hyperlinks and Morepath actually knows about them. See Paths and Linking.
  • Views are simple functions. Generic views are just views too. See Views.
  • It has all the tools to develop REST web services in the box. See REST.
  • Documentation is important. Morepath has a lot of Documentation.

Sounds interesting?

Walk the Morepath with us!

Video intro

Here is a a 25 minute introduction to Morepath, originally given at EuroPython 2014:

Morepath Knows About Your Models

import morepath

class App(morepath.App):
    pass

class Document(object):
    def __init__(self, id):
        self.id = id

@App.path(path='')
class Root(object):
    pass

@App.path(path='documents/{id}', model=Document)
def get_document(id):
    return Document(id)  # query for doc

@App.html(model=Root)
def hello_root(self, request):
    return '<a href="%s">Go to doc</a>' % request.link(Document('foo'))

@App.html(model=Document)
def hello_doc(self, request):
    return '<p>Hello document: %s!</p>' % self.id

if __name__ == '__main__':
    config = morepath.setup()
    config.scan()
    config.commit()
    morepath.run(App())

Want to know what’s going on? Check out the Quickstart!

More documentation, please!

If you have questions, please join the #morepath IRC channel on freenode. Hope to see you there!

Quickstart

Morepath is a micro-framework, and this makes it small and easy to learn. This quickstart guide should help you get started. We assume you’ve already installed Morepath; if not, see the Installation section.

Hello world

Let’s look at a minimal “Hello world!” application in Morepath:

import morepath

class App(morepath.App):
    pass

@App.path(path='')
class Root(object):
    pass

@App.view(model=Root)
def hello_world(self, request):
    return "Hello world!"

if __name__ == '__main__':
    config = morepath.setup()
    config.scan()
    config.commit()
    morepath.run(App())

You can save this as hello.py and then run it with Python:

$ python hello.py
Running <morepath.App 'Hello'> with wsgiref.simple_server on http://127.0.0.1:5000

If you now go with a web browser to the URL given, you should see “Hello world!” as expected. When you want to stop the server, just press control-C.

This application is a bit bigger than you might be used to in other web micro-frameworks. That’s for a reason: Morepath is not geared to create the most succinct “Hello world!” application but to be effective for building slightly larger applications, all the way up to huge ones.

Let’s go through the hello world app step by step to gain a better understanding.

Code Walkthrough

  1. We import morepath.

  2. We create a subclass of morepath.App named App. This class contains our application’s configuration: what models and views are available. It can also be instantiated into a WSGI application object.

  3. We then set up a Root class. Morepath is model-driven and in order to create any views, we first need at least one model, in this case the empty Root class.

    We set up the model as the root of the website (the empty string '' indicates the root, but '/' works too) using the morepath.App.path() decorator.

  4. Now we can create the “Hello world” view. It’s just a function that takes self and request as arguments (we don’t need to use either in this case), and returns the string "Hello world!". The self argument is the instance of the model class that is being viewed.

    We then need to hook up this view with the morepath.App.view() decorator. We say it’s associated with the Root model. Since we supply no explicit name to the decorator, the function is the default view for the Root model on /.

  5. The if __name__ == '__main__' section is a way in Python to make the code only run if the hello.py module is started directly with Python as discussed above. In a real-world application you instead use a setuptools entry point so that a startup script for your application is created automatically.

  6. morepath.setup() sets up Morepath’s default behavior, and returns a Morepath config object. If your app is in a Python package and you’ve set up the right install_requires in setup.py, consider using morepath.autosetup() to be done in one step.

  7. We then scan() this module (or package) for configuration decorators (such as morepath.App.path() and morepath.App.view()) and cause the registration to be registered using morepath.Config.commit().

    This step ensures your configuration (model routes, views, etc) is loaded exactly once in a way that’s reusable and extensible.

    Note that if you want to use a Morepath extension like more.static, you need to either scan this as well:

    import more.static
    
    ...
    config.scan(more.static)
    ...
    

    or use morepath.autosetup() to automate this. See Organizing your Project for more information.

  8. We then instantiate the App class to create a WSGI app using the default web server. Since you create a WSGI app you can also plug it into any other WSGI server.

This example presents a compact way to organize your code in a single module, but for a real project we recommend you read Organizing your Project. This supports organizing your project with multiple modules.

Routing

Morepath uses a special routing technique that is different from many other routing frameworks you may be familiar with. Morepath does not route to views, but routes to models instead.

Models

A model is any Python object that represents the content of your application: say a document, or a user, an address, and so on. A model may be a plain in-memory Python object or be backed by a database using an ORM such as SQLAlchemy, or some NoSQL database such as the ZODB. This is entirely up to you; Morepath does not put special requirements on models.

Above we’ve exposed a Root model to the root route /, which is rather boring. To make things more interesting, let’s imagine we have an application to manage users. Here’s our User class:

class User(object):
     def __init__(self, username, fullname, email):
         self.username = username
         self.fullname = fullname
         self.email = email

We also create a simple users database:

users = {}
def add_user(user):
     users[user.username] = user

faassen = User('faassen', 'Martijn Faassen', 'faassen@startifact.com')
bob = User('bob', 'Bob Bobsled', 'bob@example.com')
add_user(faassen)
add_user(bob)
Publishing models

We want our application to have URLs that look like this:

/users/faassen

/users/bob

Here’s the code to expose our users database to such a URL:

@App.path(model=User, path='/users/{username}')
def get_user(username):
    return users.get(username)

The get_user function gets a user model from the users database by using the dictionary get method. If the user doesn’t exist, it returns None. We could’ve fitted a SQLAlchemy query in here instead.

Now let’s look at the decorator. The model argument has the class of the model that we’re putting on the web. The path argument has the URL path under which it should appear.

The path can have variables in it which are between curly braces ({ and }). These variables become arguments to the function being decorated. Any arguments the function has that are not in the path are interpreted as URL parameters.

What if the user doesn’t exist? We want the end-user to see a 404 error. Morepath does this automatically for you when you return None for a model, which is what get_user does when the model cannot be found.

Now we’ve published the model to the web but we can’t view it yet.

For more on this, see Paths and Linking.

Views

In order to actually see a web page for a user model, we need to create a view for it:

@App.view(model=User)
def user_info(self, request):
    return "User's full name is: %s" % self.fullname

The view is a function decorated by morepath.App.view() (or related decorators such as morepath.App.json() and morepath.App.html()) that gets two arguments: self, which is the model that this view is working for, so in this case an instance of User, and request which is the current request. request is a morepath.request.Request object (a subclass of webob.request.BaseRequest).

Now the URLs listed above such as /users/faassen will work.

What if we want to provide an alternative view for the user, such as an edit view which allows us to edit it? We need to give it a name:

@App.view(model=User, name='edit')
def edit_user(self, request):
    return "An editing UI goes here"

Now we have functionality on URLs like /users/faassen/edit and /users/bob/edit.

For more on this, see Views.

Linking to models

Morepath is great at creating links to models: it can do it for you automatically. Previously we’ve defined an instance of User called bob. What now if we want to link to the default view of bob? We simply do this:

request.link(bob)

which generates the path /users/bob for us.

What if we want to see Bob’s edit view? We do this:

request.link(bob, 'edit')

And we get /users/bob/edit (with the hostname, for instance http://example.com, as a prefix).

Using morepath.Request.link`() everywhere for link generation is easy. You only need models and remember which view names are available, that’s it. If you ever have to change the path of your model, you won’t need to adjust any linking code.

For more on this, see Paths and Linking.

JSON and HTML views

@App.view is rather bare-bones. You usually know more about what you want to return than that. If you want to return JSON, you can use the shortcut @App.json instead to declare your view:

@App.json(model=User, name='info')
def user_json_info(self, request):
    return {'username': self.username,
            'fullname': self.fullname,
            'email': self.email}

This automatically serializes what is returned from the function JSON, and sets the content-type header to application/json.

If we want to return HTML, we can use @App.html:

@App.html(model=User)
def user_info(self, request):
    return "<p>User's full name is: %s</p>" % self.fullname

This automatically sets the content type to text/html. It doesn’t do any HTML escaping though, so the use of % above is unsafe! We recommend the use of a HTML template language in that case.

Request object

The first argument for a view function is the request object. We’ll give a quick overview of what’s possible here, but consult the WebOb API documentation for more information.

Redirects

To redirect to another URL, use morepath.redirect(). For example:

@App.view(model=User, name='extra')
def redirecting(self, request):
    return morepath.redirect(request.link(self, 'other'))

HTTP Errors

To trigger an HTTP error response you can raise various WebOb HTTP exceptions (webob.exc). For instance:

from webob.exc import HTTPNotAcceptable

@App.view(model=User, name='extra')
def erroring(self, request):
    raise HTTPNotAcceptable()

But note that Morepath already raises a lot of these errors for you automatically just by having your structure your code the Morepath way.

Community

Mailing list/forum

There’s a mailing list/web forum for discussing Morepath. Discussion about use and development of Morepath are both welcome:

https://groups.google.com/forum/#!forum/morepath

Feel free to speak up. Questions are very welcome!

#morepath on Freenode IRC

Want to chat with us? Join us on the #morepath channel on Freenode IRC.

If you don’t have an IRC client, an easy way to use Freenode is through its webchat feature.

Github

Morepath is maintained as a Github project:

https://github.com/morepath/morepath

Feel free to fork it and make pull requests!

We use the Github issue tracker for discussion about bugs and new features:

https://github.com/morepath/morepath/issues

So please report issues there. Feel free to add new issues!

Installation

Quick and Dirty Installation

To get started with Morepath right away, first create a Python 2.7 virtualenv:

$ virtualenv morepath_env
$ source morepath_env/bin/activate

Now install Morepath into it:

$ pip install morepath

You can now use the virtual env’s Python to run any code that uses Morepath:

$ python quickstart.py

See Quickstart for information on how to get started with Morepath itself, including an example of quickstart.py.

Creating a Morepath Project

When you develop a web application it’s a good idae to use standard Python project organization practices. Organizing your Project describes some recommendations on how to do this with Morepath. Relevant in particular is the contents of setup.py, which depends on Morepath and also sets up an entry point to start the web server.

Once you have a project you can use tools like pip or buildout. We’ll briefly describe how to use both.

pip

With pip and a virtualenv called morepath_env, you can do this in your project’s root directory:

$ pip install --editable .

You can now run the application like this (if you called the console script myproject-start):

$ myproject-start
buildout

Buildout is more involved than pip, but can also do a lot more for you automatically and repeatedly.

Create a buildout.cfg file containing this:

[buildout]
develop = .
parts = scripts devpython
versions = versions

[versions]
venusian = 1.0a8
morepath = 0.1
reg = 0.6

[scripts]
recipe = zc.recipe.egg:scripts
eggs = myproject
       pytest

[devpython]
recipe = zc.recipe.egg
interpreter = devpython
eggs = myproject
       flake8

This describes how to install our project for development. Change myproject to the name your project has in setup.py.

Place a buildout bootstrap.py in your project’s root directory.

The first time you create or check out a project you need to bootstrap the buildout. You can do this using the bootstrap.py script. Do this from a virtualenv:

$ /path/to/morepath_env/bin/python bootstrap.py

You only need to do this once. After that you can run:

$ bin/buildout

each time you want to redo the installation after you change the buildout config. It’s safe to run this when nothing has really changed too.

Once you’ve run buildout, you can start your application. If it’s named myproject-start in the entry point in setup.py, you can run it like this:

$ bin/myproject-start
What’s going on with buildout?

What’s going on? What else did that buildout.cfg do for us?

The develop line tells which directories to look in for Python projects (with a setup.py). In this case only the local project directory . is one. But if you also have the checkout of another project that you depend on (maybe a development version of Morepath itself), you can add that directory to the develop section.

parts tells buildout what to configure; they are described in the [scripts] and [devpython] sections later.

The line versions=versions tells buildout to lock down version numbers according to the [versions] section.

The [scripts] section installs your web application as a script in the bin subdirectory of your project, according to the console_scripts entry point in your project’s setup.py. If it’s called myproject-start, then you can start it like this:

bin/myproject-start

This will start a HTTP server for your project.

The buildout also has installed pytest so you can run your project’s tests automatically:

bin/py.test myproject

(if your Python package is in myproject)

Now as to some optional extras. The [devpython] section installs a Python interpreter which can import exactly what your project can import. It assumes your project is called myproject in its setup.py; change the name to match your project. You can start it using:

$ bin/devpython

You’ll get the usual Python console >>>. This is useful for testing your project’s imports and API manually.

It also installs the flake8 tool which runs pep 8 checks and pyflakes automatically. You can run it against your project by writing:

$ bin/flake8 myproject

where myproject is your project’s source code directory.

Depending on Morepath development versions

If you like being on the cutting edge and want to depend on the latest Morepath and Reg development versions always, we recommend you use buildout with the mr.developer extension for your project. You can see how in this buildout.cfg.

You can also install these using pip (in a virtualenv). Here’s how:

$ pip install git+git://github.com/morepath/reg.git@master

$ pip install git+git://github.com/morepath/morepath.git@master

Superpowers

We said Morepath has super powers. Are they hard to use, then? No: they’re both powerful and also easy to use, which makes them even more super!

Generic UI

Morepath knows about model inheritance. It lets you define views for a base class that automatically become available for all subclasses. This is a powerful mechanism to let you write generic UIs.

For example, if we have this generic base class:

class ContainerBase(object):
    def entries(self):
       """All entries in the container returned as a list."""

We can easily define a generic default view that works for all subclasses:

@App.view(model=ContainerBase)
def overview(self, request):
    return ', '.join([entry.title for entry in self.entries()])

But what if you want to do something different for a particular subclass? What if MySpecialContainer needs it own custom default view? Easy:

@App.view(model=MySpecialContainer)
def special_overview(self, request):
    return "A special overview!"

Morepath leverages the power of the flexible Reg generic function library to accomplish this.

For much more, see Views.

Model-driven Permissions

Morepath features a very flexible but easy to use permission system. Let’s say we have an Edit permission; it’s just a class:

class Edit(object):
    pass

And we have a view for some Document class that we only want to be accessible if the user has an edit permission:

@App.view(model=Document, permission=Edit)
def edit_document(self, request):
    return "Editable"

How does Morepath know whether someone has Edit permission? We need to tell it using the morepath.App.permission_rule() directive. We can implement any rule we want, for instance this one:

@App.permission_rule(model=Document, permission=Edit)
def have_edit_permission(identity, model, permission):
    return model.has_permission(identity.userid)

Instead of a specific rule that only works for Document, we can also give our app a broad rule (use model=object).

Composable Views

Let’s say you have a JSON view for a Document class:

@App.json(model=Document)
def document_json(self, request):
    return {'title': self.title}

And now we have a view for a container that contains documents. We want to automatically render the JSON views of the documents in a list. We can write this:

@App.json(model=DocumentContainer)
def document_container_json(self, request):
    return [document_json(request, doc) for doc in self.entries()]

Here we’ve used document_json ourselves. But what now if the container does not only contain Document instances? What if one of them is a SpecialDocument? Our document_container_json function breaks. How to fix it? Easy, we can use morepath.Request.view():

@App.json(model=DocumentContainer)
def document_container_json(self, request):
    return [request.view(doc) for doc in self.entries()]

Now document_container_json works for anything in the container model that has a default view!

Extensible Applications

Somebody else has written an application with Morepath. It contains lots of stuff that does exactly what you want, and one view that doesn’t do what you want:

@App.view(model=Document)
def recalcitrant_view(self, request):
    return "The wrong thing!"

Ugh! We can’t just change the application as it needs to continue to work in its original form. Besides, it’s being maintained by someone else. What do we do now? Monkey-patch? Not at all: Morepath got you covered. You simply create a new application subclass that extends the original:

class MyApp(App):
    pass

We now have an application that does exactly what app does. Now to override that one view to do what we want:

@MyApp.view(model=Document)
def whatwewant(self, request):
    return "The right thing!"

And we’re done!

It’s not just the view directive that works this way: all Morepath directives work this way.

Morepath also lets you mount one application within another, allowing composition-based reuse. See App Reuse for more information. Using these techniques you can build large applications, see Building Large Applications.

A Review of the Web

Morepath is a web framework. Here is a quick review of how the web works, how applications can be built with it, and how Morepath fits.

HTTP protocol

HTTP is a protocol by which clients (such as web browsers) and servers can communicate. The client sends a HTTP request, and the server sends back a HTTP response. HTTP is extensible, and can be extended with content types, new headers, and so on.

Version 1.1 of HTTP is most common on the web today. It is defined by a bunch of specifications:

Luckily it’s not necessary to understand the full details of these specifications to develop a web application. We’ll go into a basic overview of relevant concepts in this document.

Morepath handles the HTTP protocol on the server side: creating a response to incoming HTTP requests.

Web browser

A web browser such as Firefox, Chrome and Internet Explorer uses the HTTP protocol to talk to web servers.

A web browser is a type of HTTP client.

Web server

A web server implements the HTTP protocol to respond to requests from HTTP clients such as web browsers.

There are general web servers such as Apache and Nginx. These are programmable in various ways.

There are also more specific web servers that are geared at particular tasks. Examples of these are Waitress and Gunicorn which are geared towards serving web applications written in Python.

A web server is programmable in various ways. Morepath can plug into web servers that implement the Python WSGI protocol.

Web application

A web application is software that presents a user interface by means of a web browser. The web browser is usually a visible piece of software, but may also be embedded in other software, such as in FirefoxOS.

A web application is loaded from a web server. After it is loaded it can still interact with the web server (or other web servers). The web server can implement part of the application logic and maintains the application data.

The dynamic behavior of a web application used to be implemented almost entirely by the server, but it is now also possible to implement a large part of their behavior within the web browser instead, using the JavaScript language.

Morepath code runs entirely on the server, but supports web applications that want to implement a large part of their dynamic behavior within the web browser.

Web service

A web service does not present a user interface to the user. A web service instead presents an application programming interface (API) to custom HTTP client software. The API is to this software what the UI is to the user.

You can layer a full web application on top of a web service. Such layering can result in looser coupling in the implementation, which tends to increase the quality of the implementation.

Morepath helps developers to implement web services.

Custom HTTP client

A web browser is one form of HTTP client, but other HTTP software can be written in a variety of languages to talk to a web server programmatically. This uses it as a web service.

JavaScript code in a web browser can also use the browser’s facilities to talk to the web server programmatically (a technique called AJAX), and can thus serve as a custom HTTP client as well.

Framework

A library is reusable code that your code calls, whereas a framework is reusable code that calls your code. “Don’t call us, we’ll call you”.

A framework aims to help you do particular tasks quickly; you only need to fill in the details, and the framework handles the rest.

There is a gray area between library and framework. Morepath is mostly a framework.

Server web framework

A framework that helps you program the behavior of a web server. Morepath is a server web framework written in the Python programming language.

JavaScript

JavaScript is a programming language that is run in the browser. It can use the web browser APIs (such as the DOM) to manipulate the web page, get user input, or access the server programmatically (AJAX).

JavaScript can also be run on the server with Node.JS, but Morepath is a Python web framework and does not make use of server-side JavaScript.

Bower is a tool to help manage client-side JavaScript code.

Bower

A popular way to install client-side JavaScript (and CSS) code is to use the Bower package management tool. By using a package manager installing and updating a collection of JavaScript libraries becomes more easy than doing it by hand.

Morepath offers Bower integration, see: Static resources with Morepath.

AJAX

AJAX is a technique to access resources programmatically from a browser application in JavaScript. These resources typically have a JSON representation.

Client web framework

There are also client-side web frameworks that let you program the behavior of a web browser, typically called “JavaScript MVC framework”. Examples of such are React, Ember and Angular.

Morepath supports client-side code that uses a client web framework, but does not implement a client web framework itself. You can pick whichever you want.

WSGI

WSGI is a Python protocol by which Python code can be integrated with a web server. WSGI can also be used to implement framework components which are layered between application code and server.

A morepath.App instance implements the WSGI protocol and can therefore be integrated with a WSGI-compliant web server and WSGI framework component.

HTTP request

A HTTP request is a message a HTTP client sends to the server. The server then returns a HTTP response.

The HTTP request contains a URL path, a request method, possibly a request body, and various headers such as the content type.

A HTTP request in Morepath is made accessible programmatically as a Python request object using the WebOb library. It is a class:`morepath.Request, which is a subclass of webob.request.BaseRequest.

HTTP response

A HTTP response returns a representation of the resource indicated by the path of the request as the response body. The response has a content type which determines what representation is being sent. The response also has a status code that indicates whether the request could be handled, or the reason why a detailed response could not be generated.

A lot of different representations exist. HTML is a very common one, but for programmatic clients JSON is typically used.

Morepath lets you create a morepath.Response object directly, which is a subclass of webob.response.Response, and return it from a view function.

More conveniently you use a specialized view type (morepath.App.json() or morepath.App.html()) and return the content that should go into the response body, such as a HTML string or a JSON-serializable object. Morepath then automatically creates the response with the right content type for you. Should you wish to set additional information on the response object, you can use morepath.Request.after().

Resource

A resource is anything that can be addressed on the web by a URL (or URI or IRI). Can be a web page presenting a full UI (using HTML + CSS), or can be a piece of information (typically in JSON), or can also be an abstract entity that has no representation at all.

Morepath lets you implement resources of all kinds. Normally Morepath resources have representations, but it is also possible to implement abstract entities that have just a URL and have no representation. Morepath can also help you create links to resources on other web servers.

URL

Here is an example of a URL:

http://example.com/documents/3

A HTTP client such as a web browser uses URLs to determine:

  • What protocol to use to talk to the server (in this case http).
  • What host to talk to (in this case example.com). This identifies the web server, though a complex host may be implemented using a combination of web servers.
  • What path to request from the server (in this case /documents/3).

The server determines how it responds to requests for particular paths.

Path

A path is a way for a client to address a particular resource on a server. It is part of the request. The path is also part of URLs, and thus can be used for linking resources.

Morepath connects paths with Python objects using the path directive (morepath.App.path()): it can resolve a path to a Python object, and construct a path for a given Python object. This is described in Paths and Linking.

Example:

@App.path(path='/documents/{id}', model=Document)
def get_document(id):
   return query_document(id)

Headers

A HTTP request and a HTTP response have headers. Headers contain information about the message that are not the body: they are about the request or the response, or about the body. For example, the content-type is header named Content-Type and has a value that is a MIME type such as text/html.

Headers are used for a wide variety of purposes, such as to declare information about how a client may cache a response, or what kind of responses a client accepts from a server, or to pass cookies along. Here is an overview of common headers.

In Morepath, the headers are accessible on a request and response object as the attribute webob.request.BaseRequest.headers and webob.response.Response.headers. which behaves like a Python dictionary. You could therefore access the request content-type using request.headers['Content-Type']. But see below for a more convenient way to access the content type.

To set the headers (or other information) on a response, you can create a morepath.Response instance in a view function. You can then pass in the headers, or set them afterward.

Often better is to use the morepath.Request.after() decorator to declare a function that sets headers the response object once it has been created for you by the framework.

WebOb has APIs that help you deal with many headers at a higher level of abstraction. For example, webob.request.BaseRequest.content_type is a more convenient way to access the content type information of a request than to access the header directly, as additional charset information is not there. Before you start to manipulate headers directly it pays off to consult the WebOb documentation for webob.request.BaseRequest and webob.response.Response: there may well be a better way.

Morepath also has special support for dealing with certain headers. For instance, the Forwarded header can be set by a HTTP proxy. To make Morepath use this header for URL generation, you can use the more.forwarded extension.

Cookies

One special set of headers deals with HTTP cookies. A server can set a cookie on the client by passing back a special header in its response. A cookie is much like a key/value pair in a Python dictionary.

Once the cookie has been set, the client sends back the cookie to the server during each subsequent request, again using a header, until the cookie expires or cookie is explicitly deleted by the server using a response header.

Normally in HTTP requests are independent from each other: assuming the server database is the same, the same request should give the same response, no matter what other requests have gone before it. This makes it easier to reason about HTTP, and it makes it easier to scale it up, for instance by caching responses.

Cookies change this: they can be used to make requests order-dependent. This can be useful, but it can also make it harder to reason about what is going on and scale, so be careful with them. In particular, a REST web service should be able to function without requiring the client to maintain cookies.

Cookies are commonly used to store login session information on the client.

WebOb makes management of cookies more convenient: the webob.request.BaseRequest.cookies attribute on the request object contains the list of cookies sent by the client, and the response object has an API incuding webob.response.Response.set_cookie() and webob.response.Response.delete_cookie() to allow you to manage cookies.

Content types

A resource may present itself in variety of representations. This is indicated by the content type set in the HTTP response, using the Content-Type header. There are a lot of content types, including HTML and JSON. The value is a MIME type such as text/html for HTML and application/json for JSON. The value can also contain additional parameters such as character encoding information.

WebOb makes content-type header information conveniently available with the webob.request.BaseRequest.content_type, webob.response.Response.content_type and webob.response.Response.content_type_params attributes.

A request may also have a content type: the request content type determines what kind of content is sent to the server by the client in the request body.

While you can create any kind of content type with Morepath, it has special support for generating HTML and JSON responses (using morepath.App.html() and morepath.App.json()), and for processing a JSON request body (see load_json in JSON and objects).

View

In Morepath, a view is a Python function that takes a Python object to represent (self) and a morepath.Request object (request) as arguments and returns something that can be turned into a HTTP response, or a HTTP response object directly.

Here is an example of a Morepath view, using the most basic morepath.App.view() directive:

@App.view(model=MyObject)
def my_object_default(self, request):
    return "some text content"

There are also specific morepath.App.json() and morepath.App.html() directives to support those content types.

See Views for much more on how to construct Morepath views.

HTTP request method

A HTTP request has a method, also known as HTTP verb. The GET method is used to retrieve information from the server. The POST method is used to add new information to the server (for instance a form submit), and the PUT method is used to update existing information. The DELETE method is used to delete information from the server.

It is up to the server implementation how to exactly handle the request method. With Morepath, by default a view responds to the GET method, but you can also write views to handle the other HTTP methods, by indicating it with a view predicate. Here is a view that handles the POST method (and returns a representation of what has just been POSTed):

@App.view(model=MyCollection, request_method='POST')
def add_to_collection(self, request):
    item = MyItem(request.json)
    self.add(item)
    return request.view(item)

You can access the method on the request using webob.request.BaseRequest.method, but typically Morepath does this for you when you use the request_method predicate.

View predicate

A view predicate in Morepath is used to match a view function with details of self and request.

This view directive:

@App.view(model=MyCollection, request_method='POST')
def add_to_collection(self, request):
   ...

only matches when self is an instance of MyCollection (model predicate) and when request.method is POST (request_method predicate). Only in this case will add_to_collection be called.

You can extend Morepath with additional view predicates. You can also define a predicate fallback, which can be used to specify what HTTP status code to set when the view cannot be matched.

See view predicates

HTTP status codes

HTTP status codes such as 200 Ok and 404 Not Found are part of the HTTP response. Here is a list of HTTP status codes. The server can use them to indicate to the client whether it was successfully able to create a response, or if not, what the problem was.

Morepath can automatically generate the correct HTTP status codes for you in many cases:

200 Ok:
When the path in the request is matched with a path directive, and there is a view for the particular model and request method.
404 Not Found:

When the path does not match, or when the path matches but the path function returns None.

Also when no view is available for the request in combination with the object returned by the path function. More specifically, the model view predicate or the name view predicate do not match.

400 Bad Request:
When information in the path or request parameters could not be converted to the required types.
405 Method Not Allowed:
When no view exists for the given HTTP request method. More specifically, the request_method view predicate does not match.
422 Unprocessable Entity:

When the request body supplied with a POST or PUT request can be parsed (as JSON, for instance), but is not the correct type.

More specifically, the body_model view predicate does not match.

500 Internal Server Error:
There is a bug in the server that causes an exception to be raised. Morepath does not generate these itself, but a WSGI server automatically catches any exceptions not handled by Morepath and turns them into 500 errors.

Instead of having to write code that sends back the right status codes manually, you declare paths and views with Morepath and Morepath can usually do the right thing for you automatically. This saves you from writing a lot of custom code when you want to implement HTTP properly.

Sometimes it is still useful to set the status code directly. WebOb lets you raise special exceptions for HTTP errors. You can also set the webob.response.Response.status attribute on the response.

JSON

A representation of a resource. JSON is a language that represents data, not user interface (like HTML combined with CSS) or logic (like Python or JavaScript). JSON looks like this:

{
  "id": "foo_barson",
  "name": "Foo Barson",
  "occupation": "Carpenter",
  "level": 34
  "friends": ["http://example.com/people/qux_quxson",
              "http://example.com/people/one_twonson"]
}

JSON is the most common data representation language used in REST web services. The main alternative is XML. While XML does offer more extensive tooling support, it is a lot more verbose and more difficult to process than JSON. JSON is already very close to the data structures of many programming languages, including JavaScript and Python.

In Python, JSON can be constructed by combining Python dictionaries and lists with strings, numbers, booleans and None.

With Morepath you can use the morepath.App.json() directive to generate JSON programmatically:

@App.json(model=MyObject)
def my_object_default(self, request):
     return {
        "id": self.id,
        "name": self.name,
        "occuptation": self.get_occupation(),
        "level": self.level,
        "friends": [request.link(friend) for friend in self.friends]
     }

This works like the view directive, but in addition converts the return value of the function into a JSON response that is sent to the client.

JSON-LD

JSON-LD is an extension of JSON that helps support linked data in JSON. Any JSON-LD structure is valid JSON, but not every JSON structure is valid JSON-LD.

Using a @context, it lets a JSON object describe which parts of it contain hyperlinks, and also allows JSON property names themselves to be interpreted as unique hyperlinks. You can also express that particular property values have a particular data type; this can range from basic data types like datetime to custom data types like “person”. All of this can help when you want to process JSON coming from different data sources.

Perhaps more important in practice for REST web services is that it also offers a standard way for a JSON object to have a unique id and a type. Both are identified by a hyperlink, as the special @id and @type properties. @type in particular makes it easier to use JSON data as hypermedia: client behavior can be driven by the type of data that is retrieved, instead of what URL it happened to be retrieved from.

Morepath does not mandate the use of JSON-LD, or has any special support for it, but its link generation facilities make it easier to use it.

HTTP API

A HTTP API is a web service that is built on HTTP; it is based on the notion of HTTP resources on URLs and has an understanding of HTTP request methods.

This is to distinguish it from a web service implementation where HTTP is merely a transport mechanism, such as SOAP.

Because the client needs to understand what URLs exist on the server and how to interpret their response, the coupling between client and server code is relatively tight.

This type of web service is commonly called a REST web service, but the original definition of REST goes beyond this and adds hypermedia. Many HTTP APIs only reach level 2 on the Richardson Maturity Model, which isn’t full REST yet.

A HTTP API is sometimes simply called API, which is also confusing, as the word API has a lot of other uses in development outside of HTTP.

Morepath is designed to help you build HTTP APIs, but also to go you a step further to full REST.

REST web service

Morepath helps you to create REST web service, also known as a hypermedia API.

This is level 3 on the Richardson Maturity Model.

This means that to interact with the content of the web service you can follow hyperlinks. A client starts at one root URL and to get to other information it follow links in the content.

Different JSON resources can be distinguished from each other by their type; this can based on the content-type of the response, or be based on information within the content itself, such as a type property in JSON (@type in JSON-LD).

In other words, the web service represents itself to software much like a web site presents itself to a human: as content with links.

A REST web service allows for a looser coupling between server and client than a plain HTTP API allows, as the client does not need to know more than a single entry point URL into the server, and only needs an understanding of the response types and how to navigate links.

HTML and CSS

HTML is a markup language used to represent a resource. Augmented by CSS, a style language, it determines what you see on a web page.

HTML can be loaded from a files on the server; this typically done with a general web server such as Apache and Nginx. For dynamic applications HTML can also be generated on the server, often using a server-side templating language.

HTML may also be manipulated programmatically in the browser using JavaScript through the DOM API.

In Morepath you can use the morepath.App.html() view directive to generate HTML programmatically:

@App.view(model=MyObject)
def my_object_default(self, request):
     return '<html><head></head><body></body></html>'

Morepath at this point does not have support for server-side templating.

See Static resources with Morepath for information on how you can load static resources such as CSS and JavaScript automatically to augment a HTML page.

Web page

The browser displays a user interface to the user in the form of a web page. A web page is usually constructed using HTML and CSS. Other content such as images, video, audio, SVG, canvas, WebGL may also be embedded into it.

JavaScript code is executed in the browser to make the user interface more dynamic, and this dynamism can go very far.

A web page is loaded by putting a URL in the address bar of the browser. The browser then fetches it (and related resources) from the server. You can do this manually, or by clicking a link, or the URL of the browser may be changed programmatically with JavaScript code.

In the past, all web applications were implemented as a multiple web pages that were generated on the server in response to user actions.

It is also possible to change the URL in the address bar without fetching a complete new web page from the server. This technique is used to implement single-page web applications.

Single-page web application

A single-page web application (SPA) is web application that consists of a single web page that is updated within the browser without the need to load a complete need web page. So the web page is loaded from the server only once, when the user first goes there.

When a user interacts with it, JavaScript code is executed that updates the user interface and may also interact with a web server using AJAX.

A single page web application may update the URL in the address bar of the browser, and respond to URL changes, but it is the same web page that implements the behavior for all these URLs. It may need a bit of server-side support to do so.

Morepath supports the creation of single-page web applications. It also lets you create multi-page applications, but at this point in time has no special support for server-side templating.

Paths and Linking

Introduction

Morepath lets you publish model classes on paths using Python functions. It also lets you create links to model instances. To be able do so Morepath needs to be told what variables there are in the path in order to find the model, and how to find these variables again in the model in order to construct a link to it.

Paths

Let’s assume we have a model class Overview:

class Overview(object):
    pass

Here’s how we could expose it to the web under the path overview:

@App.path(model=Overview, path='overview')
def get_overview():
    return Overview()

And let’s give it a default view so we can see it when we go to its URL:

@App.view(model=Overview)
def overview_default(self, request):
    return "Overview"

No variables are involved yet: they aren’t in the path and the get_overview function takes no arguments.

Let’s try a single variable now. We have a class Document:

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

Let’s expose it to the web under documents/{name}:

@App.path(model=Document, path='documents/{name}')
def get_document(name):
    return query_document_by_name(name)

@App.view(model=Document)
def document_default(self, request):
    return "Document: " + self.name

Here we declare a variable in the path ({name}), and it gets passed into the get_document function. The function does some kind of query to look for a Document instance by name. We then have a view that knows how to display a Document instance.

We can also have multiple variables in a path. We have a VersionedDocument:

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

We could expose this to the web like this:

@App.path(model=VersionedDocument,
          path='versioned_documents/{name}-{version}')
def get_versioned_document(name, version):
    return query_versioned_document(name, version)

@App.view(model=VersionedDocument)
def versioned_document_default(self, request):
    return "Versioned document: %s %s" % (self.name, self.version)

The rule is that all variables declared in the path can be used as arguments in the model function.

URL query parameters

What if we want to use URL parameters to expose models? That is possible too. Let’s look at the Document case first:

@App.path(model=Document, path='documents')
def get_document(name):
    return query_document_by_name(name)

get_document has an argument name, but it doesn’t appear in the path. This argument is now taken to be a URL parameter. So, this exposes URLs of the type documents?name=foo. That’s not as nice as documents/foo, so we recommend against parameters in this case: you should use paths to identify something.

URL parameters are more useful for queries. Let’s imagine we have a collection of documents and we have an API on it that allows us to search in it for some text:

class DocumentCollection(object):
    def __init__(self, text):
        self.text = text

    def search(self):
        if self.text is None:
            return []
        return fulltext_search(self.text)

We now publish this collection, making it searchable:

@App.path(model=DocumentCollection, path='search')
def document_search(text):
    return DocumentCollection(text)

To be able to see something, we add a view that returns a comma separated string with the names of all matching documents:

@App.view(model=DocumentCollection)
def document_collection_default(self, request):
    return ', '.join([document.name for document in self.search()])

As you can see it uses the DocumentCollection.search method.

Unlike path variables, URL parameters can be omitted, i.e. we can have a plain search path without a text parameter. In that case text has the value None. The search method has code to handle this special case: it returns the empty list.

Often it’s useful to have a default instead. Let’s imagine we have a default search query, all that should be used if no text parameter is supplied (instead of None). We make a default available by supplying a default value in the document_search function:

@App.path(model=DocumentCollection, path='search')
def document_search(text='all'):
    return DocumentCollection(text)

Note that defaults have no meaning for path variables, because whenever a path is resolved, all variables in it have been found. They can be used as type hints however; we’ll talk more about those soon.

Like with path variables, you can have as many URL parameters as you want.

Extra URL query parameters

URL parameters are matched with function arguments, but it could be you’re interested in an arbitrary amount of extra URL parameters. You can specify that you’re interested in this by adding an extra_parameters argument:

@App.path(model=DocumentCollection, path='search')
def document_search(text='all', extra_parameters):
    return DocumentCollection(text, extra_parameters)

Now any additional URL parameters are put into the extra_parameters dictionary. So, search?text=blah&a=A&b=B would match text with the text parameter, and there would be an extra_parameters containing {'a': 'A', 'b': 'B'}.

extra_parameters can also be useful for the case where the name of the parameter is not a valid Python name (such as @foo) – you can still receive such parameters using extra_parameters.

Linking

To create a link to a model, we can call morepath.Request.link() in our view code. At that point the model is examined to retrieve the variables so that the path can be constructed.

Here is a simple case involving Document again:

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

@App.path(model=Document, path='documents/{name}')
def get_document(name):
    return query_document_by_name(name)

We add a named view called link that links to the document itself:

@App.view(model=Document, name='link')
def document_self_link(self, request):
    return request.link(self)

The view at /documents/foo/link produces the link /documents/foo. That’s the right one!

So, it constructs a link to the document itself. This view is not very useful, but the principle is the same everywhere in any view: as long as we have a Document instance we can create a link to it using request.link().

You can also give link a name to link to a named view. Here’s a link2 view creates a link to the link view:

@App.view(model=Document, name='link2')
def document_self_link(self, request):
    return request.link(self, name='link')

So the view at /documents/foo/link2 produces the link /documents/foo/link.

Linking with path variables

How does the request.link code know what the value of the {name} variable should be so that the link can be constructed? In this case this happened automatically: the value of the name attribute of Document is assumed to be the one that goes into the link.

This automatic rule won’t work everywhere, however. Perhaps an attribute with a different name is used, or a more complicated method is used to construct the name. For those cases we can take over and supply a custom variables function that knows how to construct the variables needed to construct the link from the model.

The variables function gets the model as a single argument and needs to return a dictionary. The keys should be the variable names used in the path or URL parameters, and the values should be the values as extracted from the model.

As an example, here is the variables function for the Document case made explicit:

@App.path(model=Document, path='documents/{name}',
          variables=lambda model: dict(name=model.name))
def get_document(name):
    return query_document_by_name(name)

Or to spell it out without the use of lambda:

def document_variables(model):
    return dict(name=model.name)

@App.path(model=Document, path='documents/{name}',
          variables=document_variables)
def get_document(name):
    return query_document_by_name(name)

Let’s change Document so that the name is stored in the id attribute:

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

Our automatic variables won’t cut it anymore, so we have to be explicit:: attribute, we can do this:

@App.path(model=DifferentDocument, path='documents/{name}',
          variables=lambda model: dict(name=model.id))
def get_document(name):
    return query_document_by_name(name)

All we’ve done is adjust the variables function to take model.id.

Getting variables works for multiple variables too of course. Here’s the explicit variables for the VersionedDocument case that takes multiple variables:

@App.path(model=VersionedDocument,
          path='versioned_documents/{name}-{version}',
          variables=lambda model: dict(name=model.name,
                                       version=model.version))
def get_versioned_document(name, version):
    return query_versioned_document(name, version)

If you have extra_parameters, the default variables expects that extra_parameters to exist as an attribute on the object, but you can write a custom variables that retrieves this dictionary from the object in some other way:

@App.path(model=SearchResults,
          path='search',
          variables=lambda model: dict(text=model.search_text,
                                       extra_parameters=model.get_extra()))
def get_search_results(text, extra_parameters):
    ...

Linking with URL query parameters

Linking works the same way for URL parameters as it works for path variables.

Here’s a get_model that takes the document name as a URL parameter, using an implicit variables:

@App.path(model=Document, path='documents')
def get_document(name):
    return query_document_by_name(name)

Now we add back the same self_link view as we had before:

@App.view(model=Document, name='link')
def document_self_link(self, request):
    return request.link(self)

Here’s get_document with an explicit variables:

@App.path(model=Document, path='documents',
          variables=lambda model: dict(name=model.name))
def get_document(name):
    return query_document_by_name(name)

i.e. exactly the same as for the path variable case.

Let’s look at a document exposed on this URL:

/documents?name=foo

Then the view documents/link?name=foo constructs the link:

/documents?name=foo

The documents/link?name=foo is interesting: the name=foo parameters are added to the end, but they are used by the get_document function, not by its views. Here’s link2 again to further demonstrate this behavior:

@App.view(model=Document, name='link2')
def document_self_link(self, request):
    return request.link(self, name='link')

When we now go to documents/link2?name=foo we get the link /documents/link?name=foo.

Linking to external applications

As a more advanced use case for link_prefix, you can use it to represent an application that is completely external, just for the purposes of making it easier to create a link to it.

Let’s say we want to be able to link to documents on the external site http://example.com, and that these documents live on URLs like http://example.com/documents/{id}.

We can create a model for such an external document first:

class ExternalDocument(object):
    def __init__(self, id):
        self.id = id

And declare the path space of the external site:

@ExternalApp.path(model=ExternalDocument, path='/documents/{id}')
def get_external_document(id):
    return ExternalDocument(id)

We don’t need to declare any views for ExternalDocument; ExternalApp only exists to let you generate a link to the example.com external site more easily.

Now we want request.link(ExternalDocument('foo')) to result in the link http://example.com/documents/foo. All we need to do is to declare a special link_prefix for the external app where we hardcode http://example.com:

@ExternalApp.link_prefix()
def simple_link_prefix(request):
    return 'http://example.com'

Type hints

So far we’ve only dealt with variables that have string values. But what if we want to use other types for our variables, such as int or datetime? What if we have a record that you obtain by an int id, for instance? Given some Record class that has an int id like this:

class Record(object):
    def __init__(self, id):
        self.id = id

We could do this to expose it:

@App.path(model=Record, path='records/{id}')
def get_record(id):
    try:
        id = int(id)
    except ValueError:
        return None
    return record_by_id(id)

But Morepath offers a better way. We can tell Morepath we expect an int and only an int, and if something else is supplied, the path should not match. Here’s how:

@App.path(model=Record, path='records/{id}')
def get_record(id=0):
    return record_by_id(id)

We’ve added a default parameter (id=0) here that Morepath uses as an indication that only an int is expected. Morepath will now automatically convert id to an int before it enters the function. It also gives a 404 Not Found response for URLs that don’t have an int. So it accepts /records/100 but gives a 404 for /records/foo.

Let’s examine the same case for an id URL parameter:

@App.path(model=Record, path='records')
def get_record(id=0):
    return record_by_id(id)

This responds to an URL like /records?id=100, but rejects /records/id=foo as foo cannot be converted to an int. It rejects a request with the latter path with a 400 Bad Request error.

By supplying a default for a URL parameter we’ve accomplished two in one here, as it’s a good idea to supply defaults for URL parameters anyway, as that makes them properly optional.

Conversion

Sometimes simple type hints are not enough. What if multiple possible string representations for something exist in the same application? Let’s examine the case of datetime.date.

We could represent it as a string in ISO 8601 format as returned by the datetime.date.isoformat() method, i.e. 2014-01-15 for the 15th of january 2014. We could also use ISO 8601 compact format, namely 20140115 (and this what Morepath defaults to). But we could also use another representation, say 15/01/2014.

Let’s first see how a string with an ISO compact date can be decoded (deserialized, loaded) into a date object:

from datetime import date
from time import mktime, strptime

def date_decode(s):
    return date.fromtimestamp(mktime(strptime(s, '%Y%m%d')))

We can try it out:

>>> date_decode('20140115')
datetime.date(2014, 1, 15)

Note that this function raises a ValueError if we give it a string that cannot be converted into a date:

>>> date_decode('blah')
Traceback (most recent call last):
   ...
ValueError: time data 'blah' does not match format '%Y-%m-%d'

This is a general principle of decode: a decode function can fail and if it does it should raise a ValueError.

We also specify how to encode (serialize, dump) a date object back into a string:

def date_encode(d):
    return d.strftime('%Y%m%d')

We can try it out too:

>>> date_encode(date(2014, 1, 15))
'20140115'

A encode function should never fail, if at least presented with input of the right type, in this case a date instance.

Now that we have our date_decode and date_encode functions, we can wrap them in an morepath.Converter object:

date_converter = morepath.Converter(decode=date_decode, encode=date_encode)

Let’s now see how we can use date_converter.

We have some kind of Records collection that can be parameterized with start and end to select records in a date range:

class Records(object):
   def __init__(self, start, end):
      self.start = start
      self.end = end

   def query(self):
      return query_records_in_date_range(self.start, self.end)

We expose it to the web:

@App.path(model=Records, path='records',
          converters=dict(start=date_converter, end=date_converter))
def get_records(start, end):
    return Records(start, end)

We also add a simple view that gives us comma-separated list of matching record ids:

@App.view(model=Records):
def records_view(self, request):
    return ', '.join([str(record.id) for record in self.query()])

We can now go to URLs like this:

/records?start=20110110&end=20110215

The start and end URL parameters now are decoded into date objects, which get passed into get_records. And when you generate a link to a Records object, the start and end dates are encoded into strings.

What happens when a decode raises a ValueError, i.e. improper dates were passed in? In that case, the URL parameters cannot be decoded properly, and Morepath returns a 400 Bad Request response.

You can also use encode and decode for arguments used in a path:

@App.path(model=Day, path='days/{d}', converters=dict(d=date_converter))
def get_day(d):
    return Day(d)

This publishes the model on a URL like this:

/days/20110101

When you pass in a broken date, like /days/foo, a ValueError is raised by the date decoder, and a 404 not Found response is given by the server: the URL does not resolve to a model.

Default converters

Morepath has a number of default converters registered; we already saw examples for int and strings. Morepath also has a default converter for date (compact ISO 8601, i.e. 20131231) and datetime (i.e. 20131231T23:59:59).

You can add new default converters for your own classes, or override existing default behavior, by using the morepath.App.converter() decorator. Let’s change the default behavior for date in this example to use ISO 8601 extended format, so that dashes are there to separate the year, month and day, i.e. 2013-12-31:

def extended_date_decode(s):
    return date.fromtimestamp(mktime(strptime(s, '%Y-%m-%d')))

def extended_date_encode(d):
    return d.strftime('%Y-%m-%d')

@App.converter(type=date)
def date_converter():
    return Converter(extended_date_decode, extended_date_encode)

Now Morepath understand type hints for date differently:

@App.path(model=Day, path='days/{d}')
def get_day(d=date(2011, 1, 1)):
    return Day(d)

has models published on a URL like:

/days/2013-12-31

Type hints and converters

You may have a situation where you don’t want to add a default argument to indicate the type hint, but you know you want to use a default converter for a particular type. For those cases you can pass the type into the converters dictionary as a shortcut:

@App.path(model=Day, path='days/{d}', converters=dict(d=date))
def get_day(d):
    return Day(d)

The variable d is now interpreted as a date. Morepath uses whatever converter that was registered for that type.

List converters

What if you want to allow a list of parameters instead of just a single one? You can do this by wrapping the converter or type in the converters dictionary in a list:

@App.path(model=Days, path='days', converters=dict(d=[date]))
def get_days(d):
    return Days(d)

Now the d parameter will be interpreted as a list. This means URLs like this are accepted:

/days?d=2014-01-01

/days?d=2014-01-01&d=2014-01-02

/days

For the first case, d is a list with one date item, in the second case, d has 2 items, and in the third case the list d is empty.

get_converters

Sometimes you only know what converters are available at run-time; this particularly relevant if you want to supply converters for the values in extra_parameters. You can supply the converters using the special get_converters parameter to @app.path:

def my_get_converters():
    return { 'something': int }

@App.path(path='search', model=SearchResults,
          get_converters=my_get_converters)
...

Now if there is a parameter (or extra parameter) called something, it is converted to an int.

You can combine converters and get_converters. If you use both, get_converters will override any converters also defined in the static converters. This can also be useful for dealing with URL parameters that are not valid Python names, such as @foo or foo[]; these can still be converted using get_converters.

Required

Sometimes you may want a URL parameter to be required: when the URL parameter is missing, it’s an error and a 400 Bad Request should be returned. You can do this by passing in a required argument to the model decorator:

@App.path(model=Record, path='records', required=['id'])
def get_record(id):
    return query_record(id)

Normally when the id URL parameter is missing, the None value is passed into get_record (if there is no default). But since we made id required, 400 Bad Request will be issued if id is missing now. required only has meaning for URL parameters; path variables are always present if the path matches at all.

Absorbing

In some special cases you may want a path to match all sub-paths, absorbing them. This can be useful if you are writing a server backend to a client side application that does routing on the client using the HTML 5 history API – the server needs to handle catch all subpaths in that case and send them back to the client, where they can be handled by the client-side router.

You can do this using the special absorb argument to the path decorator, like this:

class Model(object):
    def __init__(self, absorb):
        self.absorb = absorb

@App.path(model=Model, path='start', absorb=True)
def get_foo(absorb):
    return Model(absorb)

As you can see, if you use absorb then a special absorb argument is passed into the model factory function.

Now the start path matches all of its sub-paths. So for this path:

/start/foo/bar/baz

model.absorb is foo/bar/baz.

It also matches if there is no sub-path:

/start

model.absorb is the empty string ''.

Note that you cannot use view names with a path that absorbs; only a default view with the empty name. View names are absorbed along with the rest of the path.

Note also that you cannot define an explicit path under an absorbed path – this is ignored. This means that the following additional code has no effect:

@App.path(model=Foo, path='start/extra')

You can still generate a link to a model that is under an absorbed path – it uses the value of the absorb variable.

Proxy support

If you have a Morepath application that sits behind a trusted proxy that sets the Forwarded header, then you want links generated by Morepath take this header into account. To do this, you can make your project depend on the more.forwarded extension. After you have it installed, you can subclass your app from more.forwarded.ForwardedApp to make your app proxy-aware. Note that you only need to do this for the root app, not for any apps mounted into it.

You should only use this extension if you know you are behind a trusted proxy that indeed sets the Forwarded header. This because otherwise you could expose your application to attacks that affect link generation through the Forwarded header.

Views

Introduction

Morepath views are looked up through the URL path, but not through the routing procedure. Routing stops at models. Then the last segment of the path is taken to identify the view by name.

Named views

Let’s examine a path:

/documents/1/edit

If there’s a model like this:

@App.path(model=Document, path='/documents/{id}')
def get_document(id):
    return query_for_document(id)

then /edit identifies a view named edit on the Document model (or on one of its base classes). Here’s how we define it:

@App.view(model=Document, name='edit')
def document_edit(self, request):
    return "edit view on model: %s" % self.id

Default views

Let’s examine this path:

/documents/1

If the model is published on the path /documents/{id}, then this is a path to the default view of the model. Here’s how that view is defined:

@App.view(model=Document)
def document_default(self, request):
    return "default view on model: %s" % self.id

The default view is the view that gets triggered if there is no special path segment in the URL that indicates a specific view. The default view has as its name the empty string "", so this registration is the equivalent of the one above:

@App.view(model=Document, name="")
def document_default(self, request):
    return "default view on model: %s" % self.id

Generic views

Generic views in Morepath are nothing special: the thing that makes them generic is that their model is a base class, and inheritance does the rest. Let’s see how that works.

What if we want to have a view that works for any model that implements a certain API? Let’s imagine we have a Collection model:

class Collection(object):
   def __init__(self, offset, limit):
       self.offset = offset
       self.limit = limit

   def query(self):
       raise NotImplementedError

A Collection represents a collection of objects, which can be ordered somehow. We restrict the objects we actually get by offset and limit. With offset 100 and limit 10, we get objects 100 through 109.

Collection is a base class, so we don’t actually implement how to do a query. That’s up to the subclasses. We do specify that query is supposed to return objects that have an id attribute.

We can create a view to this abstract collection that displays the ids of the things in it in a comma separated list:

@App.view(model=Collection)
def collection_default(self, request):
    return ", ".join([str(item.id) for item in self.query()])

This view is generic: it works for any kind of collection.

We can now create a concrete collection that fulfills the requirements:

class Item(object):
   def __init__(self, id):
       self.id = id

class MyCollection(Collection):
   def query(self):
       return [Item(str(i)) for i in
               range(self.offset, self.offset + self.limit)

When we now publish the concrete MyCollection on some URL:

@App.path(model=MyCollection, path='my_collection')
def get_my_collection():
    return MyCollection()

it automatically gains a default view for it that represents the ids in it as a comma separated list. So the view collection_default is generic.

Details

The decorator morepath.App.view() (@App.view) takes two arguments here, model, which is the class of the model the view is representing, and name, which is the name of the view in the URL path.

The @App.view decorator decorates a function that takes two arguments: a self and a request.

The self object is the model that’s being viewed, i.e. the one found by the get_document function. It is going to be an instance of the class given by the model parameter.

The request object is an instance of morepath.Request, which in turn is a special kind of webob.request.BaseRequest. You can get request information from it like arguments or form data, and it also exposes a few special methods, such as morepath.Request.link().

The @App.path and @App.view decorators are associated by indirectly their model parameters: the view works for a given model path if the model parameter is the same, or if the view is associated with a base class of the model exposed by the @App.path decorator.

Ambiguity between path and view

Let’s examine these simple paths in an application:

/folder
/folder/{name}

/folder shows an overview of the items in it. /folder/{name} is a way to get to an individual item.

This means:

/folder/some_item

is a path if there is an item in the folder with the name some_item.

Now what if we also want to have a path that allows you to edit the folder? It’d be natural to spell it like this:

/folder/edit

i.e. there is a path /folder with a view edit.

But now we have a problem: how does Morepath know that edit is a view and not a named item in the folder? The answer is that it doesn’t. You cannot reach the view this way.

Instead we have to make it explicit in the path that we want a view with a + character:

/folder/+edit

Now Morepath won’t try to interpret +edit as a named item in the folder, but instead looks up the view.

Any view can be addressed not just by name but also by its name with a + prefix. To generate a link to a name with a + prefix you can use the prefix as well, so you can write:

request.link(my_folder, '+edit')

render

By default @App.view returns either a morepath.Response object or a string that gets turned into a response. The content-type of the response is not set. For a HTML response you want a view that sets the content-type to text/html. You can do this by passing a render parameter to the @App.view decorator:

@App.view(class=Document, render=morepath.render_html)
def document_default(self, request):
    return "<p>Some html</p>"

morepath.render_html() is a very simple function:

def render_html(content, request):
    response = morepath.Response(content)
    response.content_type = 'text/html'
    return response

You can define your own render functions; they just need to take some content (any object, in this case its a string), and return a Response object.

Another render function is morepath.render_json(). Here it is:

import json

def render_json(content, request):
    response = morepath.Response(json.dumps(content))
    response.content_type = 'application/json'
    return response

We’d use it like this:

@App.view(class=Document, render=morepath.render_json)
def document_default(self, request):
    return {'my': 'json'}

HTML views and JSON views are so common we have special shortcut decorators:

Here’s how you use them:

@App.html(class=Document)
def document_default(self, request):
    return "<p>Some html</p>"

@App.json(class=Document)
def document_default(self, request):
    return {'my': 'json'}

Templates

You can use a server template with a view by using the template argument:

@App.html(model=Document, template='document.pt')
def document_default(self, request):
    return { 'title': self.title, 'content': self.content }

See Templates for more information.

Permissions

We can protect a view using a permission. A permission is any Python class:

class Edit(object):
    pass

The class doesn’t do anything; it’s just a marker for permission.

You can use such a class with a view:

@App.view(model=Document, name='edit', permission=Edit)
def document_edit(self, request):
    return 'edit document'

You can define which users have what permission on which models by using the morepath.App.permission_rule() decorator. To learn more, read Security.

Manipulating the response

Sometimes you want to do things to the response specific to the view, so that you cannot do it in a render function. Let’s say you want to add a cookie using webob.Response.set_cookie(). You don’t have access to the response object in the view, as it has not been created yet. It is only created after the view has returned. We can register a callback function to be called after the view is done and the response is ready using the morepath.Request.after() decorator. Here’s how:

@App.view(model=Document)
def document_default(self, request):
    @request.after
    def manipulate_response(response):
        response.set_cookie('my_cookie', 'cookie_data')
    return "document default"

after only applies if the view was successfully resolved into a response. If your view raises an exception for any reason, or if Morepath itself does, any after set in the view does not apply to the response for this exception. If the view returns a response object directly itself, then after is also not run - you have the response object to manipulate directly. Note that this the case when you use morepath.redirect(): this returns a redirect response object.

request_method

By default, a view only answers to a GET request: it doesn’t handle other request methods like POST or PUT or DELETE. To write a view that handles another request method you need to be explicit and pass in the request_method parameter:

@App.view(model=Document, name='edit', request_method='POST')
def document_edit(self, request):
    return "edit view on model: %s" % self.id

Now we have a view that handles POST. Normally you cannot have multiple views for the same document with the same name: the Morepath configuration engine rejects that. But you can if you make sure they each have a different request method:

@App.view(model=Document, name='edit', request_method='GET')
def document_edit_get(self, request):
    return "get edit view on model: %s" % self.id

@App.view(model=Document, name='edit', request_method='POST')
def document_edit_post(self, request):
    return "post edit view on model: %s" % self.id

Grouping views

At some point you may have a lot of view decorators that share a lot of information; multiple views for the same model are the most common example.

Instead of writing this:

@App.view(model=Document)
def document_default(self, request):
    return "default"

@App.view(model=Document, name='edit')
def document_edit(self, request):
    return "edit"

You can use the with statement to write this instead:

with App.view(model=Document) as view:
   @view()
   def document_default(self, request):
       return "default"

   @view(name="edit")
   def document_edit(self, request):
       return "edit"

This is equivalent to the above, you just don’t have to repeat model=Document. You can use this for any parameter for @App.view.

This use of the with statement is in fact general; it can be used like this with any Morepath directive, and with any parameter for such a directive. The with statement may even be nested, though we recommend being careful with that, as it introduces a lot of indentation.

Predicates

The model, name, request_method and body_model arguments on the @App.view decorator are examples of view predicates. You can add new ones by using the morepath.App.predicate() decorator.

Let’s say we have a view that we only want to kick in when a certain request header is set to something:

import reg

@App.predicate(generic.view, name='something', default=None,
               index=reg.KeyIndex,
               after=morepath.LAST_VIEW_PREDICATE)
def something_predicate(request):
    return request.headers.get('Something')

We can use any information in the request and model to construct the predicate. Now you can use it to make a view that only kicks in when the Something` header is special:

@App.view(model=Document, something='special')
def document_default(self, request):
    return "Only if request header Something is set to special."

If you have a predicate and you don’t use it in a @App.view, or set it to None, the view works for the default value for that predicate. The default parameter is also used when rendering a view using morepath.Request.view() and you don’t pass in a particular value for that predicate.

Let’s look into the predicate directive in a bit more detail.

You can use either self or request as the argument for the predicate function. Morepath sees this argument and sends in either the object instance or the request.

We use reg.KeyIndex as the index for this predicate. You can also have predicate functions that return a Python class. In that case you should use reg.ClassIndex.

morepath.LAST_VIEW_PREDICATE is the last predicate defined by Morepath itself. Here we want to insert the something_predicate after this predicate in the predicate evaluation order.

The after parameter for the predicate determines which predicates match more strongly than another; a predicate after another one matches more weakly. If there are two view candidates that both match the predicates, the strongest match is picked.

request.view

It is often useful to be able to compose a view from other views. Let’s look at our earlier Collection example again. What if we wanted a generic view for our collection that included the views for its content? This is easiest demonstrated using a JSON view:

@App.json(model=Collection)
def collection_default(self, request):
    return [request.view(item) for item in self.query()]

Here we have a view that for all items returned by query includes its view in the resulting list. Since this view is generic, we cannot refer to a specific view function here; we just want to use the view function appropriate to whatever item may be. For this we can use morepath.Request.view().

We could for instance have a particular item with a view like this:

@App.json(model=ParticularItem)
def particular_item_default(self, request):
    return {'id': self.id}

And then the result of collection_default is something like:

[{'id': 1}, {'id': 2}]

but if we have a some other item with a view like this:

@App.json(model=SomeOtherItem)
def some_other_item_default(self, request):
    return self.name

where the name is some string like alpha or beta, then the output of collection_default is something like:

['alpha', 'beta']

So request.view can make it much easier to construct composed JSON results where JSON representations are only loosely coupled.

You can also use predicates in request.view. Here we get the view with the name "edit" and the request_method "POST":

request.view(item, name="edit", request_method="POST")

You can also create views that are for internal use only. You can use them with request.view() but they won’t show up to the web; going to such a view is a 404 error. You can do this by passing the internal flag to the directive:

@App.json(model=SomeOtherItem, name='extra', internal=True)
def some_other_item_extra(self, request):
    return self.name

The extra view can be used with request.view(item, name='extra'), but it is not available on the web – there is no /extra view.

Exception views

Sometimes your application raises an exception. This can either be a HTTP exception, for instance when the user goes to a URL that does not exist, or an arbitrary exception raised by the application.

HTTP exceptions are by default rendered in the standard WebOb way, which includes some text to describe Not Found, etc. Other exceptions are normally caught by the web server and result in a HTTP 500 error (internal server error).

You may instead want to customize what these exceptions look like. You can do so by declaring a view using the exception class as the model. Here’s how you make a custom 404 Not Found:

from webob.exc import HTTPNotFound

@App.view(model=HTTPNotFound)
def notfound_custom(self, request):
    def set_status_code(response):
        response.status_code = self.code # pass along 404
    request.after(set_status_code)
    return "My custom not found!"

We have to add the set_status_code to make sure the response is still a 404; otherwise we change the 404 to a 200 Ok! This shows that self is indeed an instance of HTTPNotFound and we can access its code attribute.

Your application may also define its own custom exceptions that have a meaning particular to the application. You can create custom views for those as well:

class MyException(Exception):
    pass

@App.view(model=MyException)
def myexception_default(self, request):
     return "My exception"

Without an exception view for MyException any view code that raises MyException would bubble all the way up to the WSGI server and a 500 Internal Server Error is generated.

But with the view for MyException in place, whenever MyException is raised you get the special view instead.

Templates

Introduction

When you generate HTML from the server (using HTML views) it can be very handy to have a template language available. A template language provides some high-level constructs for generating HTML, which are handy. It can also help you avoid HTML injection security bugs because it takes care of escaping HTML. It may also be useful to separate HTML presentation from code.

This document discusses template rendering on the server. In some modern web applications template rendering is done in the browser instead of on the server. To do client-side template rendering you need to use a Client web framework with Morepath. See also Static resources with Morepath.

Morepath does not have a template language built in. The example in this document uses more.chameleon. more.chameleon integrates the Chameleon template engine, which implements the ZPT template language. If you prefer Jinja2, you can use the more.jinja2 extension instead. You can also integrate other template languages.

To use a template you need to use the template argument with the morepath.App.html() view directive.

Example

This example presupposes that more.chameleon and its dependencies have been installed. Here is how we use it:

from more.chameleon import ChameleonApp

class App(ChameleonApp):
    pass

@App.template_directory()
def get_template_directory():
    return 'templates'

@App.html(model=Person, template='person.pt')
def person_default(self, request):
    return { 'name': self.name }

Let’s examine this code. First we import ChameleonApp and subclass from it in our own app. This enables Chameleon templating for the .pt file extension.

We then need to specify the directory that contains our templates using the morepath.App.template_directory() directive. The directive should return either an absolute or a relative path to this template directory. If a relative path is returned, it is automatically made relative to the directory the Python module is in.

Next we use template='person.pt' in the HTML view directive. person.pt is a file sitting in the templates directory, with this content:

<html>
<body>
  <p>Hello ${name}!</p>
</body>
</html>

Once we have this set up, given a person with a name attribute of "world", the output of the view is the following HTML:

<html>
<body>
  <p>Hello world!</p>
</body>
</html>

The template is applied on the return value of the view function and the request. This results in a rendered template that is returned as the response.

Overrides

When you subclass an app you may want to override some of the templates it uses, or add new templates. You can do this by using the template_directory directive in your subclassed app:

class SubApp(App):
    pass

@SubApp.template_directory()
def get_override_template_directory():
   return 'templates_override'

Morepath’s template integration searches for templates in the template directories in application order, so for SubApp here, first templates_override, and then templates as defined by the base App. So for SubApp, you can override a template defined in the directory templates by placing a file with the same name in the directory templates_override. This only affects SubApp, not App itself.

You can also use the before argument with the morepath.App.template_directory() directive to specify more exactly how you want template directories to be searched. This can be useful if you want to organize your templates in multiple directories in the same application. If get_override_template_directory should come before get_template_directory in the directory search path, you should use before=get_template_directory:

@SubApp.template_directory(before=get_template_directory)
def get_override_template_directory():
   return 'templates_override'

but it is usually simpler not to be this explicit and to rely on application inheritance instead.

Details

Templates are loaded during configuration time at startup. The file extension of the extension (such as .pt) indicates the template engine to use.

Morepath itself does not support any template language out of the box, but lets you register a template language engine for a file extension. You can reuse a template language integration in the same way you reuse any Morepath code: by subclassing the app class that implements it in your app.

The template language integration works like this:

  • During startup time, person.pt is loaded from the configured template directories as a template object.
  • When the person_default view is rendered, its return value is passed into the template, along with the request. The template language integration code then makes this information available for use by the template – the details are up to the integration (and should be documented there).

The template argument works not just with html but also with view, json, and any other view functions you may have. It’s most useful for html views however.

Integrating a new template engine

A template in Morepath is actually just a convenient way to generate a render function for a view. That render function is then used just like when you write it manually: it’s given the return value of the view function along with a request object, and should return a WebOb response.

Here is an example of how you can integrate the Chameleon template engine for .pt files (taken from more.chameleon):

import chameleon

@App.template_loader(extension='.pt')
def get_template_loader(template_directories, settings):
    settings = settings.chameleon.__dict__.copy()
    # we control the search_path entirely by what we pass here as
    # template_directories, so we never want the template itself
    # to prepend its own path
    settings['prepend_relative_search_path'] = False
    return chameleon.PageTemplateLoader(
        template_directories,
        default_extension='.pt',
        **settings)

@App.template_render(extension='.pt')
def get_chameleon_render(loader, name, original_render):
    template = loader.load(name)

    def render(content, request):
        variables = {'request': request}
        variables.update(content)
        return original_render(template.render(**variables), request)
    return render

@App.setting_section(section='chameleon')
def get_setting_section():
    return {'auto_reload': False}

Some details:

  • extension is the file extension. When you refer to a template with a particular extension, this template engine is used.

  • The function decorated by morepath.App.template_loader() gets two arguments: directories to look in for templates (earliest in the list first), and Morepath settings from which template engine settings can be extracted.

  • The function decorated by morepath.App.template_render() gets three arguments:

    • loader: the loader constructed by the template_loader directive.
    • name: the name of the template to create a render function for.
    • The original_render function as passed into the view decorator, so render_html for instance. It takes the content to render and the request and returns a webob response object. then passed along to Chameleon.

    The decorated function needs to return a render function which takes the content to render (output from view function) and the request as arguments.

    The implementation of this can use the original render function which is passed in as an argument as original_render function. It can also create a morepath.Response object directly.

JSON and objects

Introduction

Morepath lets you define a JSON representations for arbitrary Python objects. When you return such an object from a json view, the object is automatically converted to JSON. When JSON comes in as the POST or PUT body of the request, this JSON can be automatically converted to a Python object. This system allows you to write views in terms of Python objects instead of JSON.

dump_json

The morepath.App.dump_json() directive lets you define a function that turns a model of a particular class into JSON. Here we define it for an Item class:

class Item(object):
   def __init__(self, value):
       self.value = value

@App.dump_json(model=Item)
def dump_item_json(self, request):
    return { 'type': 'Item', 'x': self.value }

So for instance, Item('foo') is represented in JSON as:

{
  'type': 'Item',
  'x': 'foo'
}

If we omit the model argument from the directive, we define a general dump_json function that applies to all objects.

Now we can write a JSON view that just returns an Item instance:

@App.json(model=Item)
def item_default(self, request):
    return self

The self we return in this view is an istance of Item. This is now automatically converted to a JSON object.

load_json

The App.load_json() directive lets you define a function that turns incoming JSON into a Python object. We detect JSON with the type field Item and interpret it as an Item instance, and pass through everything else:

@App.load_json()
def load_json(json, request):
    if json.get('type') != 'Item':
        return json
    return Item(json['x'])

When you write a json view you automatically get the Item instance as the body_obj attribute of the request:

@App.json(model=Collection, request_method='POST')
def collection_post(self, request):
    collection.add(request.body_obj)
    return "success!"

Security

Introduction

The security infrastructure in Morepath helps you make sure that web resources published by your application are only accessible by those persons that are allowed to do so. If a person is not allowed access, they will get an appropriate HTTP error: HTTP Forbidden 403.

Identity

Before we can determine who is allowed to do what, we need to be able to identify who people are in the first place.

The identity policy in Morepath takes a HTTP request and establishes a claimed identity for it. For basic authentication for instance it will extract the username and password. The claimed identity can be accessed by looking at the morepath.Request.identity attribute on the request object.

You use the morepath.App.identity_policy() directive to install an identity policy into a Morepath app:

from morepath.security import BasicAuthIdentityPolicy

@App.identity_policy()
def get_identity_policy():
    return BasicAuthIdentityPolicy()

If you want to create your own identity policy, see the morepath.security.IdentityPolicy API documentation to see what methods you need to implement.

Verify identity

The identity policy only establishes who someone is claimed to be. It doesn’t verify whether that person is actually who they say they are. For identity policies where the browser repeatedly sends the username/password combination to the server, such as with basic authentication and cookie-based authentication, we need to check each time whether the claimed identity is actually a real identity.

By default, Morepath will reject any claimed identities. To let your application verify identities, you need to use morepath.App.verify_identity():

@App.verify_identity()
def verify_identity(identity):
    return user_has_password(identity.username, identity.password)

The identity object received here is as established by the identity policy. What the attributes of the identity object are (besides username) is also determined by the specific identity policy you install.

Note that user_has_password stands in for whatever method you use to check a user’s password; it’s not part of Morepath.

Session or ticket identity verification

If you use an identity policy based on the session (which you’ve made secure otherwise), or on a cryptographic ticket based authentication system such as the one implemented by mod_auth_tkt, the claimed identity is actually enough.

We know that the claimed identity is actually the one given to the user earlier when they logged in. No database-based identity check is required to establish that this is a legitimate identity. You can therefore implement verify_identity like this:

@App.verify_identity()
def verify_identity(identity):
    # trust the identity established by the identity policy
    return True

Login and logout

So now we know how identity gets established, and how it can be verified. We haven’t discussed yet how a user actually logs in to establish an identity in the first place.

For this, we need two things:

  • Some kind of login form. Could be taken care of by client-side code or by a server-side view. We leave this as an exercise for the reader.
  • The view that the login data is submitted to when the user tries to log in.

How this works in detail is up to your application. What’s common to login systems is the action we take when the user logs in, and the action we take when the user logs in. When the user logs in we need to remember their identity on the response, and when the user logs in we need to forget their identity again.

Here is a sketch of how logging in works. Imagine we’re in a Morepath view where we’ve already retrieved username and password from the request (coming from a login form):

# check whether user has password, using password hash and database
if not user_has_password(username, password):
    return "Sorry, login failed" # or something more fancy

# now that we've established the user, remember it on the response
@request.after
def remember(response):
    identity = morepath.Identity(username)
    morepath.remember_identity(response, request, identity)

This is enough for session-based or cryptographic ticket-based authentication.

For cookie-based authentication where the password is sent as a cookie to the server for each request, we need to make sure include the password the user used to log in, so that remember can then place it in the cookie so that it can be sent back to the server:

@request.after
def remember(response):
    identity = morepath.Identity(username, password=password)
    morepath.remember_identity(response, request, identity)

When you construct the identity using morepath.security.Identity, you can any data you want in the identity object by using keyword parameters.

Logging out

Logging out is easy to implement and will work for any kind of authentication except for basic auth (see later). You simply call morepath.forget_identity somewhere in the logout view:

@request.after
def forget(response):
    morepath.forget_identity(response, request)

This will cause the login information (in cookie-form) to be removed from the response.

Basic authentication

Basic authentication is special in a number of ways:

  • The HTTP response status that triggers basic auth is Unauthorized (401), not the default Forbidden (403). This needs to be sent back to the browser each time login fails, so that the browser asks the user for a username and a password.
  • The username and password combination is sent to the server by the browser automatically; there is no need to set some type of cookie on the response. Therefore remember_identity does nothing.
  • With basic auth, there is no universal way for a web application to trigger a log out. Therefore forget_identity does nothing either.

To trigger a 401 status when time Morepath raises a 403 status, we can use an exception view, something like this:

from webob.exc import HTTPForbidden

@App.view(model=HTTPForbidden)
def make_unauthorized(self, request):
    @request.after
    def set_status_code(response):
        response.status_code = 401
    return "Unauthorized"

The core of the login code can remain the same as remember_identity is a no-op, but you could reduce it to this:

# check whether user has password, using password hash and database
if not user_has_password(username, password):
    return "Sorry, login failed" # or something more fancy

Permissions

Now that we have a way to establish identity and a way for the user to log in, we can move on to permissions. Permissions are per view. You can define rules for your application that determine when a user has a permission.

Let’s say we want two permissions in our application, view and edit. We define those as plain Python classes:

class ViewPermission(object):
    pass

class EditPermission(object):
    pass

Now we can protect views with those permissions. Let’s say we have a Document model that we can view and edit:

@App.html(model=Document, permission=ViewPermission)
def document_view(request, model):
    return "<p>The title is: %s</p>" % model.title

@App.html(model=Document, name='edit', permission=EditPermission)
def document_edit(request, model):
    return "some kind of edit form"

This says:

  • Only allow access to document_view if the identity has ViewPermission on the Document model.
  • Only allow allow access to document_edit if the identity has EditPermission on the Document model.

Permission rules

Now that we give people a claimed identity and we have guarded our views with permissions, we need to establish who has what permissions where using some rules. We can use the morepath.App.permission_rule() directive to do that.

This is very flexible. Let’s look at some examples.

Let’s give absolutely everybody view permission on Document:

@App.permission_rule(model=Document, permission=ViewPermission)
def document_view_permission(identity, model, permission)
    return True

Let’s give only those users that are in a list allowed_users on the Document the edit permission:

@App.permission_rule(model=Document, permission=EditPermission)
def document_edit_permission(identity, model, permission):
    return identity.userid in model.allowed_users

This is just is one hypothetical rule. allowed_users on Document objects is totally made up and not part of Morepath. Your application can have any rule at all, using any data, to determine whether someone has a permission.

Morepath Super Powers Go!

What if we don’t want to have to define permissions on a per-model basis? In our application, we may have a generic way to check for the edit permission on any kind of model. We can easily do that too, as Morepath knows about inheritance:

@App.permission_rule(model=object, permission=EditPermission)
def has_edit_permission(identity, model, permission):
    ... some generic rule ...

This permission function is registered for model object, so will be valid for all models in our application.

What if we want that policy for all models, except Document where we want to do something else? We can do that too:

@App.permission_rule(model=Document, permission=EditPermission)
def document_edit_permission(identity, model, permission):
    ... some special rule ...

You can also register special rules that depend on identity. If you pass identity=None, you can can register a permission policy for when the user has not logged in yet and has no claimed identity:

@App.permission_rule(model=object, permission=EditPermission, identity=None)
def has_edit_permission_not_logged_in(identity, model, permission):
    return False

This permission check works in addition to the ones we specified above.

If you want to defer to a completely generic permission engine, you could define a permission check that works for any permission:

@App.permission_rule(model=object, permission=object)
def generic_permission_check(identity, model, permission):
     ... generic rule ...

REST

Introduction

In this section we’ll look at how you could go about implementing a RESTful web service with Morepath.

REST stands for Representational State Transfer, and is a particular way to design web services. We won’t try to explain here why this can be a good thing for you to do, just explain what is involved.

REST is not only useful for pure web services, but is also highly relevant for web application development, especially when you are building a single-page rich client application in JavaScript in the web browser. It can be beneficial to organize the server-side application as a RESTful web service.

Elements of REST

That’s all rather abstract. Let’s get more concrete. It’s useful to refer to the Richardson Maturity Model for REST in this context. In REST we do the following:

  • We uses HTTP as a transport system. What you use to communicate is typically JSON or XML, but it could be anything.
  • We don’t just use HTTP to tunnel method calls to a single URL. Instead, we model our web service as resources, each with their own URL, that we can interact with.
  • We use HTTP methods meaningfully. Most importantly we use GET to retrieve information, and POST when we want to change information. Along with this we also use HTTP response status codes meaningfully.
  • We have links between the resources. So, one resource points to another. A container resource could point to a link that you can POST to create a new sub resource in it, for instance, and may have a list of links to the resources in the container. See also HATEOAS.

Morepath has features that help you create RESTful applications.

HTTP as a transport system

We don’t really need to say much here, as Morepath is of course all about HTTP in the end. Morepath lets you write a bare-bones view using morepath.App.view(). This also lets you pass in a render function that lets you specify how to render the return value of the view function as a morepath.Response. If you use JSON, for convenience you can use morepath.App.json() has a JSON render function baked in.

We could for instance have a Document model in our application:

class Document(object):
    def __init__(self, id, title, author, content):
        self.id = id
        self.title = title
        self.author = author
        self.content = content

We can expose it on a URL:

@App.path(model=Document, path='documents/{id}')
def get_document(id):
   return document_by_id(id)

We assume here that a document_by_id() function exists that returns a Document instance by id from some database, or None if the document cannot be found. Any way to get your model instance is fine.

Now we want a metadata resource that exposes its metadata as JSON:

@App.json(model=Document, name='metadata')
def document_metadata(self, request):
    return {
      'id': self.id,
      'title': self.title,
      'author': self.author
    }

Modeling as resources

Modeling a web service as multiple resources comes pretty naturally to Morepath, as it’s model-oriented in the first place. You can think carefully about how to place models in the URL space and expose them using morepath.App.path(). In Morepath each model class can only be exposed on a single URL (per app), which gives them a canonical URL automatically.

A collection resource could be modelled like this:

class DocumentCollection(object):
    def __init__(self):
        self.documents = []

    def add(self, doc):
        self.documents.append(doc)

We now want to expose this collection to a URL path /documents. We want:

  • a resource /documents to GET the ids of all documents in the collection.
  • a resource /documents/add that lets you POST an id to it so that this document is added to the collection.

Here is how we could make documents available on a URL:

documents = DocumentCollection()

@App.path(model=DocumentCollection, path='documents')
def documents_collection():
   return documents

When someone accesses /documents they should get a JSON structure which includes ids of all documents in the collection. Here’s how to do that:

@App.json(model=DocumentCollection)
def collection_default(self, request):
    return {
       'type': 'document_collection',
       'ids': [doc.id for doc in self.documents]
    }

Then we want to allow people to POST the document id (as a URL parameter) to the /documents/add resource:

@App.json(model=DocumentCollection, name='add', request_method='POST')
def collection_add_document(self, request):
    doc = document_by_id(request.args['id'])
    self.add(doc)
    return {}

We again use the document_by_id function. We also return an empty JSON object in the response; not very useful, but in this simple view we don’t have anything more interesting to report when the POST succeeds.

Note the use of request_method, which we’ll talk about more next.

Note also that there are some things still missing: giving back a proper response with status codes, and error handling when things go wrong.

HTTP methods

As you saw above, we’ve used request_method to make sure that /documents/add only works for POST requests.

By default, request_method is GET, meaning that /documents only responds to a GET request, which is what we want. Let’s make it explicit:

@App.json(model=DocumentCollection, request_method='GET')
def collection_default(self, request):
    ...

What if we had defined our web service differently, and instead of having a /documents/add we wanted to allow the POSTing of document ids on /documents directly? Here’s how you rewrite collection_add_document to be the view directly on /documents`:

@App.json(model=DocumentCollection, request_method='POST')
def collection_add_document(self, request):
    ...

It’s just a matter of removing the name parameter so that it becomes the default view on DocumentCollection.

HTTP response status codes

When a view did its thing with success, Morepath automatically returns the HTTP status code 200. When you try to access a URL that cannot be routed to a model or a view, a 404 error is raised.

But what if the view did not manage to do something successfully? Let’s get back to this view:

@App.json(model=DocumentCollection, name='add', request_method='POST')
def collection_add_document(self, request):
    doc = document_by_id(request.args['id'])
    self.add(doc)
    return {}

What if there is no id parameter in the request? That’s something our application cannot handle: a bad request, status code 400.

WebOb, the request/response library upon which Morepath is built, defines a set of HTTP exception classes webob.exc that we can use. In this case we need webob.exc.HTTPBadRequest. We modify our view so it is raised if there was no id:

from webob.exc import HTTPBadRequest

@App.json(model=DocumentCollection, name='add', request_method='POST')
def collection_add_document(self, request):
    id = request.args.get('id')
    if id is None:
        raise HTTPBadRequest()
    doc = document_by_id(id)
    self.add(doc)
    return {}

We also want to deal with the situation where an id was given, but no document with that id exists. Let’s handle that with 400 Bad Request too:

@App.json(model=DocumentCollection, name='add', request_method='POST')
def collection_add_document(self, request):
    id = request.args.get('id')
    if id is None:
        raise BadRequest()
    doc = document_by_id(id)
    if doc is None:
        raise BadRequest()
    self.add(doc)
    return {}

Linking: HATEOAS

We’ve now reached the point where many would say that this is a RESTful web service. But in fact a vital ingredient is still missing: hyperlinks. That ugly acronym HATEOAS thing.

Morepath makes it very easy to create hyperlinks, so we won’t have to do much. Let’s first modify our default GET view for the collection so it also has a link to the add resource:

@App.json(model=DocumentCollection)
def collection_default(self, request):
    return {
       'type': 'document_collection',
       'ids': [doc.id for doc in self.documents],
       'add': request.link(documents, 'add')
    }

documents, if you can remember, is the instance of DocumentCollection we were working with, and we want to link to its add view.

Let’s make things more interesting though. Before we had the default view for the collection return a list of document ids. We can change this so we return a list of document URLs instead:

@App.json(model=DocumentCollection)
def collection_default(self, request):
    return {
       'type': 'document_collection',
       'documents': [request.link(doc) for doc in self.documents],
       'add': request.link(documents, 'add')
    }

Or perhaps better, include the id and the URL:

@App.json(model=DocumentCollection)
def collection_default(self, request):
    return {
       'type': 'document_collection',
       'documents': [dict(id=doc.id, link=request.link(doc))
                     for doc in self.documents],
       'add': request.link(documents, 'add')
    }

Now we’ve got HATEOAS: the collection links to the documents it contains, and also to the add URL that can be used to add a new document. The developers looking at the responses your web service sends get a few clues about where to go next. Coupling is looser.

We got HATEOAS, so at last we got true REST. Why is hyperlinking so often ignored? Why don’t more systems implement HATEOAS? Perhaps because they make linking to things too hard or too brittle. Morepath instead makes it easy. Link away!

Compose from reusable apps

If you’re going to create a larger RESTful web service, you should start thinking about composing them from smaller applications. See App Reuse for more information.

Settings

Introduction

A typical application has some settings: if an application logs, a setting is the path to the log file. If an aplication sends email, there are settings to control how email is sent, such as the email address of the sender.

Applications that serve as frameworks for other applications may have settings as well: the transaction_app defined by more.transaction for instance has settings controlling transactional behavior.

Morepath has a powerful settings system that lets you define what settings are available in your application and framework. It allows an app that extends another app to override settings. This lets an app that defines a framework can also define default settings that can be overridden by the extending application if needed.

Defining a setting

You can define a setting using the App.setting() directive:

@App.setting(section="logging", name="logfile")
def get_logfile():
    return "/path/to/logfile.log"

You can also use this directive to override a setting in another app:

class Sub(App):
    pass

@Sub.setting(section="logging", name="logfile")
def get_logfile_too():
   return "/a/different/logfile.log"

Settings are grouped logically: a setting is in a section and has a name. This way you can organize all settings that deal with logging under the logging section.

Accessing a setting

During runtime, you can access the settings of the current application using the morepath.settings() function, like this:

settings().logging.logfile

In a tween factory (see :doc:tweens) or a directive implementation, you can access a setting through the app object like this:

app.registry.settings.logging.logfile

Defining multiple settings

It can be convenient to define multiple settings in a section at once. You can do this using the App.setting_section() directive:

@App.setting_section(section="logging")
def get_setting_section():
    return {
       'logfile': "/path/to/logfile.log",
       'loglevel': logging.WARNING
    }

You can mix setting and setting_section freely, but you cannot define a setting multiple times in the same app, as this will result in a configuration conflict.

Organizing your Project

Introduction

Morepath does not put any requirements on how your Python code is organized. You can organize your Python project as you see fit and put app classes, paths, views, etc, anywhere you like. A single Python package (or even module) may define a single Morepath app, but could also define multiple apps. In this Morepath is like Python itself; the Python language does not restrict you in how you organize functions and classes.

While this leaves you free to organize your code as you see fit, that doesn’t mean that your code shouldn’t be organized. Here are some guidelines on how you may want to organize things in your own project. But remember: these are guidelines to break when you see the need.

Python project

It is recommended you organize your code in a Python project with a setup.py where you declare the dependency on Morepath. If you’re unfamiliar with how this works, you can check out this tutorial.

Doing this is good Python practice and makes it easy for you to install and distribute your project using common tools like pip, buildout and PyPI. In addition Morepath itself can also load its code more easily.

Project layout

Here’s a quick overview of the files and directories of Morepath project that follows the guidelines in this document:

myproject
    setup.py
    myproject
         __init__.py
        main.py
        model.py
        [collection.py]
        path.py
        view.py

Project setup

Here is an example of your project’s setup.py with only those things relevant to Morepath shown and everything else cut out:

from setuptools import setup, find_packages

setup(name='myproject',
      packages=find_packages(),
      install_requires=[
         'morepath'
      ],
      entry_points={
         'console_scripts': [
          'myproject-start = myproject.main:main'
          ]
      })

This setup.py assumes you also have a myproject subdirectory in your project directory that is a Python package, i.e. it contains an __init__.py. This is the directory where you put your code. The find_packages() call finds it for you.

The install_requires section declares the dependency on Morepath. Doing this makes everybody who installs your project automatically also pull in a release of Morepath and its own dependencies. In addition, it lets this package be found and configured when you use morepath.autosetup().

Finally there is an entry_points section that declares a console script (something you can run on the command-prompt of your operating system). When you install this project, a myproject-start script is automatically generated that you can use to start up the web server. It calls the main() function in the myproject.main module. Let’s create this next.

You now need to install this project. If you want to install this project for development purposes you can use python setup.py develop, or pip install -e . from within a virtualenv.

See also the setuptools documentation.

Project naming

Its possible to name your project differently than you name your Python package; you could for instance have the name ThisProject in setup.py, and then have your Python package be still called myproject. We recommend naming the project the same as the Python package to avoid confusion.

Namespace packages

Sometimes you have projects that are grouped in some way: they are all created by the same organization or they are part of the same larger project. In that case you can use Python namespace packages to make this relationship clear. Let’s say you have a larger project called myproject. The namespace package itself may not contain any code, so unlike the example everywhere else in this document the myproject directory is always empty but for a __init__.py.

Different sub-projects could then be called myproject.core, myproject.wiki, etc. Let’s examine the files and directories of myproject.core:

myproject.core
    setup.py
    myproject
        __init__.py
        core
            __init__.py
            main.py
            model.py
            [collection.py]
            path.py
            view.py

The change is the namespace package directory myproject that contains a single file, __init__.py, that contains the following code to declare it is a namespace package:

__import__('pkg_resources').declare_namespace(__name__)

Inside is the normal package called core.

setup.py is modified too to include a declaration in namespace_packages, and we’ve changed the entry point:

setup(name='myproject.core',
      packages=find_packages(),
      namespace_packages=['myproject'],
      install_requires=[
         'morepath'
      ],
      entry_points={
         'console_scripts': [
          'myproject.core-start = myproject.core.main:main'
          ]
      })

See also the namespace packages documentation.

Main Module

The main.py module is where we define our Morepath app and allow a way to start it up as a web server. Here’s a sketch of main.py:

import morepath

class App(morepath.App):
    pass

def main():
   morepath.autosetup()
   morepath.run(App())

We create an App class, then have a main() function that is going to be called by the myproject-start entry point we defined in setup.py. This main function does two things:

  • Use morepath.autosetup() to set up Morepath, including any of your code.
  • start a WSGI server for the App instance on port localhost, port 5000. This uses the standard library wsgiref WSGI server. Note that this should only used for testing purposes, not production! For production, use an external WSGI server.

The main module is also a good place to do other general configuration for the application, such as setting up a database connection.

Debugging scanning problems

If you for some reason get 404 Not Found errors where you expect some content, something may have gone wrong with scanning the configuration of your project. Here’s a checklist:

  • Check whether your project has a setup.py with an install_requires that depends morepath (possibly indirectly through another dependency). You need to declare your code as a project so that autosetup can find it.

  • Check whether your project is installed in a virtualenv using pip install -e . or in a buildout. Morepath needs to be able to find your project in order to scan it.

  • Be sure that you have your modules in an actual sub-directory to the project with its own __init__.py. Modules in the top-level of a project won’t be scanned as a package

  • Check whether manually scanning the individual modules or packages helps. Try writing this code in main instead of autosetup:

    from . import path, view
    
    config = morepath.config()
    config.scan()
    config.scan(path)
    config.scan(view)
    config.commit()
    

    Alternatively you can try moving your code into main.py and see whether it starts working.

    If this fixes things, then your Python package seems not to be properly installed as a Python package; only the main module get scanned properly. Morepath should be able to pick up everything in your package if only you organize it correctly.

Variation: automatic restart

During development it can be very helpful to have the WSGI server restart the Morepath app whenever a file is changed.

Morepath’s built in development server does not offer this feature, but you can accomplish it with Werkzeug’s server.

First install the Werkzeug package into your project. Then modify your main module to look like this:

import morepath
from werkzeug.serving import run_simple

class App(morepath.App):
    pass

def main():
    morepath.autosetup()
    run_simple('localhost', 8080, App(), use_reloader=True)

Using this runner changes to Python code in your package trigger a restart of the WSGI server.

Variation: no or multiple entry points

Not all packages have an entry point to start it up: a framework app that isn’t intended to be run directly may not define one. Some packages may define multiple apps and multiple entry points.

Variation: waitress

Instead of using Morepath’s simple built-in WSGI server you can use another WSGI server. The built-in WSGI server is only meant for testing, so we strongly recommend doing so in production. Here’s how you’d use Waitress. First we adjust setup.py so we also require waitress:

...
      install_requires=[
         'morepath',
         'waitress'
      ],
...

Then we modify main.py to use waitress:

import waitress

...

def main():
   ...
   waitress.serve(App())
Variation: command-line WSGI servers

You could also do away with the entry point and instead use waitress-serve on the command line directly. For this we need to first create a factory function that returns the fully configured WSGI app:

def wsgi_factory():
   morepath.autosetup()
   return App()

$ waitress-serve --call myproject.main:wsgi_factory

This uses waitress’s --call functionality to invoke a WSGI factory instead of a WSGI function. If you want to use a WSGI function directly we have to create one using the wsgi_factory function we just defined. To avoid circular dependencies you should do it in a separate module that is only used for this purpose, say wsgi.py:

prepared_app = wsgi_factory()

You can then do:

$ waitress-serve myproject.wsgi:prepared_app

You can also use gunicorn this way:

$ gunicorn -w 4 myproject.wsgi:prepared_app

Model module

The model.py module is where we define the models relevant to the web application. They may integrate with some kind of database system, for instance the SQLAlchemy ORM. Note that your model code is completely independent from Morepath and there is no reason to import anything Morepath related into this module. Here is an example model.py that just uses plain Python classes:

class Document(object):
    def __init__(self, id, title, content):
        self.id = id
        self.title = title
        self.content = content
Variation: models elsewhere

Sometimes you don’t want to include model definitions in the same codebase that also implements a web application, as you would like to reuse them outside of the web context without any dependencies on Morepath. Your model classes are independent from Morepath, so this is easy to do: just put them in a separate project and depend on it from your web project.

You can also have a project that reuses models defined by another Morepath project. Each Morepath app is isolated from the others by default, so you could remix its models into a whole new web application.

Variation: collection module

An application tends to contain two kinds of models:

  • content object models, i.e. a Document. If you use an ORM like SQLAlchemy these would typically be backed by a table.
  • collection models, i.e. a collection of documents. This typically let you browse content models, search/filter for them, and let you add or remove them.

Since collection models tend to not be backed by a database directly but are often application-specific classes, it can make sense to maintain them in a separate collection.py module. This module, like model.py also does not have any dependencies on Morepath.

Path module

Now that we have models, we need to publish them on the web. First we need to define their paths. We do this in a path.py module:

from .main import App
from . import model

@App.path(model=model.Document, path='documents/{id}')
def get_document(id):
   if id != 'foo':
      return None # not found
   return Document('foo', 'Foo document', 'FOO!')

In the functions decorated by App.path() we do whatever query is necessary to retrieve the model instance from a database, or return None if the model cannot be found.

Morepath allows you to scatter @App.path decorators throughout your codebase, but by putting them all together in a single module it becomes really easy to inspect and adjust the URL structure of your application, and to see exactly what is done to query or construct the model instances. Once it becomes really big you can always split a single path module into multiple ones, though at that point you may want to consider splitting off a separate project with its own application instead.

View module

We have models and they’re published on a path. Now we need to represent them as actual web resources. We do this in the view.py module:

from .main import App
from . import model

@App.json(model=model.Document)
def document_default(self, request):
    return {'id': self.id, 'title': self.title, 'content': self.content }

Here we use App.view(), App.json() and App.html() directives to declare views.

By putting them all in a view module it becomes easy to inspect and adjust how models are represented, but of course if this becomes large it’s easy to split it into multiple modules.

Directive debugging

Morepath’s directive issue log messages that can help you debug your application: see Logging for more information.

Logging

Directive logging

Morepath has support for logging directive execution. This can be helpful when debugging why your Morepath application does not do what was expected. Morepath’s directive logging makes use of Python’s logging module, which is very flexible.

To get the complete log of directive executions, you can set up the following code in your project:

directive_logger = logging.getLogger('morepath.directive')
directive_logger.addHandler(logging.StreamHandler())
directive_logger.setLevel(logging.DEBUG)

The StreamHandler logs messages to stderr. You can reconfigure this or use another handler altogether. You need to change the log level so that logging.DEBUG level messages are also shown, as Morepath’s directive logging uses this log level.

You can also configure it to just see the output for one particular directive. To see all path directive executed in your project you’d change the getLogger statement to this:

directive_logger = logging.getLogger('morepath.directive.path')

The Python logging module has many more options, but this should get you started.

App Reuse

Morepath is a microframework with a difference: it’s small and easy to learn like the others, but has special super powers under the hood.

One of those super powers is Reg, which along with Morepath’s model/view separation makes it easy to write reusable views. But here we’ll talk about another super power: Morepath’s application reuse facilities.

We’ll talk about how Morepath lets you isolate applications, extend and override applications, and compose applications together. Morepath tries to make these things not only possible, but simple.

Many other web frameworks have mechanisms for overriding behavior and reusing code. But these tend to have been developed in an ad-hoc fashion as new needs arose.

Morepath instead has general mechanisms for app extension and reuse. Any normal Morepath app can without extra effort be reused. Anything registered in a Morepath app can be overridden.

Application Isolation

Morepath lets you create app classes like this:

class App(morepath.App):
    pass

When you instantiate the app class, you get a WSGI application. The app class itself serves as a registry for application construction information. This configuration is specify used decorators. Apps consist of paths and views for models:

@App.path(model=User, path='users/{username}')
def get_user(username):
    return query_for_user(username)

@App.view(model=User)
def render_user(self, request):
    return "User: %s" % self.username

Here we’ve exposed the User model class under the path /users/{username}. When you go to such a URL, the default (unnamed) view is found. We’ve provided that too: it just renders “User: {username}”.

What now if we have another app where we want to publish User in a different way? No problem, we can just create one:

class OtherApp(morepath.App):
    pass

@OtherApp.path(model=User, path='different_path/{username}')
def get_user(username):
    return different_query_for_user(username)

@OtherApp.view(model=User)
def render_user(self, request):
    return "Differently Displayed User: %s" % self.username

Here we expose User to the web again, but use a different path and a different view. If you use OtherApp (even in the same runtime), it functions independently from App.

This app isolation is nothing really special; it’s kind of obvious that this is possible. But that’s what we wanted. Let’s look at a few more involved possibilities next.

Application Extension

Let’s look at our first application App again. It exposes a single view for users (the default view). What now if we want to add a new functionality to this application so that we can edit users as well?

This is simple; we can add a new edit view to App:

@App.view(model=User, name='edit')
def edit_user(self, request):
    return 'Edit user: %s' % self.username

The string we return here is of course useless for a real edit view, but you get the idea.

But what if we have a scenario where there is a core application and we want to extend it without modifying it?

Why would this ever happen, you may ask? Well, it can, especially in more complex applications and reuse scenarios. Often you have a common application core and you want to be able to plug into it. Meanwhile, you want that core application to still function as before when used (or tested!) by itself. Perhaps there’s somebody else who has created another extension of it.

This architectural principle is called the Open/Closed Principle in software engineering, and Morepath makes it really easy to follow it. What you do is create another app that subclasses the original:

class ExtendedApp(App):
    pass

And then we can add the view to the extended app:

@ExtendedApp.view(model=User, name='edit')
def edit_user(self, request):
    return 'Edit user: %s' % self.username

Now when we publish ExtendedApp using WSGI, the new edit view is there, but when we publish App it won’t be.

Just subclassing. Kind of obvious, perhaps. Good. Let’s move on.

Application Overrides

Now we get to a more exciting example: overriding applications. What if instead of adding an extension to a core application you want to override part of it? For instance, what if we want to change the default view for User?

Here’s how we can do that:

@ExtendedApp.view(model=User)
def render_user_differently(self, request):
    return 'Different view for user: %s' % self.username

We’ve now overridden the default view for User to a new view that renders it differently.

You can also do this for what is returned for model paths. We might for instance want to return a different user object altogether in our overriding app:

@ExtendedApp.path(model=OtherUser, path='users/{username}')
def get_user_differently(username):
    return OtherUser(username)

To make OtherUser actually be published on the web under /users/{username} it either needs to be a subclass of User, for which we’ve already registered a default view, or we need to register a new default view for OtherUser.

Overriding apps actually doesn’t look much different from how you build apps in the first place. Again, it’s just like subclassing. Hopefully not so obvious that it’s boring. Let’s talk about something new.

Nesting Applications

Let’s talk about application composition: nesting one app in another.

Imagine our user app allows users to have a wiki associated with them. It has paths like /users/faassen/wiki/my_wiki_page and /users/bob/wiki/page_on_things.

We could implement this directly in the user app along these lines:

def wiki_for_user(username):
    wiki_id = get_wiki_id_for_username(username)
    return get_wiki(wiki_id)

@App.path(model=WikiPage, path='users/{username}/wiki/{page_id}')
def get_wiki_page(username, page_id):
    return wiki_for_user(username).get_page(page_id)

@App.view(model=WikiPage)
def wiki_page_default(self, request):
    return "Wiki Page"

To understand this app, we need to describe a hypothetical Wiki class first. We can get an instance of it from some database by using get_wiki with a wiki id. It has a get_page method for getting access to wiki page objects (class WikiPage). We also have a way to determine the wiki id for a given username, get_wiki_id_for_username.

This application makes available wiki pages on a sub-URL for users, and then supplies a default view for them so we see something when we go to the page.

There are some issues with this implementation, though:

  • Why would we implement a wiki as part of our user app? Our wiki application should really be an app by itself, that we can use by itself and also test by itself.
  • The username appears in the path for the WikiPage model. The same would apply to any other wiki related models (like the wiki root). Why should we have to care about the username of a user when we expose a wiki page?
  • Related to this, what if we wanted to associate a wiki app with some other object such as a project, instead of a user? It would be nice if we can use the wiki app in such other contexts as well, not just for users.

To deal with those issues, we can create a separate app for wikis that is only about wikis. So let’s do it. Here’s the wiki app by itself:

class WikiApp(morepath.App):
    def __init__(self, wiki_id):
        self.wiki_id = wiki_id

@wiki_app.path(path='{page_id}', model=WikiPage)
def get_wiki(page_id, app):
    return get_wiki(app.wiki_id).get_page(page_id)

@App.view(model=WikiPage)
def wiki_page_default(self, request):
    return "Wiki Page"

Here we have a stand-alone wiki app. It needs a wiki_id to be instantiated:

app = WikiApp(3)

We could now use app as a WSGI application, but that only works for one wiki id at the time. What if we want to associate the wiki with a user like we had before? We can accomplish this by mounting the wiki app into the user app, like this:

def variables(app):
    return dict(username=get_username_for_wiki_id(app.wiki_id))

@App.mount(app=WikiApp, path='users/{username}/wiki',
           variables=variables)
def mount_wiki(username):
    return WikiApp(get_wiki_id_for_username(username))

Note that in order to be able to link to WikiApp we need to supply a special variables function that takes the wiki app and returns the username for it. For more details, see the documentation for the morepath.App.mount() directive.

Linking to other mounted apps

Now that we have applications mounted into each other, we want a way to make links between them.

It is easy to make a link to an object in the same application. We use morepath.Request.link():

wiki_page = get_wiki(3).get_page('my_page')

request.link(wiki_page)

This works to create links to wiki pages from within the wiki app. But what if we want to link to a wiki page from outside the wiki app, for instance from the user app?

To do this, we need not only the wiki page, but also a reference to the specific mounted application the wiki page is in. We can get this by navigating to it from the user app.

If we are in the user application, we can navigate to the mounted wiki app using the morepath.App.child() method:

wiki_app = request.app.child(WikiApp(3))

What if we want to navigate with the username under which it was mounted instead? We can do this too. We give child the WikiApp class and then the username as a keyword argument:

wiki_app = request.app.child(WikiApp, username='faassen')

There is one more alternative. We can also refer to WikiApp with the name under which it was mounted (the path by default):

wiki_app = request.app.child('users/{username}/wiki', username='faassen')

We can now use wiki_app to make the link from the username app to a wiki page in the wiki app:

request.link(wiki_page, app=wiki_app)

What if we wanted to create a link from the wiki app into the user app in which it was mounted? We get to the user app from the wiki app with morepath.App.parent:

request.link(User('faassen'), app=request.app.parent)

For a quick navigation to a sibling app, there is also morepath.App.sibling(). To quickly get to the root app, use morepath.App.root. You can also combine parent and child together to navigate the application tree.

Further reading

To see an extended example of how you can structure larger applications to support reuse, see Building Large Applications.

Building Large Applications

Introduction

A small web application is relatively easy to understand. It does less stuff. That makes the application easier to understand: the UI (or REST web service) is smaller, and the codebase too.

But sometimes we need larger web applications. Morepath offers a number of facilities to help you manage the complexity of larger web applications:

  • Morepath lets you build larger applications from multiple smaller ones. A CMS may for instance be composed of a document management application and a user management application. This is much like how you manage complexity in a codebase by decomposing it into smaller functions and classes.
  • Morepath lets you factor out common, reusable functionality. In other words, Morepath helps you build frameworks, not just end-user applications. For instance, you may have multiple places in an application where you need to represent a large result-set in smaller batches (with previous/next), and they should share common code.

There is also the case of reusable applications. Larger applications are often deployed multiple times. An open source CMS is a good example: different organizations each have their own installation. Or imagine a company with an application that it sells to its customers: each customer can have its own special deployment.

Different deployments of an application have real differences as every organization has different requirements. This means that you need to be able to customize and extend the application to fit the purposes of each particular deployment. As a result the application has to take on framework-like properties. Morepath recognizes that there is a large gray area between application and framework, and offers support to build framework-like applications and application-like frameworks.

The document doc:app_reuse describes the basic facilities Morepath offers for application reuse. The document Organizing your Project describes how a single application project can be organized, and we will follow its guidelines in this document.

This document sketches out an example of a larger application that consists of multiple sub-projects and sub-apps, and that needs customization.

A Code Hosting Site

Our example large application is a code hosting site along the lines of Github or Bitbucket. This example is a sketch, not a complete working application. We focus on the structure of the application as opposed to the details of the UI.

Let’s examine the URL structure of a code hosting site. Our hypothetical code hosting site lives on example.com:

example.com

A user (or organization) has a URL directly under the root with the user name or organization name included:

example.com/faassen

Under this URL we can find repositories, using the project name in the URL:

example.com/faassen/myproject

We can interact with repository settings on this URL:

example.com/faassen/myproject/settings

We also have a per-repository issue tracker:

example.com/faassen/myproject/issues

And a per-repository wiki:

example.com/faassen/myproject/wiki

Simplest approach

The simplest approach to make this URL structure work is to implement all paths in a single application, like this:

from .model import Root, User, Repository, Settings, Issues, Wiki

class App(morepath.App):
    pass

@App.path(path='', model=Root)
def get_root():
   ...

@App.path(path='{user_name}', model=User)
def get_user(user_name):
   ...

@App.path(path='{user_name}/{repository_name}', model=Repository)
def get_repository(user_name, repository_name):
   ...

We could try to implement settings, issues and wiki as views on repository, but these are complicated pieces of functionality that benefit from having sub-URLs (i.e. issues/12 or ...wiki/mypage), so we model them using paths as well:

@App.path(path='{user_name}/{repository_name}/settings', model=Settings)
def get_settings(user_name, repository_name):
   ...

@App.path(path='{user_name}/{repository_name}/issues', model=Issues)
def get_issues(user_name, repository_name):
   ...

@App.path(path='{user_name}/{repository_name}/wiki', model=Wiki)
def get_wiki(user_name, repository_name):
   ...

Let’s also make a path to an individual issue, i.e. example.com/faassen/myproject/issues/12:

from .model import Issue

@App.path(path='{user_name}/{repository_name}/issues/{issue_id}', model=Issue)
def get_issue(user, repository, issue_id):
    ...

Problems

This approach works perfectly well, and it’s often the right way to start, but there are some problems with it:

  • The URL patterns in the path are repetitive; for each sub-model under the repository we keep having to repeat ‘{user_name}/{repository_name}`.
  • We may want to be able to test the wiki or issue tracker during development without having to worry about setting up the whole outer application.
  • We may want to reuse the wiki application elsewhere, or in multiple places in the same larger application. But user_name and repository_name are now hardcoded in the way to get any sub-path into the wiki.
  • We could have different teams developing the core app and the wiki (and issue tracker, etc). It would be nice to partition the code so that the wiki developers don’t need to look at the core app code and vice versa.
  • You may want the abilitity to swap in new implementations of a issue tracker or a wiki under the same paths, without having to change a lot of code.

We’re going to show how Morepath can solve these problems by partitioning a larger app into smaller ones, and mounting them.

The code to accomplish this is more involved than simply declaring all paths under a single core app as we did before. If you feel more comfortable doing that, by all means do so; you don’t have these problems. But if your application is successful and grows larger you may encounter these problems, and these features are then there to help.

Multiple sub-apps

Let’s split up the larger app into multiple sub apps. How many sub-apps do we need? We could go and partition things up into many sub-applications, but that risks getting lost in another kind of complexity. So let’s start with three application:

  • core app, everything up to repository, and including settings.
  • issue tracker app.
  • wiki sub app.

In code:

class CoreApp(morepath.App):
    pass

class IssuesApp(morepath.App):
    def __init__(self, issues_id):
        self.issues_id = issues_id

class WikiApp(morepath.App):
    def __init__(self, wiki_id):
        self.wiki_id = wiki_id

Note that IssuesApp and WikiApp expect arguments to be initialized; we’ll learn more about this later.

We now can group our paths into three. First we have the core app, which includes the repository and its settings:

@CoreApp.path(path='', model=Root)
def get_root():
   ...

@CoreApp.path(path='{user_name}', model=User)
def get_user(user_name):
   ...

@CoreApp.path(path='{user_name}/{repository_name}', model=Repository)
def get_repository(user_name, repository_name):
   ...

@CoreApp.path(path='{user_name}/{repository_name}/settings', model=Settings)
def get_settings(user_name, repository_name):
   ...

Then we have the paths for our issue tracker:

@IssuesApp.path(path='', model=Issues)
def get_issues():
   ...

@IssuesApp.path(path='{issue_id}', model=Issue)
def get_issue(issue_id):
    ...

And the paths for our wiki:

@WikiApp.path(path='', model=Wiki)
def get_wiki():
   ...

We have drastically simplified the paths in IssuesApp and WikiApp; we don’t deal with user_name and repository_name anymore.

Mounting apps

Now that we have an independent IssuesApp and WikiApp, we want to be able to mount these under the right URLs under CoreApp. We do this using the mount directive:

def variables(app):
    repository = get_repository_for_wiki_id(app.wiki_id)
    return dict(
          repository_name=repository.name,
          user_name=repository.user.name)

@CoreApp.mount(path='{user_name}/{repository_name}/issues',
               app=IssuesApp, variables=variables)
def mount_issues(user_name, repository_name):
    return IssuesApp(issues_id=get_issues_id(user_name, repository_name))

Let’s look at what this does:

  • @CoreApp.mount: We mount something onto CoreApp.
  • path='{user_name}/{repository_name}/issues': We are mounting it on that path. All sub-paths in the issue tracker app will fall under it.
  • app=IssuesApp: We are mounting IssuesApp.
  • The mount_issues function takes the path variables user_name and repository_name as arguments. It then returns an instance of the IssuesApp. To create one we need to convert the user_name and repository_name into an issues id. We do this by looking it up in some kind of database.
  • The variables function needs to do the inverse: given a WikiApp instance it needs to translate this back into a repository_name and user_name. This allows Morepath to link to a mounted WikiApp.

Mounting the wiki is very similar:

def variables(app):
    return dict(user_name=get_username_for_wiki_id(app.id))

@CoreApp.mount(path='{user_name}/{repository_name}/wiki',
                app=WikiApp, variables=variables)
def mount_wiki(user_name, repository_name):
    return WikiApp(get_wiki_id(user_name, repository_name))

No more path repetition

We have solved the repetition of paths issue now; the issue tracker and wiki handle many paths, but there is no more need to repeat ‘{user_name}/{repository_name}’ everywhere.

Testing in isolation

To test the issue tracker by itself, we can run it as a separate WSGI app:

def run_issue_tracker():
    mounted = IssuesApp(4)
    morepath.run(mounted)

Here we mount and run the issues_app with issue tracker id 4.

You can hook the run_issue_tracker function up to a script by using an entry point in setup.py as we’ve seen in Organizing your Project.

You can also mount applications this way in automated tests and then use WebTest or some other WSGI testing library.

Reusing an app

We can now reuse the issue tracker app in the sense that we can mount it in different apps; all we need is a way to get issues_id. What then if we have another Python project and we wanted to reuse the issue tracker in it as well? In that case it may start sense to start maintaining the issue tracker it in a separate Python project of its own.

We could for instance split our code into three separate Python projects, for instance:

  • myproject.core
  • myproject.issues
  • myproject.wiki

Each would be organized as described in Organizing your Project.

myproject.core could have an install_requires in its setup.py that depends on myproject.issues and myproject.wiki. To get IssuesApp and WikiApp in order to mount them in the core, we would simply import them (for instance in myproject.core.main):

from myproject.issues.main import IssuesApp
from myproject.wiki.main import WikiApp

In some scenarios you may want to turn this around: the IssuesApp and WikiApp know they should be mounted in CoreApp, but the CoreApp wants to remain innocent of this. In that case, you would have myproject.issues and myproject.wiki both depend on myproject.core, whereas myproject.core depends on nothing. The wiki and issues projects then mount themselves into the core app.

Different teams

Now that we have separate projects for the core, issue tracker and wiki, it becomes possible for a team to focus on the wiki without having to worry about core or the issue tracker and vice versa.

This may in fact be of benefit even when you alone are working on all three projects! When developing software it is important to free up your brain so you only have to worry about one detail at the time: this an important reason why we decomposition logic into functions and classes. By decomposing the project into three independent ones, you can temporarily forget about the core when you’re working on the issue tracker, allowing you to focus on the problems at hand.

Swapping in a new sub-app

Perhaps a different, better wiki implementation is developed. Let’s call it ShinyNewWikiApp. Swapping in the new sub application is easy: it’s just a matter of changing the mount directive:

@CoreApp.mount(path='{user_name}/{repository_name}/wiki',
               app=ShinyNewWikiApp, variables=variables)
def mount_wiki(user_name, repository_name):
    return ShinyNewWikiApp(get_wiki_id(user_name, repository_name))

Customizing an app

Let’s change gears and talk about customization now.

Imagine a scenario where a particular customer wants exactly core app. Really, it’s perfect, exactly what they need, no change needed, but then ... wait for it ... they actually do need a minor tweak.

Let’s say they want an extra view on Repository that shows some important customer-specific metadata. This metadata is retrieved from a customer-specific extra database, so we cannot just add it to core app. Besides, this new view isn’t useful to other customers.

What we need to do is create a new customer specific core app in a separate project that is exactly like the original core app by extending it, but with the one extra view added. Let’s call the project important_customer.core. important_customer.core has an install_requires in its setup.py that depends on myproject.core and also the customer database (which we call customerdatabase in this example).

Now we can import CoreApp in important_customer.core‘s main.py module, and extend it:

from myproject.core.main import CoreApp

class CustomerApp(CoreApp):
    pass

At this point CustomerApp and CoreApp have identical behavior. We can now make our customization and add a new JSON view to Repository:

from myproject.core.model import Repository
# customer specific database
from customerdatabase import query_metadata

@CustomerApp.json(model=Repository, name='customer_metadata')
def repository_customer_metadata(self, request):
    metadata = query_metadata(self.id) # use repository id to find it
    return {
      'special_marketing_info': medata.marketing_info,
      'internal_description': metadata.description
    }

You can now run CustomerApp and get the core app with exactly the one tweak the customer wanted: a view with the extra metadata. The important_customer.core project depends on customerdatabase, but myproject.core remains unchanged.

We’ve made exactly the tweak necessary without having to modify our original project. The original project continues to work the same way it always did.

Swapping in, for one customer

Morepath lets you extend any directive, not just the view directive. It also lets you override things in the applications you extend. Let’s say the important customer wants exactly the original wiki, with just one tiny teeny little tweak. Other customers should still continue to use the original wiki.

We’d tweak the wiki just as we would tweak the core app. We end up with a TweakedWikiApp:

from myproject.wiki.main import WikiApp

class TweakedWikiApp(WikiApp):
     pass

# some kind of tweak
@TweakedWikiApp.json(model=WikiPage, name='extra_info')
def page_extra_info(self, request):
    ...

We want a new version of CoreApp just for this customer that mounts TweakedWikiApp instead of WikiApp:

class ImportantCustomerApp(CoreApp):
    pass

@ImportantCustomerApp.mount(path='{user_name}/{repository_name}/wiki',
                            app=TweakedWikiApp, variables=variables)
def mount_wiki(user_name, repository_name):
    return TweakedWikiApp(get_wiki_id(user_name, repository_name))

The mount directive above overrides the one in the CoreApp that we’re extending, because it uses the same path but mounts TweakedWikiApp instead.

Framework apps

A morepath.App subclass does not need to be a full working web application. Instead it can be a framework with only those paths and views that we intend to be reusable.

We could for instance have a base class Metadata and define some views for it in the framework app. If we then have an application that inherits from the framework app, any Metadata model we expose to the web using the path directive automatically gets its views supplied by the framework.

For instance:

class Framework(morepath.App):
    pass

class Metadata(object):
    def __init__(self, d):
        self.d = d # metadata dictionary

    def get_metadata(self):
        return self.d

@Framework.json(model=Metadata, name='metadata')
def metadata_view(self, request):
    return self.get_metadata()

We want to use this framework in our own application:

class App(Framework):
    pass

Let’s have a model that subclasses from Metadata:

class Document(Metadata):
    ...

Let’s put the model on a path:

@App.path(path='documents/{id}', model=Document)
def get_document(id):
    ...

Since App extends Framework, all documents published this way have a metadata view automatically. Apps that don’t extend Framework won’t have this behavior, of course.

As we mentioned before, there is a gray area between application and framework; applications tend to gain attributes of a framework, and larger frameworks start to look more like applications. Don’t worry too much about which is which, but enjoy the creative possibilities!

Note that Morepath itself is designed as an application (morepath.App) that your apps extend. This means you can override parts of it just like you would override a framework app! We did our best to make Morepath do the right thing already, but if not, you can customize it.

Tweens

Introduction

Tweens are a light-weight framework component that sits between the web server and the app. It’s very similar to a WSGI middleware, except that a tween has access to the Morepath API and is therefore less low-level.

Tweens can be used to implement transaction handling, logging, error handling and the like.

signature of a handler

Morepath has an internal publish function that takes a single morepath.Request argument, and returns a morepath.Response as a result:

def publish(request):
    ...
    return response

Tweens have the same signature.

We call such functions handlers.

Under and over

Given a handler, we can create a factory that creates a tween that wraps around it:

def make_tween(app, handler):
    def my_tween(request):
        print "Enter"
        response = handler(request)
        print "Exit"
        return response
    return my_tween

We say that my_tween is over the handler argument, and conversely that handler is under my_tween.

The application constructs a chain of tween over tween, ultimately reaching the request handler. Request come in in the outermost tween and descend down the chain into the underlying tweens, and finally into the Morepath publish handler itself.

What can a tween do?

A tween can:

  • amend or replace the request before it goes in to the handler under it.
  • amend or replace the response before it goes back out to the handler over it.
  • inspect the request and completely take over response generation for some requests.
  • catch and handle exceptions raised by the handler under it.
  • do things before and after the request is handled: this can be logging, or commit or abort a database transaction.

Creating a tween factory

To have a tween, we need to add a tween factory to the app. The tween factory is a function that given a handler constructs a tween. You can register a tween factory using the App.tween_factory() directive:

@App.tween_factory()
def make_tween(app, handler):
    def my_tween(request):
        print "Enter"
        response = handler(request)
        print "Exit"
        return response
    return my_tween

The tween chain is now:

my_tween -> publish

It can be useful to control the order of the tween chain. You can do this by passing under or over to tween_factory:

@App.tween_factory(over=make_tween)
def make_another_tween(app, handler):
    def another_tween(request):
        print "Another"
        return handler(request)
    return another_tween

The tween chain is now:

another_tween -> my_tween -> publish

If instead you used under:

@App.tween_factory(under=make_tween)
def make_another_tween(app, handler):
    def another_tween(request):
        print "Another"
        return handler(request)
    return another_tween

Then the tween chain is:

my_tween -> another_tween -> publish

Tweens and settings

A tween factory may need access to some application settings in order to construct its tweens. A logging tween for instance needs access to a setting that indicates the path of the logfile.

The tween factory gets two arguments: the app and the handler. You can then access the app’s settings using app.settings. See also the Settings section.

Tweens and apps

You can register different tween factories in different Morepath apps. A tween factory only has an effect when the app under which it is registered is being run directly as a WSGI app. A tween factory has no effect if its app is mounted under another app. Only the tweens of the outer app are in effect at that point, and they are also in effect for any apps mounted into it.

This means that if you install a logging tween in an app, and you run this app with a WSGI server, the logging takes place for that app and any other app that may be mounted into it, directly or indirectly.

more.transaction

If you need to integrate SQLAlchemy or the ZODB into Morepath, Morepath offers a special app you can extend that includes a transaction tween that interfaces with the transaction package. The morepath_sqlalchemy demo project gives an example of what that looks like with SQLAlchemy.

Static resources with Morepath

Introduction

A modern client-side web application is built around JavaScript and CSS. The code is in files that is served by the web server too.

Morepath does not include in itself a way to serve these static resources. Instead it leaves the task to other WSGI components you can integrate with the Morepath WSGI component. Examples of such systems that can be integrated through WSGI are BowerStatic, Fanstatic and Webassets.

We will focus on BowerStatic integration here. We recommend you read its documentation, but we provide a small example of how to integrate it here that should help you get started. You can find all the example code in the github repo.

Application layout

To integrate BowerStatic with Morepath we can use the more.static extension.

First we need to include more.static as a dependency of our code in setup.py. Once it is installed, we can create a Morepath application that subclasses from more.static.StaticApp to get its functionality:

from more.static import StaticApp

class App(StaticApp):
    pass

We give it a simple HTML page on the root HTML that contains a <head> section in its HTML:

@App.path(path='/')
class Root(object):
    pass


@App.html(model=Root)
def root_default(self, request):
    return ("<!DOCTYPE html><html><head></head><body>"
            "jquery is inserted in the HTML source</body></html>")

It’s important to use @App.html as opposed to @App.view, as that sets the content-header to text/html, something that BowerStatic checks before it inserts any <link> or <script> tags. It’s also important to include a <head> section, as that’s where BowerStatic includes the static resources by default.

We also set up a main() function that when run serves the WSGI application to the web:

def main():
   morepath.autosetup()
   wsgi = App()
   morepath.run(wsgi)

All this code lives in the main.py module of a Python package.

Manual scan

We recommend you use morepath.autosetup to make sure that all code that uses Morepath is automatically scanned. If you do not use autosetup but use manual config.scan() instead, you need to scan more.static explicitly, like this:

import more.static

def main():
   config = morepath.setup()
   config.scan()
   config.scan(more.static)
   config.commit()
   wsgi = App()
   morepath.run(wsgi)

Bower

BowerStatic integrates the Bower JavaScript package manager with a Python WSGI application such as Morepath.

Once you have bower installed, go to your Python package directory (where the main.py lives), and install a Bower component. Let’s take jquery:

bower install jquery

You should now see a bower_components subdirectory in your Python package. We placed it here so that when we distribute the Python package that contains our application, the needed bower components are automatically included in the package archive. You could place bower_components elsewhere however and manage its contents separately.

Registering bower_components

BowerStatic needs a single global bower object that you can register multiple bower_copmonents directories against. Let’s create it first:

bower = bowerstatic.Bower()

We now tell that bower object about our bower_component directory:

components = bower.components(
  'app', os.path.join(os.path.dirname(__file__), 'bower_components'))

The first argument to bower.components is the name under which we want to publish them. We just pick app. The second argument specifies the path to the bower.components directory. The os.path business here is a way to make sure that we get the bower_components next to this module (main.py) in this Python package.

BowerStatic now lets you refer to files in the packages in bower_components to include them on the web, and also makes sure they are available.

Saying which components to use

We now need to tell our application to use the components object. This causes it to look for static resources only in the components installed there. We do this using the @App.static_components directive, like this:

@App.static_components()
def get_static_components():
    return components

You could have another application that use another components object, or share this components with the other application. Each app can only have a single components registered to it, though.

The static_components directive is not part of standard Morepath. Instead it is part of the more.static extension, which we enabled before by subclassing from StaticApp.

Including stuff

Now we are ready to include static resources from bower_components into our application. We can do this using the include() method on request. We modify our view to add an include() call:

@App.html(model=Root)
def root_default(self, request):
    request.include('jquery')
    return ("<!DOCTYPE html><html><head></head><body>"
            "jquery is inserted in the HTML source</body></html>")

When we now open the view in our web browser and check its source, we can see it includes the jquery we installed in bower_components.

Note that just like the static_components directive, the include() method is not part of standard Morepath, but has been installed by the more.static.StaticApp base class as well.

Local components

In many projects we want to develop our own client-side JS or CSS code, not just rely on other people’s code. We can do this by using local components. First we need to wrap the existing components in an object that allows us to add local ones:

local = bower.local_components('local', components)

We can now add our own local components. A local component is a directory that needs a bower.json in it. You can create a bower.json file most easily by going into the directory and using bower init command:

$ mkdir my_component
$ cd my_component
$ bower init

You can edit the generated bower.json further, for instance to specify dependencies. You now have a bower component. You can add any static files you are developing into this directory.

Now you need to tell the local components object about it:

local.component('/path/to/my_component', version=None)

See the BowerStatic local component documentation for more of what you can do with version – it’s clever about automatically busting the cache when you change things.

You need to tell your application that instead of plain components you want to use local instead, so we modify our static_components directive:

@App.static_components()
def get_static_components():
    return local

When you now use request.include(), you can include local components by their name (as in bower.json) as well:

request.include('my_component')

It automatically pulls in any dependencies declared in bower.json too.

As mentioned before, check the morepath_static github repo for the complete example.

A note about mounted applications

more.static uses a tween to inject scripts into the response (see :doc:tweens). If you use more.static in a view in a mounted application, you need to make sure that the root application also derives from more.static.StaticApp, otherwise the resources aren’t inserted correctly:

from more.static import StaticApp

class App(StaticApp):  # this needs to subclass StaticApp too
    pass

class Mounted(StaticApp):
    pass

 @App.mount(app=Mounted, path='mounted')
 def mount():
    return Mounted()

Morepath API

class morepath.App

A Morepath-based application object.

You subclass App to create a morepath application class. You can then configure this class using Morepath decorator directives.

An application can extend one or more other applications, if desired, by subclassing them. By subclassing App itself, you get the base configuration of the Morepath framework itself.

Conflicting configuration within an app is automatically rejected. An subclass app cannot conflict with the apps it is subclassing however; instead configuration is overridden.

You can turn your app class into a WSGI application by instantiating it. You can then call it with the environ and start_response arguments.

request_class

The class of the Request to create. Must be a subclass of morepath.Request.

alias of Request

@converter(type)

Register custom converter for type.

Parameters:type – the Python type for which to register the converter. Morepath uses converters when converting path variables and URL parameters when decoding or encoding URLs. Morepath looks up the converter using the type. The type is either given explicitly as the value in the converters dictionary in the morepath.App.path() directive, or is deduced from the value of the default argument of the decorated model function or class using type().

Defer link generation for model to mounted app.

With defer_links you can specify that link generation for instances of model is to be handled by a returned mounted app it cannot be handled by the given app itself. Request.link() and Request.view() are affected by this directive.

The decorated function gets an instance of the application and object to link to. It should return another application that it knows can create links for this object. The function uses navigation methods on App to do so like App.parent() and App.child().

Parameters:model – the class for which we want to defer linking.
@dump_json(model=<type 'object'>)

Register a function that converts model to JSON.

The decorated function gets self (model instance) and request (morepath.Request) parameters. The function should return an JSON object. That is, a Python object that can be dumped to a JSON string using json.dump.

Parameters:model – the class of the model for which this function is registered. The self passed into the function is an instance of the model (or of a subclass). By default the model is object, meaning we register a function for all model classes.
@function(func, **kw)

Register function as implementation of generic dispatch function

The decorated function is an implementation of the generic function supplied to the decorator. This way you can override parts of the Morepath framework, or create new hookable functions of your own.

The func argument is a generic dispatch function, so a Python function marked with app.dispatch() or app.predicate_dispatch().

Parameters:
  • func (dispatch function object) – the generic function to register an implementation for.
  • kw – keyword parameters with the predicate keys to register for. Argument names are predicate names, values are the predicate values to match on.
@html(model, render=None, template=None, permission=None, internal=False, **predicates)

Register HTML view.

This is like morepath.App.view(), but with morepath.render_html() as default for the render function.

Sets the content type to text/html.

Parameters:
  • model – the class of the model for which this view is registered.
  • name – the name of the view as it appears in the URL. If omitted, it is the empty string, meaning the default view for the model.
  • render – an optional function that can render the output of the view function to a response, and possibly set headers such as Content-Type, etc. Renders as HTML by default. This function takes self and request parameters as input.
  • template

    a path to a template file. The path is relative to the directory this module is in. The template is applied to the content returned from the decorated view function.

    Use the morepath.App.template_engine() directive to define support for new template engines.

  • permission – a permission class. The model should have this permission, otherwise access to this view is forbidden. If omitted, the view function is public.
  • internal – Whether this view is internal only. If True, the view is only useful programmatically using morepath.Request.view(), but will not be published on the web. It will be as if the view is not there. By default a view is False, so not internal.
  • name – the name of the view as it appears in the URL. If omitted, it is the empty string, meaning the default view for the model. This is a predicate.
  • request_method – the request method to which this view should answer, i.e. GET, POST, etc. If omitted, this view will respond to GET requests only. This is a predicate.
  • predicates – predicates to match this view on. See the documentation of App.view() for more information.
@identity_policy

Register identity policy.

The decorated function should return an instance of morepath.security.IdentityPolicy. Either use an identity policy provided by a library or implement your own.

@json(model, render=None, template=None, permission=None, internal=False, **predicates)

Register JSON view.

This is like morepath.App.view(), but with morepath.render_json() as default for the render function.

Transforms the view output to JSON and sets the content type to application/json.

Parameters:
  • model – the class of the model for which this view is registered.
  • name – the name of the view as it appears in the URL. If omitted, it is the empty string, meaning the default view for the model.
  • render – an optional function that can render the output of the view function to a response, and possibly set headers such as Content-Type, etc. Renders as JSON by default. This function takes self and request parameters as input.
  • template

    a path to a template file. The path is relative to the directory this module is in. The template is applied to the content returned from the decorated view function.

    Use the morepath.App.template_engine() directive to define support for new template engines.

  • permission – a permission class. The model should have this permission, otherwise access to this view is forbidden. If omitted, the view function is public.
  • internal – Whether this view is internal only. If True, the view is only useful programmatically using morepath.Request.view(), but will not be published on the web. It will be as if the view is not there. By default a view is False, so not internal.
  • name – the name of the view as it appears in the URL. If omitted, it is the empty string, meaning the default view for the model. This is a predicate.
  • request_method – the request method to which this view should answer, i.e. GET, POST, etc. If omitted, this view will respond to GET requests only. This is a predicate.
  • predicates – predicates to match this view on. See the documentation of App.view() for more information.

Register a function that returns the prefix added to every link generated by the request.

By default the link generated is based on webob.Request.application_url().

The decorated function gets the request (morepath.Request) as its only paremeter. The function should return a string.

@load_json

Register a function that converts JSON to an object.

The decorated function gets json and request (morepath.Request) parameters. The function should return a Python object based on the given JSON.

@mount(path, app, variables=None, converters=None, required=None, get_converters=None, name=None)

Mount sub application on path.

The decorated function gets the variables specified in path as parameters. It should return a new instance of an application class.

Parameters:
  • path – the path to mount the application on.
  • app – the morepath.App subclass to mount.
  • variables – a function that given an app instance can construct the variables used in the path (including any URL parameters). If omitted, variables are retrieved from the app by using the arguments of the decorated function.
  • converters – converters as for the morepath.App.path() directive.
  • required – list or set of names of those URL parameters which should be required, i.e. if missing a 400 Bad Request response is given. Any default value is ignored. Has no effect on path variables. Optional.
  • get_converters – a function that returns a converter dictionary. This function is called once during configuration time. It can be used to programmatically supply converters. It is merged with the converters dictionary, if supplied. Optional.
  • name – name of the mount. This name can be used with Request.child() to allow loose coupling between mounting application and mounted application. Optional, and if not supplied the path argument is taken as the name.
@path(path, model=None, variables=None, converters=None, required=None, get_converters=None, absorb=False)

Register a model for a path.

Decorate a function or a class (constructor). The function should return an instance of the model class, for instance by querying it from the database, or None if the model does not exist.

The decorated function gets as arguments any variables specified in the path as well as URL parameters.

If you declare a request parameter the function is able to use that information too.

Parameters:
  • path – the route for which the model is registered.
  • model – the class of the model that the decorated function should return. If the directive is used on a class instead of a function, the model should not be provided.
  • variables – a function that given a model object can construct the variables used in the path (including any URL parameters). If omitted, variables are retrieved from the model by using the arguments of the decorated function.
  • converters – a dictionary containing converters for variables. The key is the variable name, the value is a morepath.Converter instance.
  • required – list or set of names of those URL parameters which should be required, i.e. if missing a 400 Bad Request response is given. Any default value is ignored. Has no effect on path variables. Optional.
  • get_converters – a function that returns a converter dictionary. This function is called once during configuration time. It can be used to programmatically supply converters. It is merged with the converters dictionary, if supplied. Optional.
  • absorb – If set to True, matches any subpath that matches this path as well. This is passed into the decorated function as the remaining variable.
@permission_rule(model, permission, identity=<class 'morepath.security.Identity'>)

Declare whether a model has a permission.

The decorated function receives model, permission` (instance of any permission object) and identity (morepath.security.Identity) parameters. The decorated function should return True only if the given identity exists and has that permission on the model.

Parameters:
  • model – the model class
  • permission – permission class
  • identity – identity class to check permission for. If None, the identity to check for is the special morepath.security.NO_IDENTITY.
@predicate(dispatch, name, default, index, before=None, after=None)

Register custom predicate for a predicate_dispatch function.

The function registered should have arguments that are the same or a subset of the arguments of the predicate_dispatch function. From these arguments it should determine a predicate value and return it. The predicates for a predicate_dispatch function are ordered by their before and after arguments.

You can then register a function to dispatch to using the App.function() directive. This takes the predicate_dispatch or dispatch function as its first argument and the predicate key to match on as its other arguments.

Parameters:
  • dispatch – the predicate_dispatch function this predicate is for.
  • name – the name of the predicate. This is used when constructing a predicate key from a predicate dictionary.
  • default – the default value for a predicate, in case the value is missing in the predicate dictionary.
  • index – the index to use. Typically morepath.KeyIndex or morepath.ClassIndex.
  • default – the default value for this predicate. This is used as a default value if the argument is ommitted.
  • before – predicate function this function wants to have priority over.
  • after – predicate function we want to have priority over this one.
@predicate_fallback(dispatch, func)

For a given dispatch and function dispatched to, register fallback.

The fallback is called with the same arguments as the dispatch function. It should return a response (or raise an exception that can be turned into a response).

Parameters:
  • dispatch – the dispatch function
  • func – the registered function we are the fallback for
@setting(section, name)

Register application setting.

An application setting is registered under the settings attribute of morepath.app.Registry. It will be executed early in configuration so other configuration directives can depend on the settings being there.

The decorated function returns the setting value when executed.

Parameters:
  • section – the name of the section the setting should go under.
  • name – the name of the setting in its section.
@setting_section(section)

Register application setting in a section.

An application settings are registered under the settings attribute of morepath.app.Registry. It will be executed early in configuration so other configuration directives can depend on the settings being there.

The decorated function returns a dictionary with as keys the setting names and as values the settings.

Parameters:section – the name of the section the setting should go under.
@template_directory(after=None, before=None, name=None)

Register template directory.

The decorated function gets no argument and should return a relative or absolute path to a directory containing templates that can be loaded by this app. If a relative path, it is made absolute from the directory this module is in.

Template directories can be ordered: templates in a directory before another one are found before templates in a directory after it. But you can leave both before and after out: template directories defined in sub-applications automatically have a higher priority than those defined in base applications.

Parameters:
  • after – Template directory function this template directory function to be under. The other template directory has a higher priority. You usually want to use over. Optional.
  • before – Template directory function function this function should have priority over. Optional.
  • name – The name under which to register this template directory, so that it can be overridden by applications that extend this one. If no name is supplied a default name is generated.
@template_loader(extension)

Create a template loader.

The decorated function gets a template_directories argument, which is a list of absolute paths to directories that contain templates. It also gets a settings argument, which is application settings that can be used to configure the loader.

It should return an object that can load the template given the list of template directories.

@template_render(extension)

Register a template engine.

Parameters:extension – the template file extension (.pt, etc) we want this template engine to handle.

The decorated function gets loader, name and original_render arguments. It should return a callable that is a view render function: take a content and request object and return a morepath.Response instance. This render callable should render the return value of the view with the template supplied through its template argument.

@tween_factory(under=None, over=None, name=None)

Register tween factory.

The tween system allows the creation of lightweight middleware for Morepath that is aware of the request and the application.

The decorated function is a tween factory. It should return a tween. It gets two arguments: the app for which this tween is in use, and another tween that this tween can wrap.

A tween is a function that takes a request and a mounted application as arguments.

Tween factories can be set to be over or under each other to control the order in which the produced tweens are wrapped.

Parameters:
  • under – This tween factory produces a tween that wants to be wrapped by the tween produced by the under tween factory. Optional.
  • over – This tween factory produces a tween that wants to wrap the tween produced by the over tween factory. Optional.
  • name – The name under which to register this tween factory, so that it can be overridden by applications that extend this one. If no name is supplied a default name is generated.
@verify_identity(identity=<type 'object'>)

Verify claimed identity.

The decorated function gives a single identity argument which contains the claimed identity. It should return True only if the identity can be verified with the system.

This is particularly useful with identity policies such as basic authentication and cookie-based authentication where the identity information (username/password) is repeatedly sent to the the server and needs to be verified.

For some identity policies (auth tkt, session) this can always return True as the act of establishing the identity means the identity is verified.

The default behavior is to always return False.

Parameters:identity – identity class to verify. Optional.
@view(model, render=None, template=None, permission=None, internal=False, **predicates)

Register a view for a model.

The decorated function gets self (model instance) and request (morepath.Request) parameters. The function should return either a (unicode) string that is the response body, or a morepath.Response object.

If a specific render function is given the output of the function is passed to this first, and the function could return whatever the render parameter expects as input. This function should take the object to render and the request. func:morepath.render_json for instance expects as its first argument a Python object such as a dict that can be serialized to JSON.

See also morepath.App.json() and morepath.App.html().

Parameters:
  • model – the class of the model for which this view is registered. The self passed into the view function is an instance of the model (or of a subclass).
  • render – an optional function that can render the output of the view function to a response, and possibly set headers such as Content-Type, etc. This function takes self and request parameters as input.
  • template

    a path to a template file. The path is relative to the directory this module is in. The template is applied to the content returned from the decorated view function.

    Use the morepath.App.template_loader() and morepath.App.template_render() directives to define support for new template engines.

  • permission – a permission class. The model should have this permission, otherwise access to this view is forbidden. If omitted, the view function is public.
  • internal – Whether this view is internal only. If True, the view is only useful programmatically using morepath.Request.view(), but will not be published on the web. It will be as if the view is not there. By default a view is False, so not internal.
  • name – the name of the view as it appears in the URL. If omitted, it is the empty string, meaning the default view for the model. This is a predicate.
  • request_method – the request method to which this view should answer, i.e. GET, POST, etc. If omitted, this view responds to GET requests only. This is a predicate.
  • predicates – additional predicates to match this view on. You can install your own using the morepath.App.predicate() directive.
ancestors()

Return iterable of all ancestors of this app.

Includes this app itself as the first ancestor, all the way up to the root app in the mount chain.

child(app, **variables)

Get app mounted in this app.

Either give it an instance of the app class as the first parameter, or the app class itself (or name under which it was mounted) as the first parameter and as variables the parameters that go to its mount function.

Returns the mounted application object, with its parent attribute set to this app object, or None if this application cannot be mounted in this one.

classmethod directive(name)

Decorator to register a new directive with this application class.

You use this as a class decorator for a morepath.Directive subclass:

@App.directive('my_directive')
class FooDirective(morepath.Directive):
    ...

This needs to be executed before the directive is being used and thus might introduce import dependency issues unlike normal Morepath configuration, so beware! An easy way to make sure that all directives are installed before you use them is to make sure you define them in the same module as where you define the application class that has them.

request(environ)

Create a Request given WSGI environment for this app.

Parameters:environ – WSGI environment
Returns:morepath.Request instance
sibling(app, **variables)

Get app mounted next to this app.

Either give it an instance of the app class as the first parameter, or the app class itself (or name under which it was mounted) as the first parameter and as variables the parameters that go to its mount function.

Returns the mounted application object, with its parent attribute set to the same parent as this one, or None if such a sibling application does not exist.

lookup

Get the reg.Lookup for this application.

Returns:a reg.Lookup instance.
parent = None

The parent in which this app was mounted.

root

The root application.

morepath.autoconfig(ignore=None)

Automatically load Morepath configuration from packages.

Morepath configuration consists of decorator calls on App instances, i.e. @App.view() and @App.path().

This function loads all needed Morepath configuration from all packages automatically. These packages do need to be made available using a setup.py file including currect install_requires information so that they can be found using setuptools.

Creates a Config object as with setup(), but before returning it scans all packages, looking for those that depend on Morepath directly or indirectly. This includes the package that calls this function. Those packages are then scanned for configuration as with Config.scan().

You can add manual Config.scan() calls yourself on the returned Config object. Finally you need to call Config.commit() on the returned Config object so the configuration is committed.

Typically called immediately after startup just before the application starts serving using WSGI.

autoconfig always ignores .test and .tests sub-packages – these are assumed never to contain useful Morepath configuration and are not scanned.

autoconfig can fail with an ImportError when it tries to scan code that imports an optional dependency that is not installed. This happens most commonly in test code, which often rely on test-only dependencies such as pytest or nose. If those tests are in a .test or .tests sub-package they are automatically ignored, however.

If you have a special package with such expected import errors, you can exclude them from autoconfig using the ignore argument, for instance using ['special_package']. You then can use Config.scan for that package, with a custom ignore argument that excludes the modules that generate import errors.

See also autosetup().

Parameters:ignoreVenusian style ignore to ignore some modules during scanning. Optional. If ommitted, ignore .test and .tests packages by default.
Returns:Config object.
morepath.autosetup(ignore=None)

Automatically commit Morepath configuration from packages.

As with autoconfig(), but also commits configuration. This can be your one-stop function to load all Morepath configuration automatically.

Typically called immediately after startup just before the application starts serving using WSGI.

autosetup always ignores .test and .tests sub-packages – these are assumed never to contain useful Morepath configuration and are not scanned.

autosetup can fail with an ImportError when it tries to scan code that imports an optional dependency that is not installed. This happens most commonly in test code, which often rely on test-only dependencies such as pytest or nose. If those tests are in a .test or .tests sub-package they are automatically ignored, however.

If you have a special package with such expected import errors, you may be better off switching to morepath.autoconfig() with an ignore for this package, and then doing a manual Config.scan for that package with the resulting config object. There you can add a custom ignore argument that excludes the modules that generate import errors.

Parameters:ignoreVenusian style ignore to ignore some modules during scanning. Optional. If ommitted, ignore .test and .tests by default.
morepath.setup()

Set up core Morepath framework configuration.

Returns a Config object; you can then Config.scan() the configuration of other packages you want to load and then Config.commit() it.

See also autoconfig() and autosetup().

Returns:Config object.
morepath.run(wsgi, host=None, port=None)

Uses wsgiref.simple_server to run application for debugging purposes.

Don’t use this in production; use an external WSGI server instead, for instance Apache mod_wsgi, Nginx wsgi, Waitress, Gunicorn.

Parameters:
  • wsgi – WSGI app.
  • host – hostname.
  • port – port.
morepath.settings()

Return current settings object.

In it are sections, and inside of the sections are the setting values. If there is a logging section and a loglevel setting in it, this is how you would access it:

settings().logging.loglevel
morepath.redirect(location)

Return a response object that redirects to location.

class morepath.Request(environ, app, **kw)

Request.

Extends webob.request.BaseRequest

after(func)

Call function with response after this request is done.

Can be used explicitly:

def myfunc(response):
    response.headers.add('blah', 'something')
request.after(my_func)

or as a decorator:

@request.after
def myfunc(response):
    response.headers.add('blah', 'something')

If the normal response handling is interrupted by an exception either in your own code or by Morepath raising a HTTP exception, then after won’t execute for this exception.

If you directly return a response object from the view, after won’t have any effect either. Instead, you can manipulate the response object directly. Note that this is the case when you use morepath.redirect().

Parameters:func – callable that is called with response
Returns:func argument, not wrapped

Create a link (URL) to a view on a model instance.

The resulting link is prefixed by the link prefix. By default this is the full URL based on the Host header.

You can configure the link prefix for an application using the morepath.App.link_prefix() directive.

If no link can be constructed for the model instance, a :exc:morepath.LinkError is raised. None is treated specially: if None is passed in the default value is returned.

Parameters:
  • obj – the model instance to link to, or None.
  • name – the name of the view to link to. If omitted, the the default view is looked up.
  • default – if None is passed in, the default value is returned. By default this is None.
  • app – If set, change the application to which the link is made. By default the link is made to an object in the current application. The defer_links directive can be used to change the default app for all instances of a particular class (if this app doesn’t handle them).

Prefix to all links created by this request.

resolve_path(path, app=<SAME_APP>)

Resolve a path to a model instance.

The resulting object is a model instance, or None if the path could not be resolved.

Parameters:
  • path – URL path to resolve.
  • app – If set, change the application in which the path is resolved. By default the path is resolved in the current application.
Returns:

instance or None if no path could be resolved.

view(obj, default=None, app=<SAME_APP>, **predicates)

Call view for model instance.

This does not render the view, but calls the appropriate view function and returns its result.

Parameters:
  • obj – the model instance to call the view on.
  • default – default value if view is not found.
  • app – If set, change the application in which to look up the view. By default the view is looked up for the current application. The defer_links directive can be used to change the default app for all instances of a particular class.
  • predicates – extra predicates to modify view lookup, such as name and request_method. The default name is empty, so the default view is looked up, and the default request_method is GET. If you introduce your own predicates you can specify your own default.
app = None

The App object being handled by this request.

body_obj

JSON object, converted to an object.

You can use the App.load_json() directive to specify how to transform JSON to a Python object. By default, no conversion takes place, and body_obj is identical to the json attribute.

identity

Self-proclaimed identity of the user.

The identity is established using the identity policy. Normally this would be an instance of morepath.security.Identity.

If no identity is claimed or established, or if the identity is not verified by the application, the identity is the the special value morepath.security.NO_IDENTITY.

The identity can be used for authentication/authorization of the user, using Morepath permission directives.

lookup = None

The reg.Lookup object handling generic function calls.

class morepath.Response(body=None, status=None, headerlist=None, app_iter=None, content_type=None, conditional_response=None, **kw)

Response.

Extends webob.response.Response.

morepath.render_html(content, request)

Take string and return text/html response.

morepath.render_json(content, request)

Take dict/list/string/number content and return json response.

class morepath.security.Identity(userid, **kw)

Claimed identity of a user.

Note that this identity is just a claim; to authenticate the user and authorize them you need to implement Morepath permission directives.

Parameters:
  • userid – The userid of this identity
  • kw – Extra information to store in identity.
as_dict()

Export identity as dictionary.

This includes the userid and the extra keyword parameters used when the identity was created.

Returns:dict with identity info.
class morepath.security.IdentityPolicy

Identity policy API.

Implement this API if you want to have a custom way to establish identities for users in your application.

forget(response, request)

Forget identity on response.

Implements morepath.forget_identity, which is called from user logout code.

Remove identifying information from the response. This could delete a cookie or issue a basic auth re-authentication.

Parameters:
identify(request)

Establish what identity this user claims to have from request.

Parameters:request (morepath.Request.) – Request to extract identity information from.
Returns:morepath.security.Identity instance or morepath.security.NO_IDENTITY if identity cannot be established.
remember(response, request, identity)

Remember identity on response.

Implements morepath.remember_identity, which is called from user login code.

Given an identity object, store it on the response, for instance as a cookie. Some policies may not do any storing but instead retransmit authentication information each time in the request. Basic authentication is an example of such a non-storing policy.

Parameters:
class morepath.security.BasicAuthIdentityPolicy(realm='Realm')

Identity policy that uses HTTP Basic Authentication.

forget(response, request)

Forget identity on response.

This causes the browser to issue a basic authentication dialog. Warning: for basic auth, the browser in fact does not forget the information even if forget is called.

Parameters:
identify(request)

Establish claimed identity using request.

Parameters:request (morepath.Request.) – Request to extract identity information from.
Returns:morepath.security.Identity instance.
remember(response, request, identity)

Remember identity on response.

This is a no-op for basic auth, as the browser re-identifies upon each request in that case.

Parameters:
morepath.security.NO_IDENTITY = <morepath.security.NoIdentity object at 0x7f252e1e9150>
class morepath.Converter(decode, encode=None)

How to decode from strings to objects and back.

Only used for decoding for a list with a single value, will error if more or less than one value is entered.

Used for decoding/encoding URL parameters and path parameters.

Create new converter.

Parameters:
  • decode – function that given string can decode them into objects.
  • encode – function that given objects can encode them into strings.
class morepath.Config

Contains and executes configuration actions.

Morepath configuration actions consist of decorator calls on App instances, i.e. @App.view() and @App.path(). The Config object can scan these configuration actions in a package. Once all required configuration is scanned, the configuration can be committed. The configuration is then processed, associated with morepath.config.Configurable objects (i.e. App objects), conflicts are detected, overrides applied, and the configuration becomes final.

Once the configuration is committed all configured Morepath App objects are ready to be served using WSGI.

See setup(), which creates an instance with standard Morepath framework configuration. See also autoconfig() and autosetup() which help automatically load configuration from dependencies.

action(action, obj)

Register an action and obj with this config.

This is normally not invoked directly, instead is called indirectly by scan().

A Morepath directive decorator is an action, and obj is the function that was decorated.

Param:The Action to register.
Obj:The object to perform action on.
commit()

Commit all configuration.

  • Clears any previous configuration from all registered morepath.config.Configurable objects.
  • Prepares actions using prepared().
  • Actions are grouped by type of action (action class).
  • The action groups are executed in order of depends between their action classes.
  • Per action group, configuration conflicts are detected.
  • Per action group, extending configuration is merged.
  • Finally all configuration actions are performed, completing the configuration process.

This method should be called only once during the lifetime of a process, before the configuration is first used. After this the configuration is considered to be fixed and cannot be further modified. In tests this method can be executed multiple times as it automatically clears the configuration of its configurables first.

configurable(configurable)

Register a configurable with this config.

This is normally not invoked directly, instead is called indirectly by scan().

A App object’s registry attribute is a configurable.

Param:The morepath.config.Configurable to register.
prepared()

Get prepared actions before they are performed.

The preparation phase happens as the first stage of a commit. This allows configuration actions to complete their configuration, do error checking, or transform themselves into different configuration actions.

This calls Action.prepare() on all registered configuration actions.

Returns:An iterable of prepared action, obj combinations.
scan(package=None, ignore=None, recursive=True, onerror=None)

Scan package for configuration actions (decorators).

Register any found configuration actions with this object. This also includes finding any morepath.config.Configurable objects.

If given a package, it scans any modules and sub-packages as well recursively.

Parameters:
  • package – The Python module or package to scan. Optional; if left empty case the calling package is scanned.
  • ignore – A Venusian style ignore to ignore some modules during scanning. Optional.
  • recursive – Scan packages recursively. By default this is True. If set to False, only the __init__.py of a package is scanned.
  • onerror – onerror argument passed to Venusian’s scan.
class morepath.config.Configurable(extends=None, testing_config=None)

Object to which configuration actions apply.

Actions can be added to a configurable.

Once all actions are added, the configurable is executed. This checks for any conflicts between configurations and the configurable is expanded with any configurations from its extends list. Then the configurable is performed, meaning all its actions are performed (to it).

Parameters:
  • extends (list of configurables, single configurable.) – the configurables that this configurable extends. Optional.
  • testing_config – We can pass a config object used during testing. This causes the actions to be issued against the configurable directly instead of waiting for Venusian scanning. This allows the use of directive decorators in tests where scanning is not an option. Optional, default no testing config.
action(action, obj)

Register an action with configurable.

This is normally not invoked directly, instead is called indirectly by Config.commit().

Parameters:
  • action – The action to register with the configurable.
  • obj – The object that this action is performed on.
action_classes()

Get action classes sorted in dependency order.

action_extends(action_class)

Get actions for action class in extends.

actions()

Actions the configurable wants to register as it is scanned.

A configurable may want to register some actions as it is registered with the config system.

Should return a sequence of action, obj tuples.

clear()

Clear any previously registered actions.

This is normally not invoked directly, instead is called indirectly by Config.commit().

execute()

Execute actions for configurable.

group_actions()

Group actions into Actions by class.

class morepath.config.Action(configurable)

A configuration action.

A configuration action is performed on an object. Actions can conflict with each other based on their identifier and discriminators. Actions can override each other based on their identifier.

Can be subclassed to implement concrete configuration actions.

Action classes can have a depends attribute, which is a list of other action classes that need to be executed before this one is. Actions which depend on another will be executed after those actions are executed.

Initialize action.

Parameters:configurablemorepath.config.Configurable object for which this action was configured.
clone(**kw)

Make a clone of this action.

Keyword parameters can be used to override attributes in clone.

Used during preparation to create new fully prepared actions.

codeinfo()

Info about where in the source code the action was invoked.

By default there is no code info.

discriminators(configurable)

Returns a list of immutables to detect conflicts.

Parameters:configurablemorepath.config.Configurable object for which this action is being executed.

Used for additional configuration conflict detection.

group_key()

By default we group directives by their class.

Override this to group a directive with another directive, by returning that Directive class. It will create conflicts between those directives. Typically you’d do this when you are already subclassing from that directive too.

identifier(configurable)

Returns an immutable that uniquely identifies this config.

Parameters:configurablemorepath.config.Configurable object for which this action is being executed.

Used for overrides and conflict detection.

perform(configurable, obj)

Register whatever is being configured with configurable.

Parameters:
prepare(obj)

Prepare action for configuration.

Parameters:obj – The object that the action should be performed on.

Returns an iterable of prepared action, obj tuples.

class morepath.converter.ConverterRegistry

A registry for converters.

Used to decode/encode URL parameters and path variables used by the morepath.App.path() directive.

Is aware of inheritance.

argument_and_explicit_converters(arguments, converters)

Use explict converters unless none supplied, then use default args.

converter_for_explicit_or_type(c)

Given a converter or a type, turn it into an explicit one.

converter_for_explicit_or_type_or_list(c)

Given a converter or type or list, turn it into an explicit one.

Parameters:c – can either be a converter, or a type for which a converter can be looked up, or a list with a converter or a type in it.
Returns:a Converter instance.
converter_for_type(type)

Get converter for type.

Is aware of inheritance; if nothing is registered for given type it returns the converter registered for its base class.

Parameters:type – The type for which to look up the converter.
Returns:a morepath.Converter instance.
converter_for_value(v)

Get converter for value.

Is aware of inheritance; if nothing is registered for type of given value it returns the converter registered for its base class.

Parameters:value – The value for which to look up the converter.
Returns:a morepath.Converter instance.
explicit_converters(converters)

Given converter dictionary, make everything in it explicit.

This means types have converters looked up for them, and lists are turned into ListConverter.

register_converter(type, converter)

Register a converter for type.

Parameters:
  • type – the Python type for which to register the converter.
  • converter – a morepath.Converter instance.
class morepath.Directive(app)
morepath.directive

alias of morepath.directive

Comparison with other Web Frameworks

We hear you ask:

There are a million Python web frameworks out there. How does Morepath compare?

If you’re already familiar with another web framework, it’s useful to learn how Morepath is the same and how it is different, as that helps you understand it more quickly. So we go into some of this here.

Our ability to compare Morepath to other web frameworks is limited by our familiarity with them, and also by their aforementioned large quantity. But we’ll try. Feel free to pitch in new comparisons, or tell us where we get it wrong!

You may also want to read the Design Notes document.

Overview

Morepath aims to be foundational. All web applications are different. Some are simple. Some, like CMSes, are like frameworks themselves. It’s likely that some of you will need to build your own frameworky things on top of Morepath. Morepath doesn’t get in your way. Morepath isn’t there to be hidden away under another framework though - these extensions still look like Morepath. The orientation towards being foundational makes Morepath more like Pyramid, or perhaps Flask, than like Django.

Morepath aims to have a small core. It isn’t full stack; it’s a microframework. It should be easy to pick up. This makes it similar to other microframeworks like Flask or CherryPy, but different from Django and Zope, which offer a lot of features.

Morepath is opinionated. There is only one way to do routing and one way to do configuration. This makes it like a lot of web frameworks, but unlike Pyramid, which takes more of a toolkit approach where a lot of choices are made available.

Morepath is a routing framework, but it’s model-centric. Models have URLs. This makes it like a URL traversal framework like Zope or Grok, and also like Pyramid when traversal is in use. It makes it unlike other routing frameworks like Django or Flask, which have less awareness of models.

Paradoxically enough one thing Morepath is opinionated about is flexibility, as that’s part of its mission to be a good foundation. That’s what its configuration and generic function systems are all about. Want to change behavior? You can override everything. Even core behavior of Morepath can be changed by overriding its generic functions. This makes Morepath like Zope, and especially like Pyramid, but less like Django or Flask.

Routing

Morepath is a routing web framework, like Django and Flask and a lot of others. This is a common way to use Pyramid too (the other is traversal). This is also called URL mapping or dispatching. Morepath is to our knowledge, unique in that the routes don’t directly go to views, but go through models first.

Morepath’s route syntax is very similar to Pyramid’s, i.e. /hello/{name}. Flask is also similar. It’s unlike Django’s regular expressions. Morepath works at a higher level than that deliberately, as that makes it possible to disambiguate similar routes.

This separation of model and view lookup helps in code organisation, as it allows you to separate the code that organises the URL space from the code that implements your actual views.

Linking

Because it routes to models, Morepath allows you to ask for the URL of a model instance, like this:

request.link(mymodel)

That is an easier and less brittle way to make links than having to name your routes explicitly. Morepath pushes link generation quite far: it can construct links with paths and URL parameters automatically.

Morepath shares the property of model-based links with traversal based web frameworks like Zope and Grok, and also Pyramid in non-routing traversal mode. Uniquely among them Morepath does route, not traverse.

For more: Paths and Linking.

View lookup

Morepath uses a separate view lookup system. The name of the view is determined from the last step of the path being routed to. With this URL path for instance:

/document/edit

the /edit bit indicates the name of the view to look up for the document model.

If no view step is supplied, the default view is looked up:

/document

This is like modern Zope works, and like how the Plone CMS works. It’s also like Grok. It’s like Pyramid if it’s used with traversal instead of routing. Overall there’s a strong Zope heritage going on, as all these systems are derived from Zope in one way or another. Morepath is unique in that it combines routing with view lookup.

This decoupling of views from models helps with expressivity, as it lets you write reusable, generic views, and code organisation as mentioned before.

For more: Views.

WSGI

Morepath is a WSGI-based framework, like Flask or Pyramid. It’s natively WSGI, unlike Django, which while WSGI is supported also has its own way of doing middleware.

A Morepath app is a standard WSGI app. You can plug it into a WSGI compliant web server like Apache or Nginx or gunicorn. You can also combine Morepath with WSGI components, such as for instance the Fanstatic static resource framework.

Permissions

Morepath has a permission framework built-in: it knows about authentication and lets you plug in authenticators, you can protect views with permissions and plug in code that tells Morepath what permissions someone has for which models. It’s small but powerful in what it lets you do.

This is unlike most other micro-frameworks like Flask, Bottle, CherryPy or web.py. It’s like Zope, Grok and Pyramid, and has learned from them, though Morepath’s system is more streamlined.

For more you can check out this blog entry. (It will be integrated in this documentation later).

Explicit request

Some frameworks, like Flask and Bottle, have a magic request global that you can import. But request isn’t really a global, it’s a variable, and in Morepath it’s a variable that’s passed into view functions explicitly. This makes Morepath more similar to Pyramid or Django.

Testability and Global state

Developers that care about writing testable code try to avoid global state, in particular mutable global state, as it can make testing harder. If the framework is required to be in a certain global state before the code under test can be run, it becomes harder to test that code, as you need to know first what global state to manipulate.

Globals can also be a problem when multiple threads try to write the global at the same time. Web frameworks avoid this by using thread locals. Confusingly enough these locals are globals, but they’re isolated from other threads.

Morepath the framework does not require any global state. Of course Morepath’s app are module globals, but they’re not used that way once Morepath’s configuration is loaded and Morepath starts to handle requests. Morepath’s framework code passes the app along as a variable (or attribute of a variable, such as the request) just like everything else.

Morepath is built on the Reg generic function library. Implementations of generic functions can be plugged in separately per Morepath app: each app is a registry. When you call a generic function Reg needs to know what registry to use to look it up. You can make this completely explicit by using a special lookup argument:

some_generic_function(doc, 3, lookup=app.lookup())

That’s all right in framework code, but doing that all the time is not very pretty in application code. For convenience, Morepath therefore sets up the current lookup implicitly as thread local state. Then you can simply write this:

some_generic_function(doc, 3)

Flask is quite happy to use global state (with thread locals) to have a request that you can import. Pyramid is generally careful to avoid global state, but does allow using thread local state to get access to the current registry in some cases.

Summary: Morepath does not require any global state, but allows the current lookup to be set up as such for convenience.

No default database

Morepath has no default database integration. This is like Flask and Bottle and Pyramid, but unlike Zope or Django, which have assumptions about the database baked in (ZODB and Django ORM respectively).

You can plug in your own database, or even have no database at all. You could use SQLAlchemy, or the ZODB. Morepath lets you treat anything as models. We’re not against writing examples or extensions that help you do this, though we haven’t done so yet. Contribute!

No template language

Some micro-frameworks like Flask and Bottle and web.py have template languages built-in, some, like CherryPy and the Werkzeug toolkit, don’t. Pyramid doesn’t have built-in support either, but has standard plugins for the Chameleon and Mako template languages.

Morepath aims to be a good fit for modern, client-side web applications written in JavaScript. So we’ve focused on making it easy to send anything to the client, especially JSON. If templating is used for such applications, it’s done on the client, in the web browser, not on the server.

We’re planning on letting you plug in server-side template languages as they’re sometimes useful, but we haven’t done so yet. Feel free to contribute!

For now, you can plug in something yourself. CherryPy has a good document on how to do that with CherryPy, and it’d look very similar with Morepath.

Code configuration

Most Python web frameworks don’t have an explicit code configuration system. With “code configuration” I mean expressing things like “this function handles this route”, “this view works for this model”, and “this is the current authentication system”. It also includes extension and overrides, such as “here is an additional route”, “use this function to handle this route instead of what the core said”.

If a web framework doesn’t deal with code configuration explicitly, an implicit code configuration tends to grow. There is one way to set up routes, another way to declare models, another way to do generic views, yet another way to configure the permission system, and so on. Each system works differently and uses a different API. Config files, metaclasses and import-time side effects may all be involved.

On top of this, if the framework wants to allow reuse, extension and overrides the APIs tends to grow even more distinct with specialised use cases, or yet more new APIs are grown.

Django is an example where configuration gained lots of knobs and buttons; another example is the original Zope.

Microframeworks aim for simplicity so don’t suffer from this so much, though probably at the cost of some flexibility. You can still observe this kind of evolution in Flask’s pluggable views subsystem, though, for instance.

To deal with this problem in an explicit way the Zope project pioneered a component configuration mechanism. By having a universal mechanism in which code is configured, the configuration API becomes general and allows extension and override in a general manner as well. Zope uses XML files for this.

The Grok project tried to put a friendlier face on the rather verbose configuration system of Zope. Pyramid refined Grok’s approach further. It offers a range of options for configuration: explicit calls in Python code, decorators, and an extension that uses Zope-style XML.

In order to do its decorator based configuration, the Pyramid project created the Venusian python library. This is in turn a reimagined version of the Martian python library created by the Grok project.

Morepath has a new configuration system that is based around decorators (using Venusian) attached to application objects. These application objects can extend other ones. This way it supports a range sophisticated extension and override use cases in a general way.

Components and Generic functions

The Zope project made the term “zope component architecture” (ZCA) (in)famous in the Python world. Does it sound impressive, suggesting flexibility and reusability? Or does it sound scary, overengineered, RequestProcessorFactoryFactory-like? Are you intimidated by it? We can’t blame you.

At its core the ZCA is really a system to add functionality to objects from the outside, without having to change their classes. It helps when you need to build extensible applications and reusable generic functionality. Under the hood, it’s just a fancy registry that knows about inheritance. Its a really powerful system to help build more complicated applications and frameworks. It’s used by Zope, Grok and Pyramid.

Morepath uses something else: a library called Reg. This is a new, reimagined, streamlined implementation of the idea of the ZCA.

The underlying registration APIs of the ZCA is rather involved, with quite a few special cases. Reg has a simpler, more general registration API that is flexible enough to fulfill a range of use cases.

Finally what makes the Zope component architecture rather involved to use is its reliance on interfaces. An interface is a special kind of object introduced by the Zope component architecture that is used to describe the API of objects. It’s like an abstract base class.

If you want to look up things in a ZCA component registry the ZCA requires you to look up an interface. This requires you to write interfaces for everything you want to be able to look up. The interface-based way to do lookups also looks rather odd to the average Python developer: it’s not considered to be very Pythonic. To mitigate the last problem Pyramid creates simple function-based APIs on top of the underlying interfaces.

Morepath by using Reg does away with interfaces altogether – instead it uses generic functions. The simple function-based APIs are what is pluggable; there is no need to deal with interfaces anymore, but the system retains the power. Morepath is simple functions all the way down.

Design Notes

Some of the use cases that influenced Morepath’s design are documented here.

Publish any model

It should be possible to publish any model object to the web on a readable URL. This includes model objects that are retrieved from a relational database and were created with a ORM.

Allowing individual models to be published on separate URLs avoids the god object antipattern where all web operations are routed through a single object. Instead each model, through view objects, can handle model-specific requests and operations. This encourages a more modular and reusable application design.

Routing

It should be easy to declare explicit routes to model. A route consists of a routing pattern with zero or more variables. The variables are used to identify the model, for instance using a relational database query.

Having routes makes it easier to reason about the URL structure of an application. Routes also make it easier to expose models that are retrieved using a query or are constructed on the fly, without imposing a specific structure on the models.

Traversal

It should be possible to associate routes with specific models in the application, not just to the root. This way models with sub-paths to sub-components can be made available as reusable components; an example of this could be a container. If the model is published, its sub-components are then exposed as well.

This allows for increased reuse of not just models but relationships between models, and lets the developer publish nested structures that cannot be specified using routing alone.

Linking

If a model is published, it should be possible to automatically generate a link to a model instance in the form of a URL.

This way there is no need to construct URLs manually, and there is no need to have to refer to routes explicitly in order to construct URLs. The system knows which route to use and how to construct the parameters that go into the route itself, given the model.

This is useful when creating RESTful web services (where hypermedia is the engine of application state), or to construct rich client-side applications that get all their URLs from the server from a REST-style web service.

Model is web-agnostic

Model classes should not have to have any web knowledge; no particular base classes are required, and no methods or attributes need to be implemented in order to publish instances of that model to the web. In case of an ORM, the ORM does not need to be reconfigured in order to publish ORM-mapped classes to the web. Models do not receive any request object and do not have to generate a response object.

Instead this knowledge is external to the models. Models should be optimized for programmatic use in general.

View/model separation

View objects are responsible for translating the model to the web and web operations to operations on the model. Views receive the request object and generate the response object. This is again to avoid giving the models knowledge about the web. This is a kind of model/view separation where the view is the intermediary between the model and the web.

Isolation between applications

The system allows multiple applications to be published at the same time. Applications work in isolation from each other by default. For instance, publishing a model on a URL does not affect another application, and publishing a view for a model does not make that view available in the other application.

Sharing between applications

In order to support reusable components, it should be possible to explicitly break application isolation and make routes to models and views globally available. Each application will share this information.

[Morepath in fact now allows more controlled sharing; only Morepath itself is globally shared]

Models can be published once per application

Per application a model can be exposed on a single URL pattern. So, the same instance could be published once per application, in a URL structure optimal for each application.

Again this supports applications working in isolation - they may treat database models differently than other applications do.

Linking to another application

It should be possible to construct URLs to models in the context of another application, if this application is given explicitly during link time.

Reusable components

It should be possible to define a base class (or interface) for a model that automatically pulls in (globally registered) views and sub-paths when you subclass from it. This lets a framework developer define APIs that an application developer can implement. By doing so, the application developer automatically gets a whole set of views for their models.

Declarative

It should be possible to register the components in a declarative way. This avoids spaghetti registration code, and also makes it possible to more easily reason about registrations (for instance to do overrides or detect conflicts).

Conflicts

If you try to do the same registration multiple times, the system should fail explicitly, as otherwise this would lead to subtle errors.

Overrides

It should be possible to override one registration with another one. This should either be an explicit operation, or the result of overriding in a different registry that has precedence over the defaults.

Developing Morepath

Community

Communication is important, so see Community for information on how to get in touch!

Install Morepath for development

First make sure you have virtualenv installed for Python 2.7.

Now create a new virtualenv somewhere for Morepath development:

$ virtualenv /path/to/ve_morepath

You should also be able to recycle an existing virtualenv, but this guarantees a clean one. Note that we skip activating the environment here, as this is just needed to initially bootstrap the Morepath buildout.

Clone Morepath from github and go to the morepath directory:

$ git clone git@github.com:morepath/morepath.git
$ cd morepath

Now we need to run bootstrap.py to set up buildout, using the Python from the virtualenv we’ve created before:

$ python /path/to/ve_morepath/bin/python/bootstrap.py

This installs buildout, which can now set up the rest of the development environment:

$ bin/buildout

This downloads and installs various dependencies and tools. The commands you run in bin are all restricted to the virtualenv you set up before. There is therefore no need to refer to the virtualenv once you have the development environment going.

Running the tests

You can run the tests using py.test. Buildout has installed it for you in the bin subdirectory of your project:

$ bin/py.test morepath

To generate test coverage information as HTML do:

$ bin/py.test morepath --cov morepath --cov-report html

You can then point your web browser to the htmlcov/index.html file in the project directory and click on modules to see detailed coverage information.

flake8

The buildout also installs flake8, which is a tool that can do various checks for common Python mistakes using pyflakes and checks for PEP8 style compliance.

To do pyflakes and pep8 checking do:

$ bin/flake8 morepath

radon

The buildout installs radon. This is a tool that can check various measures of code complexity.

To check for cyclomatic complexity (excluding the tests):

$ bin/radon cc morepath -e "morepath/tests*"

To filter for anything not ranked A:

$ bin/radon cc morepath --min B -e "morepath/tests*"

And to see the maintainability index:

$ bin/radon mi morepath -e "morepath/tests*"

CHANGES

0.10 (2015-04-09)

  • Server-side templating language support: there is now a template argument for the html directive (and view and json). You need to use a plugin to add particular template languages to your project, such as more.chameleon and more.jinja2, but you can also add your own.

    See http://morepath.readthedocs.org/en/latest/templates.html

  • Add a new “A Review of the Web” document to the docs to show how Morepath fits within the web.

    http://morepath.readthedocs.org/en/latest/web.html

  • The publisher does not respond to a None render function anymore. Instead, the view directive now uses a default render_view if None is configured. This simplifies the publisher guaranteeing a render function always exists.

    Fixes https://github.com/morepath/morepath/issues/283

  • Introduce a request.resolve_path method that allows you to resolve paths to objects programmatically.

  • Modify setup.py to use io.open instead of open to include the README and the CHANGELOG and hardcode UTF-8 so it works on all versions of Python with all default encodings.

  • Various documentation fixes.

0.9 (2014-11-25)

  • Breaking change. In previous releases of Morepath, Morepath did not include the full hostname in generated links (so /a instead of http://example.com/a). Morepath 0.9 does include the full hostname in generated links by default. This to support the non-browser client use case better. In the previous system without fully qualified URLs, client code needs to manually add the base of links itself in order to be able to access them. That makes client code more complicated than it should be. To make writing such client code as easy as possible Morepath now generates complete URLs.

    This should not break any code, though it can break tests that rely on the previous behavior. To fix webtest style tests, prefix the expected links with http://localhost/.

    If for some reason you want the old behavior back in an application, you can use the link_prefix directive:

    @App.link_prefix()
    def my_link_prefix(request):
        return '' # prefix nothing again
    
  • Directives are now logged to the morepath.directive log, which is using the standard Python logging infrastructure. See http://morepath.readthedocs.org/en/latest/logging.html

  • Document more.forwarded proxy support in http://morepath.readthedocs.org/en/latest/paths_and_linking.html

  • Document behavior of request.after in combination with directly returning a response object from a view.

  • Expose body_model_predicate to the public Morepath API. You can now say your predicate comes after it.

  • Expose LAST_VIEW_PREDICATE to the Morepath API. This is the last predicate defined by the Morepath core.

  • Update the predicate documentation.

  • Updated the more.static doc to reflect changes in it.

  • Fix doc for grouping views with the with statement.

  • Suggest a few things to try when your code doesn’t appear to be scanned properly.

  • A new view predicate without a fallback resulted in an internal server error if the predicate did not match. Now it results in a 404 Not Found by default. To override this default, define a predicate fallback.

0.8 (2014-11-13)

  • Breaking change. Reg 0.9 introduces a new, more powerful way to create dispatch functions, and this has resulted in a new, incompatible Reg API.

    Morepath has been adjusted to make use of the new Reg. This won’t affect many Morepath applications, and they should be able to continue unchanged. But some Morepath extensions and advanced applications may break, so you should be aware of the changes.

    • The @App.function directive has changed from this:

      class A(object):
          pass
      
      class B(object):
          pass
      
      @reg.generic
      def dispatch_function(a, b):
          pass
      
      @App.function(dispatch_function, A, B)
      def dispatched_to(a, b):
          return 'dispatched to A and B'
      

      to this:

      class A(object):
          pass
      
      class B(object):
          pass
      
      @reg.dispatch('a', 'b')
      def dispatch_function(a, b):
          pass
      
      @App.function(dispatch_function, a=A, b=B)
      def dispatched_to(a, b):
          return 'dispatched to A and B'
      

      The new system in Reg (see its docs) is a lot more flexible than what we had before. When you use function you don’t need to know about the order of the predicates anymore – this is determined by the arguments to @reg.dispatch(). You can now also have function arguments that Reg ignores for dispatch.

    • The @App.predicate and @App.predicate_fallback directive have changed. You can now install custom predicates and fallbacks for any generic function that’s marked with @reg.dispatch_external_predicates(). The Morepath view code has been simplified to be based on this, and is also more powerful as it can now be extended with new predicates that use predicate-style dispatch.

  • Introduce the body_model predicate for views. You can give it the class of the request.body_obj you want to handle with this view. In combination with the load_json directive this allows you to write views that respond only to the POSTing or PUTing of a certain type of object.

  • Internals refactoring: we had a few potentially overridable dispatch functions in morepath.generic that actually were never overridden in any directives. Simplify this by moving their implementation into morepath.publish and morepath.request. generic.link, generic.consume and generic.response are now gone.

  • Introduce a link_prefix directive that allows you to set the URL prefix used by every link generated by the request.

  • A bug fix in request.view(); the lookup on the request was not properly updated.

  • Another bug fix in request.view(); if deferred_link_app app is used, request.app should be adjusted to the app currently being deferred to.

  • request.after behavior is clarified: it does not run for any exceptions raised during the handling of the request, only for the “proper” response. Fix a bug where it did sometimes run.

  • Previously if you returned None for a path in a variables function for a path, you would get a path with None in it. Now it is a LinkError.

  • If you return a non-dict for variables for a path, you get a proper LinkError now.

  • One test related to defer_links did not work correctly in Python 3. Fixed.

  • Add API doc for body_obj. Also fix JSON and objects doc to talk about request.body_obj instead of request.obj.

  • Extend API docs for security: detail the API an identity policy needs to implement and fix a few bugs.

  • Fix ReST error in API docs for autoconfig and autosetup.

  • Fix a few ReST links to the API docs in the app reuse document.

0.7 (2014-11-03)

  • Breaking change. There has been a change in the way the mount directive works. There has also been a change in the way linking between application works. The changes result in a simpler, more powerful API and implementation.

    The relevant changes are:

    • You can now define your own custom __init__ for morepath.App subclasses. Here you can specify the arguments with which your application object should be mounted. The previous variables class attribute is now ignored.

      It’s not necessary to use super() when you subclass from morepath.App directly.

      So, instead of this:

      class MyApp(morepath.App):
          variables = ['mount_id']
      

      You should now write this:

      class MyApp(morepath.App):
          def __init__(self, mount_id):
              self.mount_id = mount_id
      
    • The mount directive should now return an instance of the application being mounted, not a dictionary with mount parameters. The application is specified using the app argument to the directive. So instead of this:

      @RootApp.mount(app=MyApp, path='sub/{id}')
      def mount_sub(id):
          return {
             'mount_id': id
          }
      

      You should now use this:

      @RootApp.mount(app=MyApp, path='sub/{id}')
      def mount_sub(id):
          return MyApp(mount_id=id)
      
    • The mount directive now takes a variables argument. This works like the variables argument to the path directive and is used to construct links.

      It is given an instance of the app being mounted, and it should reconstruct those variables needed in its path as a dictionary. If omitted, Morepath tries to get them as attributes from the application instance, just like it tries to get attributes of any model instance.

      MyApp above is a good example of where this is required: it does store the correct information, but as the mount_id attribute, not the id attribute. You should add a variables argument to the mount directive to explain to Morepath how to obtain id:

      @RootApp.mount(app=MyApp, path='sub/{id}',
                     variables=lambda app: dict(id=app.mount_id))
      def mount_sub(id):
          return MyApp(mount_id=id)
      

      The simplest way to avoid having to do this is to name the attributes the same way as the variables in the paths, just like you can do for model classes.

    • In the past you’d get additional mount context variables as extra variables in the function decorated by the path decorator. This does not happen anymore. Instead you can add a special app parameter to this function. This gives you access to the current application object, and you can extract its attributes there.

      So instead of this:

      @MyApp.path(path='models/{id}', model=Model)
      def get_root(mount_id, id):
          return Model(mount_id, id)
      

      where mount_id is magically retrieved from the way MyApp was mounted, you now write this:

      @MyApp.path(path='models/{id}', model=Model)
      def get_root(app, id):
          return Model(app.mount_id, id)
      
    • There was an request.mounted attribute. This was a special an instance of a special Mounted class. This Mounted class is now gone – instead mounted applications are simply instances of their class. To access the currently mounted application, use request.app.

    • The Request object had child and sibling methods as well as a parent attribute to navigate to different “link makers”. You’d navigate to the link maker of an application in order to create links to objects in that application. These are now gone. Instead you can do this navigation from the application object directly, and instead of link makers, you get application instances. You can pass an application instance as a special app argument to request.link and request.view.

      So instead of this:

      request.child(foo).link(obj)
      

      You now write this:

      request.link(obj, app=request.app.child(foo))
      

      And instead of this:

      request.parent.link(obj)
      

      You now write this:

      request.link(obj, app=request.app.parent)
      

      Note that the new defer_links directive can be used to automate this behavior for particular models.

    • The .child method on App can the app class as well as the parameters for the function decorated by the mount directive:

      app.child(MyApp, id='foo')
      

      This can also be done by name. So, assuming MyApp was mounted under my_app:

      app.child('my_app', id='foo')
      

      This is how request.child worked already.

      As an alternative you can now instead pass an app instance:

      app.child(MyApp(mount_id='foo'))
      

      Unlike the other ways to get the child, this takes the parameters need to create the app instance, as opposed to taking the parameters under which the app was mounted.

    Motivation behind these changes:

    Morepath used to have a Mount class separate from the App classes you define. Since Morepath 0.4 application objects became classes, and it made sense to make their instances the same as the mounted application. This unification has now taken place.

    It then also made sense to use its navigation methods (child and friend) to navigate the mount tree, instead of using the rather complicated “link maker” infrastructure we had before.

    This change simplifies the implementation of mounting considerably, without taking away features and actually making the APIs involved more clear. This simplification in turn made it easier to implement the new defer_links directive.

  • Breaking change. The arguments to the render function have changed. This is a function you can pass to a view directive. The render function now takes a second argument, the request. You need to update your render functions to take this into account. This only affects code that supplies an explicit render function to the view, json and html directives, and since not a lot of those functions exist, the impact is expected to be minimal.

  • Breaking change. In certain circumstances it was useful to access the settings through an application instance using app.settings. This does not work anymore; access the settings through app.registry.settings instead.

  • dump_json and load_json directives. This lets you automatically convert an object going to a response to JSON, and converts JSON coming in as a request body from JSON to an object. See http://morepath.readthedocs.org/en/latest/json.html for more information.

  • defer_links directive. This directive can be used to declare that a particular mounted application takes care of linking to instances of a class. Besides deferring request.link() it will also defer request.view. This lets you combine applications with more ease. By returning None from it you can also defer links to this app’s parent app.

  • app.ancestors() method and app.root attribute. These can be used for convenient access to the ancestor apps of a mounted application. To access from the request, use request.app.root and request.app.ancestors().

  • The App class now has a request_class class attribute. This determines the class of the request that is created and can be overridden by subclasses. more.static now makes use of this.

  • Several generic functions that weren’t really pulling their weight are now gone as part of the mount simplification: generic.context and generic.traject are not needed anymore, along with generic.link_maker.

  • Change documentation to use uppercase class names for App classes everywhere. This reflects a change in 0.4 and should help clarity.

  • Added documentation about auto-reloading Morepath during development.

  • No longer silently suppress ImportError during scanning: this can hide genuine ImportError in the underlying code.

    We were suppressing ImportError before as it can be triggered by packages that rely on optional dependencies.

    This is a common case in the .tests subdirectory of a package which may import a test runner like pytest. pytest is only a test dependency of the package and not a mainline dependencies, and this can break scanning. To avoid this problem, Morepath’s autosetup and autoconfig now automatically ignore .tests and .test sub-packages.

    Enhanced the API docs for autosetup and autoconfig to describe scenarios which can generate legitimate ImportError exceptions and how to handle them.

  • Fix of examples in tween documentation.

  • Minor improvement in docstrings.

0.6 (2014-09-08)

  • Fix documentation on the with statement; it was not using the local view variable correctly.

  • Add #morepath IRC channel to the community docs.

  • Named mounts. Instead of referring to the app class when constructing a link to an object in an application mounted elsewhere, you can put in the name of the mount. The name of the mount can be given explicitly in the mount directive but defaults to the mount path.

    This helps when an application is mounted several times and needs to generate different links depending on where it’s mounted; by referring to the application by name this is loosely coupled and will work no matter what application is mounted under that name.

    This also helps when linking to an application that may or may not be present; instead of doing an import while looking for ImportError, you can try to construct the link and you’ll get a LinkError exception if the application is not there. Though this still assumes you can import the model class of what you’re linking to.

    (see issue #197)

  • Introduce a sibling method on Request. This combines the .parent.child step in one for convenience when you want to link to a sibling app.

0.5.1 (2014-08-28)

  • Drop usage of sphinxcontrib.youtube in favor of raw HTML embedding, as otherwise too many things broke on readthedocs.

0.5 (2014-08-28)

  • Add more.static documentation on local components.

  • Add links to youtube videos on Morepath: the keynote at PyCon DE 2013, and the talk on Morepath at EuroPython 2014.

  • Add a whole bunch of extra code quality tools to buildout.

  • verify_identity would be called even if no identity could be established. Now skip calling verify_identity when we already have NO_IDENTITY. See issue #175.

  • Fix issue #186: mounting an app that is absorbing paths could sometimes generate the wrong link. Thanks to Ying Zhong for the bug report and test case.

  • Upgraded to a newer version of Reg (0.8) for @reg.classgeneric support as well as performance improvements.

  • Add a note in the documentation on how to deal with URL parameters that are not Python names (such as foo@, or blah[]). You can use a combination of extra_parameters and get_converters to handle them.

  • Document the use of the with statement for directive abbreviation (see the Views document).

  • Created a mailing list:

    https://groups.google.com/forum/#!forum/morepath

    Please join!

    Add a new page on community to document this.

0.4.1 (2014-07-08)

  • Compatibility for Python 3. I introduced a meta class in Morepath 0.4 and Python 3 did not like this. Now the tests pass again in Python 3.
  • remove generic.lookup, unused since Morepath 0.4.
  • Increase test coverage back to 100%.

0.4 (2014-07-07)

  • BREAKING CHANGE Move to class-based application registries. This breaks old code and it needs to be updated. The update is not difficult and amounts to:

    • subclass morepath.App instead of instantiating it to create a new app. Use subclasses for extension too.
    • To get a WSGI object you can plug into a WSGI server, you need to instantiate the app class first.

    Old way:

    app = morepath.App()
    

    So, the app object that you use directives on is an instance. New way:

    class app(morepath.App):
        pass
    

    So, now it’s a class. The directives look the same as before, so this hasn’t changed:

    @app.view(model=Foo)
    def foo_default(self, request):
       ...
    

    To extend an application with another one, you used to have to pass the extends arguments. Old way:

    sub_app = morepath.App(extends=[core_app])
    

    This has now turned into subclassing. New way:

    class sub_app(core_app):
        pass
    

    There was also a variables argument to specify an application that can be mounted. Old way:

    app = morepath.App(variables=['foo'])
    

    This is now a class attribute. New way:

    class app(morepath.App):
        variables = ['foo']
    

    The name argument to help debugging is gone; we can look at the class name now. The testing_config argument used internally in the Morepath tests has also become a class attribute.

    In the old system, the application object was both configuration point and WSGI object. Old way:

    app = morepath.App()
    
    # configuration
    @app.path(...)
    ...
    
    # wsgi
    morepath.run(app)
    

    In the Morepath 0.4 this has been split. As we’ve already seen, the application class serves. To get a WSGI object, you need to first instantiate it. New way:

    class app(morepath.App):
      pass
    
    # configuration
    @app.path(...)
    ...
    
    # wsgi
    morepath.run(app())
    

    To mount an application manually with variables, we used to need the special mount() method. Old way:

    mounted_wiki_app = wiki_app.mount(wiki_id=3)
    

    In the new system, mounting is done during instantiation of the app:

    mounted_wiki_app = wiki_app(wiki_id=3)
    

    Class names in Python are usually spelled with an upper case. In the Morepath docs the application object has been spelled with a lower case. We’ve used lower-case class names for application objects even in the updated docs for example code, but feel free to make them upper-case in your own code if you wish.

    Why this change? There are some major benefits to this change:

    • both extending and mounting app now use natural Python mechanisms: subclassing and instantation.
    • it allows us to expose the facility to create new directives to the API. You can create application-specific directives.
  • You can define your own directives on your applications using the directive directive:

    @my_app.directive('my_directive')
    

    This exposes details of the configuration system which is underdocumented for now; study the morepath.directive module source code for examples.

  • Document how to use more.static to include static resources into your application.

  • Add a recursive=False option to the config.scan method. This allows the non-recursive scanning of a package. Only its __init__.py will be scanned.

  • To support scanning a single module non-recursively we need a feature that hasn’t landed in mainline Venusian yet, so depend on Venusifork for now.

  • A small optimization in the publishing machinery. Less work is done to update the generic function lookup context during routing.

0.3 (2014-06-23)

  • Ability to absorb paths entirely in path directive, as per issue #132.

  • Refactor of config engine to make Venusian and immediate config more clear.

  • Typo fix in docs (Remco Wendt).

  • Get version number in docs from setuptools.

  • Fix changelog so that PyPI page generates HTML correctly.

  • Fix PDF generation so that the full content is generated.

  • Ability to mark a view as internal. It will be available to request.view() but will give 404 on the web. This is useful for structuring JSON views for reusability where you don’t want them to actually show up on the web.

  • A request.child(something).view() that had this view in turn call a request.view() from the context of the something application would fail – it would not be able to look up the view as lookups still occurred in the context of the mounting application. This is now fixed. (thanks Ying Zhong for reporting it)

    Along with this fix refactored the request object so it keeps a simple mounted attribute instead of a stack of mounts; the stack-like nature was not in use anymore as mounts themselves have parents anyway. The new code is simpler.

0.2 (2014-04-24)

  • Python 3 support, in particular Python 3.4 (Alec Munro - fudomunro on github).
  • Link generation now takes SCRIPT_NAME into account.
  • Morepath 0.1 had a security system, but it was undocumented. Now it’s documented (docs now in Morepath Security), and some of its behavior was slightly tweaked:
    • new verify_identity directive.
    • permission directive was renamed to permission_rule.
    • default unauthorized error is 403 Forbidden, not 401 Unauthorized.
    • morepath.remember and morepath.forbet renamed to morepath.remember_identity and morepath.forget_identity.
  • Installation documentation tweaks. (Auke Willem Oosterhoff)
  • .gitignore tweaks (Auke Willem Oosterhoff)

0.1 (2014-04-08)

  • Initial public release.

History of Morepath

For more recent changes, see CHANGES.

Morepath was written by Martijn Faassen (me writing this document).

The genesis of Morepath is complex and involves a number of projects.

Web Framework Inspirations

Morepath was inspired by Zope, in particular its component architecture; a reimagined version of this is available in Reg, a core dependency of Morepath.

An additional inspiration was the Grok web framework I helped create, which was based on Zope 3 technologies, and Pyramid, a reimagined version of Zope 3, created by Chris McDonough.

Pyramid in particular has been the source of a lot of ideas, including bits of implementation.

Once the core of Morepath had been created I found there had been quite a bit of parallel evolution with Flask. Flask served as a later inspiration in its capabilities and documentation. Morepath also used Werkzeug (basis for Flask) for a while to implement its request and response objects, but eventually I found WebOb the better fit for Morepath and switched to that.

Configuration system

In 2006 I co-founded the Grok web framework. The fundamental configuration mechanism this project uses was distilled into the Martian library:

https://pypi.python.org/pypi/martian

Martian was reformulated by Chris McDonough (founder of the Pyramid project) into Venusian, a simpler, decorator based approach:

https://pypi.python.org/pypi/venusian

Now Morepath uses Venusian as a foundation to its configuration system.

Routing system

In 2009 I wrote a library called Traject:

https://pypi.python.org/pypi/traject

I was familiar with Zope traversal. Zope traversal matches a URL with an object by parsing the URL and going through an object graph step by step to find the matching object. This works well for objects stored in an object database, as they’re already in such a graph. I tried to make this work properly with a relational database exposed through an ORM, but noticed that I had to adjust the object mapping too much just to please the traversal system.

This led me to a routing system, so expose the relational database objects to a URL. But I didn’t want to give up some nice properties of traversal, in particular that for any object that you can traverse to you can also generate a URL. I also wanted to maintain a separation between models and views. This led to the creation of Traject.

I used Traject successfully in a number of projects (based on Grok). I also ported Traject to JavaScript as part of the Obviel client-side framework. While Traject is fairly web-framework independent, to my knowledge Traject hasn’t found much adoption elsewhere.

Morepath contains a further evolution of the Traject concept (though not the Traject library directly).

Reg

In early 2010 I started the iface project with Thomas Lotze. In 2012 I started the Crom project. Finally I combined them into the Comparch project in 2013. I then renamed Comparch to Reg, and finally converted Reg to a generic function implementation.

See Reg’s history section for more information on its history. The Reg project provides the fundamental registries that Morepath builds on.

Publisher

In 2010 I wrote a system called Dawnlight:

https://bitbucket.org/faassen/dawnlight

It was the core of an object publishing system with a system to find a model and a view for that model, based on a path. It used some concepts I’d learned while implementing Traject (a URL path can be seen as a stack that’s being consumed), and it was intended to be easy to plug in Traject. I didn’t use Dawnlight myself, but it was adopted by the developers of the Cromlech web framework (Souheil Chelfouh and Alex Garel):

http://pypi.dolmen-project.org/pypi/cromlech.dawnlight

Morepath contains a reformulation of the Dawnlight system, particularly in its publisher module.

Combining it all

In 2013 I started to work with CONTACT Software. They encouraged me to rethink these various topics. This led me to combine these lines of development into Morepath: Reg registries, decorator-based configuration using Venusian, and traject-style publication of models and resources.

Spinning a Web Framework

In the fall of 2013 I gave a keynote speech at PyCon DE about the creative processes behind Morepath, called “Spinning a Web Framework”:

Indices and tables