Basic Layout

The starter files generated by the bfg_zodb template are basic, but they provide a good orientation for the high-level patterns common to most traversal -based repoze.bfg (and ZODB based) projects.

__init__.py

A directory on disk can be turned into a Python package by containing an __init__.py file. Even if empty, this marks a directory as a Python package.

Configuration With configure.zcml

repoze.bfg uses a markup language syntactically the same as Zope’s implementation of ZCML, but using a different default XML namespace. Our sample ZCML file looks like the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<configure xmlns="http://namespaces.repoze.org/bfg">

  <!-- this must be included for the view declarations to work -->
  <include package="repoze.bfg.includes" />

  <view
     for=".models.MyModel"
     view=".views.my_view"
     />

  <view
     for=".models.MyModel"
     view=".views.static_view"
     name="static"
     />

</configure>
  1. Line 1. The root <configure> element, in a bfg namespace.

  2. Line 4. Boilerplate, the comment explains.

  3. Lines 6-9. Register a <view> that is bound to a class. .views.my_view is a function we write (generated by the bfg_zodb template) that is given a context and a request and returns a response.

    Since this <view> doesn’t have a name attribute, it is the “default” view for that class.

  4. Lines 11-15. Register a view on the MyModels class that answers URL segments of static. This is a view that will serve up static resources for us, in this case, at http://localhost:6543/static/ and below.

Content Models with models.py

repoze.bfg often uses the word model when talking about content resources arranged in a hierarchical model graph. The models.py file is where the bfg_zodb Paster template put the classes that implement our models.

Here is the source for models.py:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from persistent.mapping import PersistentMapping

class MyModel(PersistentMapping):
    __parent__ = __name__ = None

def appmaker(zodb_root):
    if not 'app_root' in zodb_root:
        app_root = MyModel()
        zodb_root['app_root'] = app_root
        import transaction
        transaction.commit()
    return zodb_root['app_root']
  1. Lines 3-4. The MyModel class we referred to in the ZCML is implemented here. It is persistent (via PersistentMapping). The __parent__ and __name__ are important parts of the traversal protocol. By default, have these as None indicating that this is the root object.

  2. Lines 6-12. appmaker is used to return the application root object. It is called on every request to the repoze.bfg application. It also performs bootstrapping by creating an application root (inside the ZODB root object) if one does not already exist.

    We do so by first seeing if the database has the persistent application root. If not, we make an instance, store it, and commit the transaction. We then return the application root object.

App Startup with run.py

How does a repoze.bfg application start up? When you run under paster using the tutorial.ini generated config file, the application area points at an entry point. Our entry point happens to be in run.py and its app function:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from repoze.bfg.router import make_app
from repoze.zodbconn.finder import PersistentApplicationFinder

def app(global_config, **kw):
    """ This function returns a repoze.bfg.router.Router object.
    
    It is usually called by the PasteDeploy framework during ``paster serve``.
    """
    # paster app config callback
    import tutorial
    from tutorial.models import appmaker
    zodb_uri = kw.get('zodb_uri')
    if zodb_uri is None:
        raise ValueError("No 'zodb_uri' in application configuration.")

    get_root = PersistentApplicationFinder(zodb_uri, appmaker)
    return make_app(get_root, tutorial, options=kw)
  1. Line 11. After importing our application, get the appmaker function described above.
  2. Line 12. Get the ZODB configuration from the tutorial.ini file’s [app:main] section. This will be a URI (something like file:///path/to/Data.fs).
  3. Line 16. We create a root factory using the PersistentApplicationFinder helper class, passing it the ZODB URI and our appmaker.
  4. Line 17. We use the repoze.bfg.router.make_app to return a WSGI application. The make_app function takes the root factory (get_root), the package representing our application, and the keywords parsed by PasteDeploy.