Application framework¶
Launchpad is built around Zope components. Zope has meant substantially different things over the years (Wikipedia’s Zope article has a good overview, and The World of Zope is also a useful introduction to some terminology), so this document tries to be a little more specific. In modern terms, Launchpad uses the Zope Toolkit, but not the full Zope application server.
Component architecture¶
Launchpad uses the Zope Component Architecture (zope.interface and zope.component) extensively and pervasively.
zope.interface
defines most of Launchpad’s internal interfaces, and is
also built upon by lazr.restful to
define its external web service API.
zope.component
provides facilities for registering and looking up
components, making it easier to decouple implementations from interfaces and
reducing the need for circular imports.
The zope.schema package from the
Zope Toolkit allows specifying more detailed types for attributes of
interfaces, and zope.security
allows enforcing interfaces using security policies. The latter is
particularly important to Launchpad; it is the foundation of our ability to
operate a complex multi-tenanted service in which users’ privileges often
overlap in ways that cannot be accurately enforced purely at API boundaries,
and must instead be enforced object-by-object. Most objects passed across
interface boundaries within Launchpad are wrapped in Zope security proxies
so that the security policy in lp.services.webapp.authorization
is
consulted on all attribute accesses.
URL traversal and publishing¶
Launchpad uses zope.traversing to “traverse” URLs (i.e. work segment-by-segment along them until reaching a model object with an associated view), and zope.publisher to define the details of how objects are “published” (i.e. the process of turning an HTTP request into an appropriate response, including various hooks that are run before and after calling the object itself).
Many of the details here are handled by custom code in
lp.services.webapp
, especially lp.services.webapp.publication
which
provides many application-specific hooks, and
lp.services.webapp.publishing
which defines much of Launchpad’s
traversal framework. The URL structure is defined in various
configure.zcml
files: lp:url
tags are used to build up the canonical
URL for an object, and lp:navigation
tags register classes called as
part of traversal to resolve the next step from each intermediate object in
the URL (starting at lp.app.browser.launchpad.LaunchpadRootNavigation
).
Page templating¶
Launchpad uses Page Templates as its HTML templating mechanism. While systems like Jinja are more popular elsewhere, the Page Templates language has the benefit that source files are themselves valid XML rather than being a combination of two syntaxes, and it is not generally possible to write well-formed input that produces ill-formed output.
Page Templates were originally invented by Zope, and we still happen to use Zope’s original implementation of them, although Zope nowadays uses Chameleon instead.
Views and forms¶
Launchpad’s view layer (used for the web UI) is custom code, starting at
lp.services.webapp.publisher.LaunchpadView
. However, many views are
built around “forms”, defined by building up a data schema using
zope.interface
and zope.schema
and then using zope.formlib to generate HTML forms and to parse
data from HTTP POST
requests. zope.formlib
also provides “widgets”
whose job it is to define the precise rendering and parsing of particular
form elements, and Launchpad defines a number of custom widgets for cases
where zope.formlib
’s widgets are insufficient.
Events¶
It’s often useful for parts of Launchpad to be able to subscribe to events
generated by other parts of Launchpad. For example, a number of subscribers
watch for objects such as comments being created in order to be able to
assign “karma” to their creators. This is coordinated using zope.event, as well as subscriber
tags in
various configure.zcml
files. lazr.lifecycle enhances this with common events
for object creation, modification, and deletion.
WSGI server¶
Launchpad’s application server runs within Gunicorn, wrapped using Talisker to add several useful operational facilities.